diff --git a/pr-preview/pr-1071/0.5.html b/pr-preview/pr-1071/0.5.html deleted file mode 100644 index e99562beae..0000000000 --- a/pr-preview/pr-1071/0.5.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 0.5

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture.html b/pr-preview/pr-1071/0.5/architecture.html deleted file mode 100644 index a4afadde87..0000000000 --- a/pr-preview/pr-1071/0.5/architecture.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Architecture | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/attestation/coordinator.html b/pr-preview/pr-1071/0.5/architecture/attestation/coordinator.html deleted file mode 100644 index 70991042ce..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/attestation/coordinator.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -coordinator | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/attestation/hardware.html b/pr-preview/pr-1071/0.5/architecture/attestation/hardware.html deleted file mode 100644 index 445b645a52..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/attestation/hardware.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -hardware | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/attestation/manifest.html b/pr-preview/pr-1071/0.5/architecture/attestation/manifest.html deleted file mode 100644 index df074c5bb4..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/attestation/manifest.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -manifest | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm.html b/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm.html deleted file mode 100644 index 047501f88f..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -pod-vm | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies.html b/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies.html deleted file mode 100644 index a912b5177b..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -runtime-policies | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki.html b/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki.html deleted file mode 100644 index cf736b682c..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -pki | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/components/cli.html b/pr-preview/pr-1071/0.5/architecture/components/cli.html deleted file mode 100644 index f4190e3682..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/components/cli.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -cli | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/components/coordinator.html b/pr-preview/pr-1071/0.5/architecture/components/coordinator.html deleted file mode 100644 index 025c11dfee..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/components/coordinator.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -coordinator | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/components/init-container.html b/pr-preview/pr-1071/0.5/architecture/components/init-container.html deleted file mode 100644 index d0e99ca1f0..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/components/init-container.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -init-container | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/confidential-containers.html b/pr-preview/pr-1071/0.5/architecture/confidential-containers.html deleted file mode 100644 index fbaf394101..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/confidential-containers.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -confidential-containers | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys.html b/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys.html deleted file mode 100644 index 0c8c39d172..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -protocols-and-keys | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar.html b/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar.html deleted file mode 100644 index 21f718851c..0000000000 --- a/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -sidecar | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/basics/confidential-containers.html b/pr-preview/pr-1071/0.5/basics/confidential-containers.html deleted file mode 100644 index 41770aa479..0000000000 --- a/pr-preview/pr-1071/0.5/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 0.5

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable, core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The guest VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo Preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/basics/features.html b/pr-preview/pr-1071/0.5/basics/features.html deleted file mode 100644 index 48b0e44e80..0000000000 --- a/pr-preview/pr-1071/0.5/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product Features | Contrast - - - - -
Skip to main content
Version: 0.5

Product Features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes Compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight Installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote Attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service Mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/basics/security-benefits.html b/pr-preview/pr-1071/0.5/basics/security-benefits.html deleted file mode 100644 index 4a7d416748..0000000000 --- a/pr-preview/pr-1071/0.5/basics/security-benefits.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -security-benefits | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/category/attestation.html b/pr-preview/pr-1071/0.5/category/attestation.html deleted file mode 100644 index 37a413c267..0000000000 --- a/pr-preview/pr-1071/0.5/category/attestation.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Attestation | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/category/certificates-and-identities.html b/pr-preview/pr-1071/0.5/category/certificates-and-identities.html deleted file mode 100644 index 3e42a7f920..0000000000 --- a/pr-preview/pr-1071/0.5/category/certificates-and-identities.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Certificates and Identities | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/category/components.html b/pr-preview/pr-1071/0.5/category/components.html deleted file mode 100644 index daed2c4d68..0000000000 --- a/pr-preview/pr-1071/0.5/category/components.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/category/network-encryption.html b/pr-preview/pr-1071/0.5/category/network-encryption.html deleted file mode 100644 index ca9ba12776..0000000000 --- a/pr-preview/pr-1071/0.5/category/network-encryption.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Network Encryption | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/deployment.html b/pr-preview/pr-1071/0.5/deployment.html deleted file mode 100644 index 2f0f5cbae2..0000000000 --- a/pr-preview/pr-1071/0.5/deployment.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 0.5

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set it up.

-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml
-

Prepare your Kubernetes resources

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: kata-cc-isolation to the pod spec (pod definition or template). -In addition, add the Contrast Initializer as initContainers to these workloads and configure the -workload to use the certificates written to a volumeMount named tls-certs.

-
spec: # v1.PodSpec
runtimeClassName: kata-cc-isolation
initContainers:
- name: initializer
image: "ghcr.io/edgelesssys/contrast/initializer:latest"
env:
- name: COORDINATOR_HOST
value: coordinator
volumeMounts:
- name: tls-certs
mountPath: /tls-config
volumes:
- name: tls-certs
emptyDir: {}
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as annotations to your -deployment files. A manifest.json with the reference values of your deployment will be created.

-
contrast generate resources/
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

After this step, the Coordinator will start issuing TLS certs to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using embedded reference values. The CLI will write the service mesh -root certificate and the history of manifests into the verify/ directory. In addition, the policies referenced -in the manifest are also written to the directory.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-root.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
timeout 30s bash -c 'until kubectl get service/${MY_SERVICE} --output=jsonpath='{.status.loadBalancer}' | grep "ingress"; do sleep 2 ; done'
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh root certificate with throw the following error:

$ curl --cacert ./verify/mesh-root.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-root.pem:

-
openssl s_client -CAfile verify/mesh-root.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/examples.html b/pr-preview/pr-1071/0.5/examples.html deleted file mode 100644 index 0fc71fce58..0000000000 --- a/pr-preview/pr-1071/0.5/examples.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Examples | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/examples/emojivoto.html b/pr-preview/pr-1071/0.5/examples/emojivoto.html deleted file mode 100644 index 855070dd05..0000000000 --- a/pr-preview/pr-1071/0.5/examples/emojivoto.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 0.5

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voters perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

emojivoto components topology

-

Motivation

-

Using a voting service, users' votes are considered highly sensitive data, as we require -a secret ballot. Also, users are likely interested in the fairness of the ballot. For -both requirements, we can use Confidential Computing and, specifically, workload attestation -to prove to those interested in voting that the app is running in a protected environment -where their votes are processed without leaking to the platform provider or workload owner.

-

Prerequisites

-
    -
  • Installed Contrast CLI. -See the installation instructions on how to get it.
  • -
  • Running cluster with Confidential Containers support. -Please follow the cluster setup instructions -to create a cluster.
  • -
  • Get the deployment. This is currently available as part of the preview bundle.
  • -
-

Steps to deploy emojivoto with Contrast

-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f coordinator.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class kata-cc-isolation was added to the pods to signal they should be run -as Confidential Containers. In addition, the Contrast Initializer was added -as an init container to these workloads to facilitate the attestation and certificate pulling -before the actual workload is started.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the embedded reference values to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, we're ensured that the Coordinator -deployment hasn't been tampered with.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The emojivoto version we're using is patched to only communicate -via mTLS (the original app talks plain HTTP). The different parts of the workload are configured -to use the credentials from the volumeMount when communicating with each other.

-

Voter's perspective: Verifying the ballot

-

As voters, we want to verify the fairness and confidentiality of the deployment before -deciding to vote. Regardless of the scale of our distributed deployment, Contrast only -needs a single remote attestation step to verify the deployment. By doing remote attestation -of the Coordinator, we transitively verify those systems the Coordinator has already attested -or will attest in the future. Successful verification of the Coordinator means that -we can be sure it will enforce the configured manifest.

-

Attest the Coordinator

-

A potential voter can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using embedded reference values. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-root.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-

Manifest history and artifact audit

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Confidential connection to the attested workload

-

After ensuring the configuration of the Coordinator fits the expectation, you can securely connect -to the workloads using the Coordinator's mesh-root.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-root.pem:

-
openssl s_client -CAfile verify/mesh-root.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Certificate SAN and manifest update (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh root certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-root.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configure the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
-

Update the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh root certificate on the manifest update. Workload certificates issued -after the manifest are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-root.pem is updated with the new CA certificate chain.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-root.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/getting-started.html b/pr-preview/pr-1071/0.5/getting-started.html deleted file mode 100644 index 9f0bd7606b..0000000000 --- a/pr-preview/pr-1071/0.5/getting-started.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Getting started | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/getting-started/cluster-setup.html b/pr-preview/pr-1071/0.5/getting-started/cluster-setup.html deleted file mode 100644 index c205e33919..0000000000 --- a/pr-preview/pr-1071/0.5/getting-started/cluster-setup.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 0.5

Create a cluster

-

Prerequisites

-

Install the latest version of the Azure CLI.

-

Login to your account, which has -the permissions to create an AKS cluster, by executing:

-
az login
-

Prepare using the AKS preview

-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "$azResourceGroup" \
--location "$azLocation"
-

Create AKS cluster

-

First create an AKS cluster:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "$azResourceGroup" \
--name "$azClusterName" \
--kubernetes-version 1.29 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--node-count 1 \
--generate-ssh-keys
-

We then add a second node pool with CoCo support:

-
az aks nodepool add \
--resource-group "$azResourceGroup" \
--name nodepool2 \
--cluster-name "$azClusterName" \
--node-count 1 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "$azResourceGroup" \
--name "$azClusterName"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show two nodes:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
aks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0
-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "$azResourceGroup"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "$azResourceGroup" \
--name "$azClusterName"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/getting-started/first-steps.html b/pr-preview/pr-1071/0.5/getting-started/first-steps.html deleted file mode 100644 index 3d720767a8..0000000000 --- a/pr-preview/pr-1071/0.5/getting-started/first-steps.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -first-steps | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.5/getting-started/install.html b/pr-preview/pr-1071/0.5/getting-started/install.html deleted file mode 100644 index 9a8c27e241..0000000000 --- a/pr-preview/pr-1071/0.5/getting-started/install.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 0.5

Installation

-

Download the bundle from the URL you received:

curl -fLO <URL>

Then unpack the unpack the downloaded archive:

unzip contrast.zip
-

Install the Contrast CLI in your PATH, e.g.:

-
mv contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6.html b/pr-preview/pr-1071/0.6.html deleted file mode 100644 index ddd022d6ab..0000000000 --- a/pr-preview/pr-1071/0.6.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 0.6

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/about.html b/pr-preview/pr-1071/0.6/about.html deleted file mode 100644 index 1b5596d635..0000000000 --- a/pr-preview/pr-1071/0.6/about.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -About | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/about/telemetry.html b/pr-preview/pr-1071/0.6/about/telemetry.html deleted file mode 100644 index 01db7f83f8..0000000000 --- a/pr-preview/pr-1071/0.6/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 0.6

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/architecture.html b/pr-preview/pr-1071/0.6/architecture.html deleted file mode 100644 index 5f5a20dc31..0000000000 --- a/pr-preview/pr-1071/0.6/architecture.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Architecture | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/architecture/attestation.html b/pr-preview/pr-1071/0.6/architecture/attestation.html deleted file mode 100644 index 00a684c361..0000000000 --- a/pr-preview/pr-1071/0.6/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 0.6

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -On AMD SEV-SNP the hash of the policy is then added to the attestation report via the HOSTDATA field by the hypervisor. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/architecture/certificates.html b/pr-preview/pr-1071/0.6/architecture/certificates.html deleted file mode 100644 index b78e038384..0000000000 --- a/pr-preview/pr-1071/0.6/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 0.6

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/basics/confidential-containers.html b/pr-preview/pr-1071/0.6/basics/confidential-containers.html deleted file mode 100644 index 44ce0d6827..0000000000 --- a/pr-preview/pr-1071/0.6/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 0.6

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/basics/features.html b/pr-preview/pr-1071/0.6/basics/features.html deleted file mode 100644 index b4f7b4e374..0000000000 --- a/pr-preview/pr-1071/0.6/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Skip to main content
Version: 0.6

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/basics/security-benefits.html b/pr-preview/pr-1071/0.6/basics/security-benefits.html deleted file mode 100644 index 6a2758b375..0000000000 --- a/pr-preview/pr-1071/0.6/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Skip to main content
Version: 0.6

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/components.html b/pr-preview/pr-1071/0.6/components.html deleted file mode 100644 index 6b8ca062c9..0000000000 --- a/pr-preview/pr-1071/0.6/components.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
Version: 0.6

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/components/policies.html b/pr-preview/pr-1071/0.6/components/policies.html deleted file mode 100644 index c16005d37b..0000000000 --- a/pr-preview/pr-1071/0.6/components/policies.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Skip to main content
Version: 0.6

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/components/runtime.html b/pr-preview/pr-1071/0.6/components/runtime.html deleted file mode 100644 index fc195de608..0000000000 --- a/pr-preview/pr-1071/0.6/components/runtime.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Skip to main content
Version: 0.6

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

cloud-hypervisor virtual machine manager (VMM)

-

The containerd shim uses cloud-hypervisor to create a confidential virtual machine for every pod. -This requires the cloud-hypervisor binary to be installed on every node (responsibility of the node-installer).

-

Tardev snapshotter

-

Contrast uses a special containerd snapshotter (tardev) to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor as the virtual machine manager (VMM)
  • -
  • Install an IGVM file for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/components/service-mesh.html b/pr-preview/pr-1071/0.6/components/service-mesh.html deleted file mode 100644 index 664da8fcd0..0000000000 --- a/pr-preview/pr-1071/0.6/components/service-mesh.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - -Service Mesh | Contrast - - - - -
Skip to main content
Version: 0.6

Service Mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-pod basis by adding the service-mesh -container as a sidecar container. -The service mesh container first sets up iptables -rules based on its configuration and then starts Envoy -for TLS origination and termination.

-

Configuring the Proxy

-

The service mesh container can be configured using the EDG_INGRESS_PROXY_CONFIG -and EDG_EGRESS_PROXY_CONFIG environment variables.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the environment variable EDG_INGRESS_PROXY_CONFIG as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the -informational-only field <name>.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
initContainers:
- name: initializer
image: "ghcr.io/edgelesssys/contrast/initializer@sha256:..."
env:
- name: COORDINATOR_HOST
value: coordinator
volumeMounts:
- name: tls-certs
mountPath: /tls-config
- name: sidecar
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy@sha256:..."
restartPolicy: Always
volumeMounts:
- name: tls-certs
mountPath: /tls-config
env:
- name: EDG_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
securityContext:
privileged: true
capabilities:
add:
- NET_ADMIN
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
volumeMounts:
- name: tls-certs
mountPath: /tls-config
volumes:
- name: tls-certs
emptyDir: {}
-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as EDG_EGRESS_PROXY_CONFIG. Separate multiple entries with ##. Choose any -string identifying the service on the given port as <name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are themselves part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
initContainers:
- name: initializer
image: "ghcr.io/edgelesssys/contrast/initializer@sha256:..."
env:
- name: COORDINATOR_HOST
value: coordinator
volumeMounts:
- name: tls-certs
mountPath: /tls-config
- name: sidecar
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy@sha256:..."
restartPolicy: Always
volumeMounts:
- name: tls-certs
mountPath: /tls-config
env:
- name: EDG_EGRESS_PROXY_CONFIG
value: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
securityContext:
privileged: true
capabilities:
add:
- NET_ADMIN
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
volumeMounts:
- name: tls-certs
mountPath: /tls-config
volumes:
- name: tls-certs
emptyDir: {}
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/deployment.html b/pr-preview/pr-1071/0.6/deployment.html deleted file mode 100644 index d2d21d86e6..0000000000 --- a/pr-preview/pr-1071/0.6/deployment.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 0.6

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set it up.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

RuntimeClass and Initializer

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies. -In addition, add the Contrast Initializer as initContainers to these workloads and configure the -workload to use the certificates written to a volumeMount named tls-certs.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
initContainers:
- name: initializer
image: "ghcr.io/edgelesssys/contrast/initializer:latest"
env:
- name: COORDINATOR_HOST
value: coordinator
volumeMounts:
- name: tls-certs
mountPath: /tls-config
volumes:
- name: tls-certs
emptyDir: {}
-

Handling TLS

-

The initializer populates the shared volume with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The app has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The app has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following sidecar definition to your workload:

spec: # v1.PodSpec
initContainers:
- name: tls-sidecar
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:latest"
restartPolicy: Always
env:
- name: EDG_INGRESS_PROXY_CONFIG
value: "main#8001#false##metrics#8080#true"
- name: EDG_EGRESS_PROXY_CONFIG
value: "backend#127.0.0.2:4001#backend.default:4001"
volumeMounts:
- name: tls-certs
mountPath: /tls-config

The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as annotations to your -deployment files. A manifest.json with the reference values of your deployment will be created.

-
contrast generate resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

After this step, the Coordinator will start issuing TLS certs to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using embedded reference values. The CLI will write the service mesh -root certificate and the history of manifests into the verify/ directory. In addition, the policies referenced -in the manifest are also written to the directory.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/examples.html b/pr-preview/pr-1071/0.6/examples.html deleted file mode 100644 index 4d1aba6276..0000000000 --- a/pr-preview/pr-1071/0.6/examples.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Examples | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/examples/emojivoto.html b/pr-preview/pr-1071/0.6/examples/emojivoto.html deleted file mode 100644 index ba11a55e91..0000000000 --- a/pr-preview/pr-1071/0.6/examples/emojivoto.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 0.6

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voters perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

emojivoto components topology

-

Motivation

-

Using a voting service, users' votes are considered highly sensitive data, as we require -a secret ballot. Also, users are likely interested in the fairness of the ballot. For -both requirements, we can use Confidential Computing and, specifically, workload attestation -to prove to those interested in voting that the app is running in a protected environment -where their votes are processed without leaking to the platform provider or workload owner.

-

Prerequisites

- -

Steps to deploy emojivoto with Contrast

-

Downloading the deployment

-

The emojivoto deployment files are part of a zip file in the Contrast release. You can download the -latest deployment by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/latest/download/emojivoto-demo.zip
-

After that, unzip the emojivoto-demo.zip file to extract the deployment/ directory.

-
unzip emojivoto-demo.zip
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc-<VERSIONHASH> -was added to the pods to signal they should be run as Confidential Containers. In addition, the Contrast -Initializer was added as an init container to these workloads to -facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the embedded reference values to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, we're ensured that the Coordinator -deployment hasn't been tampered with.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Voter's perspective: Verifying the ballot

-

As voters, we want to verify the fairness and confidentiality of the deployment before -deciding to vote. Regardless of the scale of our distributed deployment, Contrast only -needs a single remote attestation step to verify the deployment. By doing remote attestation -of the Coordinator, we transitively verify those systems the Coordinator has already attested -or will attest in the future. Successful verification of the Coordinator means that -we can be sure it will enforce the configured manifest.

-

Attest the Coordinator

-

A potential voter can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using embedded reference values. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-

Manifest history and artifact audit

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Confidential connection to the attested workload

-

After ensuring the configuration of the Coordinator fits the expectation, you can securely connect -to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Certificate SAN and manifest update (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configure the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
-

Update the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/getting-started.html b/pr-preview/pr-1071/0.6/getting-started.html deleted file mode 100644 index 5baad3bfd4..0000000000 --- a/pr-preview/pr-1071/0.6/getting-started.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Getting started | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/getting-started/cluster-setup.html b/pr-preview/pr-1071/0.6/getting-started/cluster-setup.html deleted file mode 100644 index e8474c100c..0000000000 --- a/pr-preview/pr-1071/0.6/getting-started/cluster-setup.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 0.6

Create a cluster

-

Prerequisites

-

Install the latest version of the Azure CLI.

-

Login to your account, which needs -to have the permissions to create an AKS cluster, by executing:

-
az login
-

Prepare using the AKS preview

-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First create an AKS cluster:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.29 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--node-count 1 \
--generate-ssh-keys
-

We then add a second node pool with CoCo support:

-
az aks nodepool add \
--resource-group "${azResourceGroup:?}" \
--name nodepool2 \
--cluster-name "${azClusterName:?}" \
--node-count 1 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show two nodes:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
aks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0
-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/getting-started/install.html b/pr-preview/pr-1071/0.6/getting-started/install.html deleted file mode 100644 index 989e7fbfc1..0000000000 --- a/pr-preview/pr-1071/0.6/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 0.6

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/latest/download/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.6/known-limitations.html b/pr-preview/pr-1071/0.6/known-limitations.html deleted file mode 100644 index 869dced497..0000000000 --- a/pr-preview/pr-1071/0.6/known-limitations.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - -Known Limitations | Contrast - - - - -
Skip to main content
Version: 0.6

Known Limitations

-

As Contrast is currently in an early development stage, it's built on several projects that are also under active development. -This section outlines the most significant known limitations, providing stakeholders with clear expectations and understanding of the current state.

-

Availability

-
    -
  • Platform Support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
-

Kubernetes Features

-
    -
  • Persistent Volumes: Not currently supported within Confidential Containers.
  • -
  • Port-Forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource Limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime Policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling Integration

-
    -
  • CLI Availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7.html b/pr-preview/pr-1071/0.7.html deleted file mode 100644 index 95e0193806..0000000000 --- a/pr-preview/pr-1071/0.7.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 0.7

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/about.html b/pr-preview/pr-1071/0.7/about.html deleted file mode 100644 index 39f6aeac5c..0000000000 --- a/pr-preview/pr-1071/0.7/about.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -About | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/about/telemetry.html b/pr-preview/pr-1071/0.7/about/telemetry.html deleted file mode 100644 index 4de57451a7..0000000000 --- a/pr-preview/pr-1071/0.7/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 0.7

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/architecture.html b/pr-preview/pr-1071/0.7/architecture.html deleted file mode 100644 index df2491aa0d..0000000000 --- a/pr-preview/pr-1071/0.7/architecture.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Architecture | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/architecture/attestation.html b/pr-preview/pr-1071/0.7/architecture/attestation.html deleted file mode 100644 index 0a97ee78d0..0000000000 --- a/pr-preview/pr-1071/0.7/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 0.7

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -On AMD SEV-SNP the hash of the policy is then added to the attestation report via the HOSTDATA field by the hypervisor. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/architecture/certificates.html b/pr-preview/pr-1071/0.7/architecture/certificates.html deleted file mode 100644 index 9510e67f9f..0000000000 --- a/pr-preview/pr-1071/0.7/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 0.7

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/architecture/observability.html b/pr-preview/pr-1071/0.7/architecture/observability.html deleted file mode 100644 index f280cff171..0000000000 --- a/pr-preview/pr-1071/0.7/architecture/observability.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Skip to main content
Version: 0.7

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator starts two gRPC servers, one for the user API on port 1313 and -one for the mesh API on port 7777. Metrics for both servers can be accessed -using different prefixes.

-

All metric names for the user API are prefixed with contrast_userapi_grpc_server_. -Exposed metrics include the number of handled requests of the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively. For each method -you can see the gRPC status code indicating whether the request succeeded or -not and the request latency.

-

For the mesh API, the metric names are prefixed with contrast_meshapi_grpc_server_. The -metrics include similar data to the user API for the method NewMeshCert which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/basics/confidential-containers.html b/pr-preview/pr-1071/0.7/basics/confidential-containers.html deleted file mode 100644 index 3f36276e06..0000000000 --- a/pr-preview/pr-1071/0.7/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 0.7

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/basics/features.html b/pr-preview/pr-1071/0.7/basics/features.html deleted file mode 100644 index 30fb54835d..0000000000 --- a/pr-preview/pr-1071/0.7/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Skip to main content
Version: 0.7

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/basics/security-benefits.html b/pr-preview/pr-1071/0.7/basics/security-benefits.html deleted file mode 100644 index 01f0b08a02..0000000000 --- a/pr-preview/pr-1071/0.7/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Skip to main content
Version: 0.7

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/components.html b/pr-preview/pr-1071/0.7/components.html deleted file mode 100644 index 51e0627b16..0000000000 --- a/pr-preview/pr-1071/0.7/components.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
Version: 0.7

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/components/policies.html b/pr-preview/pr-1071/0.7/components/policies.html deleted file mode 100644 index 5a1b936396..0000000000 --- a/pr-preview/pr-1071/0.7/components/policies.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Skip to main content
Version: 0.7

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/components/runtime.html b/pr-preview/pr-1071/0.7/components/runtime.html deleted file mode 100644 index e88c6572ce..0000000000 --- a/pr-preview/pr-1071/0.7/components/runtime.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Skip to main content
Version: 0.7

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

cloud-hypervisor virtual machine manager (VMM)

-

The containerd shim uses cloud-hypervisor to create a confidential virtual machine for every pod. -This requires the cloud-hypervisor binary to be installed on every node (responsibility of the node-installer).

-

Tardev snapshotter

-

Contrast uses a special containerd snapshotter (tardev) to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor as the virtual machine manager (VMM)
  • -
  • Install an IGVM file for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/components/service-mesh.html b/pr-preview/pr-1071/0.7/components/service-mesh.html deleted file mode 100644 index c8a8737854..0000000000 --- a/pr-preview/pr-1071/0.7/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Skip to main content
Version: 0.7

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables EDG_INGRESS_PROXY_CONFIG, -EDG_EGRESS_PROXY_CONFIG and EDG_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: EDG_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v0.7.3@sha256:e297e9db93744445608f229d44479359313bc187a7f31e1a9c3c9b1d5407b5f6"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-tls-certs
mountPath: /tls-config
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/deployment.html b/pr-preview/pr-1071/0.7/deployment.html deleted file mode 100644 index 92e40ecf7f..0000000000 --- a/pr-preview/pr-1071/0.7/deployment.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 0.7

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set it up.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/runtime.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/coordinator.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-tls-certs shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-tls-certs volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:v0.7.3@sha256:55475365c8177420ff3b27ad48bb0f38f8a92bfe754f50f1ed97f50f17ee23b8"
name: contrast-initializer
volumeMounts:
- mountPath: /tls-config
name: contrast-tls-certs
volumes:
- emptyDir: {}
name: contrast-tls-certs
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using embedded reference values. The CLI will write the service mesh -root certificate and the history of manifests into the verify/ directory. In addition, the policies referenced -in the manifest are also written to the directory.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/examples.html b/pr-preview/pr-1071/0.7/examples.html deleted file mode 100644 index b37de62148..0000000000 --- a/pr-preview/pr-1071/0.7/examples.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Examples | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/examples/emojivoto.html b/pr-preview/pr-1071/0.7/examples/emojivoto.html deleted file mode 100644 index 979b9b5f14..0000000000 --- a/pr-preview/pr-1071/0.7/examples/emojivoto.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 0.7

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voters perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

emojivoto components topology

-

Motivation

-

Using a voting service, users' votes are considered highly sensitive data, as we require -a secret ballot. Also, users are likely interested in the fairness of the ballot. For -both requirements, we can use Confidential Computing and, specifically, workload attestation -to prove to those interested in voting that the app is running in a protected environment -where their votes are processed without leaking to the platform provider or workload owner.

-

Prerequisites

- -

Steps to deploy emojivoto with Contrast

-

Downloading the deployment

-

The emojivoto deployment files are part of a zip file in the Contrast release. You can download the -latest deployment by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v0.7.3/emojivoto-demo.zip
-

After that, unzip the emojivoto-demo.zip file to extract the deployment/ directory.

-
unzip emojivoto-demo.zip
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/runtime.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/coordinator.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc-<VERSIONHASH> -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the embedded reference values to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Voter's perspective: Verifying the ballot

-

As voters, we want to verify the fairness and confidentiality of the deployment before -deciding to vote. Regardless of the scale of our distributed deployment, Contrast only -needs a single remote attestation step to verify the deployment. By doing remote attestation -of the Coordinator, we transitively verify those systems the Coordinator has already attested -or will attest in the future. Successful verification of the Coordinator means that -we can be sure it will enforce the configured manifest.

-

Attest the Coordinator

-

A potential voter can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using embedded reference values. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-

Manifest history and artifact audit

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Confidential connection to the attested workload

-

After ensuring the configuration of the Coordinator fits the expectation, you can securely connect -to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Certificate SAN and manifest update (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configure the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
-

Update the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/features-limitations.html b/pr-preview/pr-1071/0.7/features-limitations.html deleted file mode 100644 index f8a3d84c2d..0000000000 --- a/pr-preview/pr-1071/0.7/features-limitations.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Skip to main content
Version: 0.7

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Not currently supported within Confidential Containers.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/getting-started.html b/pr-preview/pr-1071/0.7/getting-started.html deleted file mode 100644 index 9387a69e7d..0000000000 --- a/pr-preview/pr-1071/0.7/getting-started.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -Getting started | Contrast - - - - -
Skip to main content
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/getting-started/cluster-setup.html b/pr-preview/pr-1071/0.7/getting-started/cluster-setup.html deleted file mode 100644 index be5f7acba7..0000000000 --- a/pr-preview/pr-1071/0.7/getting-started/cluster-setup.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 0.7

Create a cluster

-

Prerequisites

-

Install the latest version of the Azure CLI.

-

Login to your account, which needs -to have the permissions to create an AKS cluster, by executing:

-
az login
-

Prepare using the AKS preview

-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a -non-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool.

-

We'll first start by creating the non-CoCo cluster:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.29 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--node-count 1 \
--generate-ssh-keys
-

We then add a second node pool with CoCo support:

-
az aks nodepool add \
--resource-group "${azResourceGroup:?}" \
--name nodepool2 \
--cluster-name "${azClusterName:?}" \
--node-count 1 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation
-

Optionally, we can now remove the non-CoCo node pool:

-
az aks nodepool delete \
--resource-group "${azResourceGroup:?}" \
--cluster-name "${azClusterName:?}" \
--name nodepool1
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show two nodes:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
aks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0
-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.7/getting-started/install.html b/pr-preview/pr-1071/0.7/getting-started/install.html deleted file mode 100644 index 65ccc24ee4..0000000000 --- a/pr-preview/pr-1071/0.7/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 0.7

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v0.7.3/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8.html b/pr-preview/pr-1071/0.8.html deleted file mode 100644 index 6cbf1a6f94..0000000000 --- a/pr-preview/pr-1071/0.8.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 0.8

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/about/telemetry.html b/pr-preview/pr-1071/0.8/about/telemetry.html deleted file mode 100644 index f3d4a46991..0000000000 --- a/pr-preview/pr-1071/0.8/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 0.8

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/architecture/attestation.html b/pr-preview/pr-1071/0.8/architecture/attestation.html deleted file mode 100644 index 4eef188299..0000000000 --- a/pr-preview/pr-1071/0.8/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 0.8

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -On AMD SEV-SNP the hash of the policy is then added to the attestation report via the HOSTDATA field by the hypervisor. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/architecture/certificates.html b/pr-preview/pr-1071/0.8/architecture/certificates.html deleted file mode 100644 index 799417b277..0000000000 --- a/pr-preview/pr-1071/0.8/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 0.8

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/architecture/observability.html b/pr-preview/pr-1071/0.8/architecture/observability.html deleted file mode 100644 index 5e87a17114..0000000000 --- a/pr-preview/pr-1071/0.8/architecture/observability.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Skip to main content
Version: 0.8

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator exports gRPC metrics under the prefix contrast_grpc_server_. -These metrics are labeled with the gRPC service name and method name. -Metrics of interest include contrast_grpc_server_handled_total, which counts -the number of requests by return code, and -contrast_grpc_server_handling_seconds_bucket, which produces a histogram of
-request latency.

-

The gRPC service userapi.UserAPI records metrics for the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively.

-

The meshapi.MeshAPI service records metrics for the method NewMeshCert, which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/architecture/secrets.html b/pr-preview/pr-1071/0.8/architecture/secrets.html deleted file mode 100644 index 6bd8f3a8a3..0000000000 --- a/pr-preview/pr-1071/0.8/architecture/secrets.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Secrets & recovery | Contrast - - - - -
Skip to main content
Version: 0.8

Secrets & recovery

-

When the Coordinator is configured with the initial manifest, it generates a random secret seed. -From this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history. -This derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state.

-

The secret seed is returned to the user on the first call to contrast set, encrypted with the user's public seed share owner key. -If no seed share owner key is provided, a key is generated and stored in the working directory.

-

Persistence

-

The Coordinator runs as a StatefulSet with a dynamically provisioned persistent volume. -This volume stores the manifest history and the associated runtime policies. -The manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads. -However, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users. -Thus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed.

-

Recovery

-

When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests. -It needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures. -This procedure is called recovery and is initiated by the workload owner. -The CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the Recover method. -The Coordinator recovers its key material and verifies the manifest history signature.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/basics/confidential-containers.html b/pr-preview/pr-1071/0.8/basics/confidential-containers.html deleted file mode 100644 index e98cacbfe4..0000000000 --- a/pr-preview/pr-1071/0.8/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 0.8

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/basics/features.html b/pr-preview/pr-1071/0.8/basics/features.html deleted file mode 100644 index 291f4dd443..0000000000 --- a/pr-preview/pr-1071/0.8/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Skip to main content
Version: 0.8

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/basics/security-benefits.html b/pr-preview/pr-1071/0.8/basics/security-benefits.html deleted file mode 100644 index 09af9e1fb7..0000000000 --- a/pr-preview/pr-1071/0.8/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Skip to main content
Version: 0.8

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/components/overview.html b/pr-preview/pr-1071/0.8/components/overview.html deleted file mode 100644 index 70314635a5..0000000000 --- a/pr-preview/pr-1071/0.8/components/overview.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
Version: 0.8

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/components/policies.html b/pr-preview/pr-1071/0.8/components/policies.html deleted file mode 100644 index aceecf4907..0000000000 --- a/pr-preview/pr-1071/0.8/components/policies.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Skip to main content
Version: 0.8

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/components/runtime.html b/pr-preview/pr-1071/0.8/components/runtime.html deleted file mode 100644 index 750df07d2a..0000000000 --- a/pr-preview/pr-1071/0.8/components/runtime.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Skip to main content
Version: 0.8

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

cloud-hypervisor virtual machine manager (VMM)

-

The containerd shim uses cloud-hypervisor to create a confidential virtual machine for every pod. -This requires the cloud-hypervisor binary to be installed on every node (responsibility of the node-installer).

-

Tardev snapshotter

-

Contrast uses a special containerd snapshotter (tardev) to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor as the virtual machine manager (VMM)
  • -
  • Install an IGVM file for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/components/service-mesh.html b/pr-preview/pr-1071/0.8/components/service-mesh.html deleted file mode 100644 index b24779cf4e..0000000000 --- a/pr-preview/pr-1071/0.8/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Skip to main content
Version: 0.8

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables CONTRAST_INGRESS_PROXY_CONFIG, -CONTRAST_EGRESS_PROXY_CONFIG and CONTRAST_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: CONTRAST_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v0.8.1@sha256:de65f2921d617fd2cee3734c4d325b9464e655d3c29e95844163a0738937748a"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-tls-certs
mountPath: /tls-config
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/deployment.html b/pr-preview/pr-1071/0.8/deployment.html deleted file mode 100644 index 1b9a052209..0000000000 --- a/pr-preview/pr-1071/0.8/deployment.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 0.8

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set it up.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/runtime.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/coordinator.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-tls-certs shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate --reference-values aks-clh-snp resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --reference-values aks-clh-snp --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-tls-certs volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:v0.8.1@sha256:6260af0b4ee2b5e583970aaa74ba6f5cbaa4d2029bc2aef947987d2398f1164f"
name: contrast-initializer
volumeMounts:
- mountPath: /tls-config
name: contrast-tls-certs
volumes:
- emptyDir: {}
name: contrast-tls-certs
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

This will use the reference values from the manifest file to attest the Coordinator. -After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the -service mesh root certificate and the history of manifests into the verify/ directory. In addition, the policies -referenced in the active manifest are also written to the directory. The verification will fail if the active -manifest at the Coordinator doesn't match the manifest passed to the CLI.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Recover the Coordinator

-

If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material. -For demonstration purposes, you can simulate this scenario by deleting the Coordinator pod.

-
kubectl delete pod -l app.kubernetes.io/name=coordinator
-

Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet. -You can confirm this by running verify again, or you can restart a workload pod, which should stay in the initialization phase. -However, the secret seed in your working directory is sufficient to recover the coordinator.

-
contrast recover -c "${coordinator}:1313"
-

Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state. -You can now verify the Coordinator again, which should return the same manifest you set before.

-
warning

The recovery process invalidates the mesh CA certificate: -existing workloads won't be able to communicate with workloads newly spawned. -All workloads should be restarted after the recovery succeeded.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/examples/emojivoto.html b/pr-preview/pr-1071/0.8/examples/emojivoto.html deleted file mode 100644 index 5d5cf17c4f..0000000000 --- a/pr-preview/pr-1071/0.8/examples/emojivoto.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 0.8

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voters perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

emojivoto components topology

-

Motivation

-

Using a voting service, users' votes are considered highly sensitive data, as we require -a secret ballot. Also, users are likely interested in the fairness of the ballot. For -both requirements, we can use Confidential Computing and, specifically, workload attestation -to prove to those interested in voting that the app is running in a protected environment -where their votes are processed without leaking to the platform provider or workload owner.

-

Prerequisites

- -

Steps to deploy emojivoto with Contrast

-

Downloading the deployment

-

The emojivoto deployment files are part of Contrast release. You can download the -latest deployment by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v0.8.1/emojivoto-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/runtime.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/coordinator.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc-<VERSIONHASH> -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Voter's perspective: Verifying the ballot

-

As voters, we want to verify the fairness and confidentiality of the deployment before -deciding to vote. Regardless of the scale of our distributed deployment, Contrast only -needs a single remote attestation step to verify the deployment. By doing remote attestation -of the Coordinator, we transitively verify those systems the Coordinator has already attested -or will attest in the future. Successful verification of the Coordinator means that -we can be sure it will enforce the configured manifest.

-

Attest the Coordinator

-

A potential voter can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will attest the Coordinator using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-

Manifest history and artifact audit

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Confidential connection to the attested workload

-

After ensuring the configuration of the Coordinator fits the expectation, you can securely connect -to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Certificate SAN and manifest update (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configure the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
-

Update the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/features-limitations.html b/pr-preview/pr-1071/0.8/features-limitations.html deleted file mode 100644 index 48d9cd14c2..0000000000 --- a/pr-preview/pr-1071/0.8/features-limitations.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Skip to main content
Version: 0.8

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Contrast only supports volumes with volumeMode: Block. These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
-

Automatic recovery and high availability

-

The Contrast Coordinator is a singleton and can't be scaled to more than one instance. -When this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually. -In a future release, we plan to support distributed Coordinator instances that can recover automatically.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/getting-started/cluster-setup.html b/pr-preview/pr-1071/0.8/getting-started/cluster-setup.html deleted file mode 100644 index d091d980de..0000000000 --- a/pr-preview/pr-1071/0.8/getting-started/cluster-setup.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 0.8

Create a cluster

-

Prerequisites

-

Install the latest version of the Azure CLI.

-

Login to your account, which needs -to have the permissions to create an AKS cluster, by executing:

-
az login
-

Prepare using the AKS preview

-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a -non-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool.

-

We'll first start by creating the non-CoCo cluster:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.29 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--node-count 1 \
--generate-ssh-keys
-

We then add a second node pool with CoCo support:

-
az aks nodepool add \
--resource-group "${azResourceGroup:?}" \
--name nodepool2 \
--cluster-name "${azClusterName:?}" \
--node-count 1 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation
-

Optionally, we can now remove the non-CoCo node pool:

-
az aks nodepool delete \
--resource-group "${azResourceGroup:?}" \
--cluster-name "${azClusterName:?}" \
--name nodepool1
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show two nodes:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
aks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0
-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/getting-started/install.html b/pr-preview/pr-1071/0.8/getting-started/install.html deleted file mode 100644 index 19b6b8b5b6..0000000000 --- a/pr-preview/pr-1071/0.8/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 0.8

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v0.8.1/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.8/troubleshooting.html b/pr-preview/pr-1071/0.8/troubleshooting.html deleted file mode 100644 index 83828d7e27..0000000000 --- a/pr-preview/pr-1071/0.8/troubleshooting.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - -Troubleshooting | Contrast - - - - -
Skip to main content
Version: 0.8

Troubleshooting

-

This section contains information on how to debug your Contrast deployment.

-

Logging

-

Collecting logs can be a good first step to identify problems in your -deployment. Both the CLI and the Contrast Coordinator as well as the Initializer -can be configured to emit additional logs.

-

CLI

-

The CLI logs can be configured with the --log-level command-line flag, which -can be set to either debug, info, warn or error. The default is info. -Setting this to debug can get more fine-grained information as to where the -problem lies.

-

Coordinator and Initializer

-

The logs from the Coordinator and the Initializer can be configured via the -environment variables CONTRAST_LOG_LEVEL, CONTRAST_LOG_FORMAT and -CONTRAST_LOG_SUBSYSTEMS.

-
    -
  • CONTRAST_LOG_LEVEL can be set to one of either debug, info, warn, or -error, similar to the CLI (defaults to info).
  • -
  • CONTRAST_LOG_FORMAT can be set to text or json, determining the output -format (defaults to text).
  • -
  • CONTRAST_LOG_SUBSYSTEMS is a comma-seperated list of subsystems that should -be enabled for logging, which are disabled by default. Subsystems include: -snp-issuer, kds-getter, and snp-validator. To enable all subsystems, use -* as the value for this environment variable. -Warnings and error messages from subsystems get printed regardless of whether -the subsystem is listed in the CONTRAST_LOG_SUBSYSTEMS environment variable.
  • -
-

To configure debug logging with all subsystems for your Coordinator, add the -following variables to your container definition.

-
spec: # v1.PodSpec
containers:
image: "ghcr.io/edgelesssys/contrast/coordinator:v0.8.1@sha256:bcd08a03096d38b350853c1dc8a595e0e8dd18e6af651bad4afd6838d842e257"
name: coordinator
env:
- name: CONTRAST_LOG_LEVEL
value: debug
- name: CONTRAST_LOG_SUBSYSTEMS
value: "*"
# ...
-
info

While the Contrast Coordinator has a policy that allows certain configurations, -the Initializer and service mesh don't. When changing environment variables of other -parts than the Coordinator, ensure to rerun contrast generate to update the policy.

-

To access the logs generated by the Coordinator, you can use kubectl with the -following command:

-
kubectl logs <coordinator-pod-name>
-

Pod fails to start

-

If the Coordinator or a workload pod fails to even start, it can be helpful to -look at the events of the pod during the startup process using the describe -command.

-
kubectl -n <namespace> events --for pod/<coordinator-pod-name>
-

Example output:

-
LAST SEEN  TYPE     REASON  OBJECT             MESSAGE
32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...
-

A common error, as in this example, is that the container creation was blocked by the -policy. Potential reasons are a modification of the deployment YAML without updating -the policies afterward, or a version mismatch between Contrast components.

-

Regenerating the policies

-

To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated -policies, rerun

-
contrast generate
-

on your deployment. If any of the policy annotations change, re-deploy with the updated policies.

-

Pin container images

-

When generating the policies, Contrast will download the images specified in your deployment -YAML and include their cryptographic identity. If the image tag is moved to another -container image after the policy has been generated, the image downloaded at deploy time -will differ from the one at generation time, and the policy enforcement won't allow the -container to be started in the pod VM.

-

To ensure the correct image is always used, pin the container image to a fixed sha256:

-
image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac
-

This way, the same image will still be pulled when the container tag (22.04) is moved -to another image.

-

Validate Contrast components match

-

A version mismatch between Contrast components can cause policy validation or attestation -to fail. Each Contrast runtime is identifiable based on its (shortened) measurement value -used to name the runtime class version.

-

First, analyze which runtime class is currently installed in your cluster by running

-
kubectl get runtimeclasses
-

This should give you output similar to the following one.

-
NAME                                           HANDLER                                        AGE
contrast-cc-30bfa8706b542271ec9b7762bbb400af contrast-cc-30bfa8706b542271ec9b7762bbb400af 23d
contrast-cc-4d70a6e266cca46dfa8e41d92874e638 contrast-cc-4d70a6e266cca46dfa8e41d92874e638 7d
contrast-cc-b817659e094106f61bf6c178c27153ba contrast-cc-b817659e094106f61bf6c178c27153ba 2d19h
contrast-cc-beee79ca916b9e5dc59602788cbfb097 contrast-cc-beee79ca916b9e5dc59602788cbfb097 121m
kata-cc-isolation kata-cc 45d
-

The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided -by the AKS CoCo preview, which isn't used by Contrast).

-

Next, check if the pod that won't start has the correct runtime class configured, and the -Coordinator uses the exact same runtime:

-
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>
-

The output should list the runtime class the pod is using:

-
contrast-cc-beee79ca916b9e5dc59602788cbfb097
contrast-cc-beee79ca916b9e5dc59602788cbfb097
-

Version information about the currently used CLI can be obtained via the version flag:

-
contrast --version
-
contrast version v0.X.0

runtime handler: contrast-cc-beee79ca916b9e5dc59602788cbfb097
launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35
genpolicy version: 3.2.0.azl1.genpolicy0
image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...
ghcr.io/edgelesssys/contrast/initializer@sha256:...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9.html b/pr-preview/pr-1071/0.9.html deleted file mode 100644 index 6cc79dc852..0000000000 --- a/pr-preview/pr-1071/0.9.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 0.9

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/about/telemetry.html b/pr-preview/pr-1071/0.9/about/telemetry.html deleted file mode 100644 index 65a5e9952e..0000000000 --- a/pr-preview/pr-1071/0.9/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 0.9

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/architecture/attestation.html b/pr-preview/pr-1071/0.9/architecture/attestation.html deleted file mode 100644 index ea59376844..0000000000 --- a/pr-preview/pr-1071/0.9/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 0.9

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -On AMD SEV-SNP the hash of the policy is then added to the attestation report via the HOSTDATA field by the hypervisor. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/architecture/certificates.html b/pr-preview/pr-1071/0.9/architecture/certificates.html deleted file mode 100644 index 8020bc8260..0000000000 --- a/pr-preview/pr-1071/0.9/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 0.9

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/architecture/observability.html b/pr-preview/pr-1071/0.9/architecture/observability.html deleted file mode 100644 index 0049dac133..0000000000 --- a/pr-preview/pr-1071/0.9/architecture/observability.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Skip to main content
Version: 0.9

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator exports gRPC metrics under the prefix contrast_grpc_server_. -These metrics are labeled with the gRPC service name and method name. -Metrics of interest include contrast_grpc_server_handled_total, which counts -the number of requests by return code, and -contrast_grpc_server_handling_seconds_bucket, which produces a histogram of
-request latency.

-

The gRPC service userapi.UserAPI records metrics for the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively.

-

The meshapi.MeshAPI service records metrics for the method NewMeshCert, which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures_total.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/architecture/secrets.html b/pr-preview/pr-1071/0.9/architecture/secrets.html deleted file mode 100644 index 2a7919590a..0000000000 --- a/pr-preview/pr-1071/0.9/architecture/secrets.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Secrets & recovery | Contrast - - - - -
Skip to main content
Version: 0.9

Secrets & recovery

-

When the Coordinator is configured with the initial manifest, it generates a random secret seed. -From this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history. -This derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state.

-

The secret seed is returned to the user on the first call to contrast set, encrypted with the user's public seed share owner key. -If no seed share owner key is provided, a key is generated and stored in the working directory.

-

Persistence

-

The Coordinator runs as a StatefulSet with a dynamically provisioned persistent volume. -This volume stores the manifest history and the associated runtime policies. -The manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads. -However, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users. -Thus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed.

-

Recovery

-

When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests. -It needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures. -This procedure is called recovery and is initiated by the workload owner. -The CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the Recover method. -The Coordinator recovers its key material and verifies the manifest history signature.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/basics/confidential-containers.html b/pr-preview/pr-1071/0.9/basics/confidential-containers.html deleted file mode 100644 index 93035ca86b..0000000000 --- a/pr-preview/pr-1071/0.9/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 0.9

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/basics/features.html b/pr-preview/pr-1071/0.9/basics/features.html deleted file mode 100644 index 93bd962f5b..0000000000 --- a/pr-preview/pr-1071/0.9/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Skip to main content
Version: 0.9

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/basics/security-benefits.html b/pr-preview/pr-1071/0.9/basics/security-benefits.html deleted file mode 100644 index 9ac90e269e..0000000000 --- a/pr-preview/pr-1071/0.9/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Skip to main content
Version: 0.9

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/components/overview.html b/pr-preview/pr-1071/0.9/components/overview.html deleted file mode 100644 index e0886941af..0000000000 --- a/pr-preview/pr-1071/0.9/components/overview.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
Version: 0.9

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/components/policies.html b/pr-preview/pr-1071/0.9/components/policies.html deleted file mode 100644 index 7c97b4a7fa..0000000000 --- a/pr-preview/pr-1071/0.9/components/policies.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Skip to main content
Version: 0.9

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/components/runtime.html b/pr-preview/pr-1071/0.9/components/runtime.html deleted file mode 100644 index cf1c25ccdf..0000000000 --- a/pr-preview/pr-1071/0.9/components/runtime.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Skip to main content
Version: 0.9

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

cloud-hypervisor virtual machine manager (VMM)

-

The containerd shim uses cloud-hypervisor to create a confidential virtual machine for every pod. -This requires the cloud-hypervisor binary to be installed on every node (responsibility of the node-installer).

-

Tardev snapshotter

-

Contrast uses a special containerd snapshotter (tardev) to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor as the virtual machine manager (VMM)
  • -
  • Install an IGVM file for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/components/service-mesh.html b/pr-preview/pr-1071/0.9/components/service-mesh.html deleted file mode 100644 index 92a822a23b..0000000000 --- a/pr-preview/pr-1071/0.9/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Skip to main content
Version: 0.9

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables CONTRAST_INGRESS_PROXY_CONFIG, -CONTRAST_EGRESS_PROXY_CONFIG and CONTRAST_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: CONTRAST_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v0.9.0@sha256:d97397770b8ea13082eab96099629f971688508e5b0cc1596df07aa5510d5972"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-tls-certs
mountPath: /tls-config
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/deployment.html b/pr-preview/pr-1071/0.9/deployment.html deleted file mode 100644 index 85160abde8..0000000000 --- a/pr-preview/pr-1071/0.9/deployment.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 0.9

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set it up.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/runtime.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/coordinator.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-tls-certs shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate --reference-values aks-clh-snp resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --reference-values aks-clh-snp --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-tls-certs volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:v0.9.0@sha256:ca1ee62f9abb47224a70cb4b1a4593b3fa83481e083047ec707ded911baf134b"
name: contrast-initializer
volumeMounts:
- mountPath: /tls-config
name: contrast-tls-certs
volumes:
- emptyDir: {}
name: contrast-tls-certs
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

This will use the reference values from the manifest file to attest the Coordinator. -After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the -service mesh root certificate and the history of manifests into the verify/ directory. In addition, the policies -referenced in the active manifest are also written to the directory. The verification will fail if the active -manifest at the Coordinator doesn't match the manifest passed to the CLI.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Recover the Coordinator

-

If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material. -For demonstration purposes, you can simulate this scenario by deleting the Coordinator pod.

-
kubectl delete pod -l app.kubernetes.io/name=coordinator
-

Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet. -You can confirm this by running verify again, or you can restart a workload pod, which should stay in the initialization phase. -However, the secret seed in your working directory is sufficient to recover the coordinator.

-
contrast recover -c "${coordinator}:1313"
-

Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state. -You can now verify the Coordinator again, which should return the same manifest you set before.

-
warning

The recovery process invalidates the mesh CA certificate: -existing workloads won't be able to communicate with workloads newly spawned. -All workloads should be restarted after the recovery succeeded.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/examples/emojivoto.html b/pr-preview/pr-1071/0.9/examples/emojivoto.html deleted file mode 100644 index 29e244f49c..0000000000 --- a/pr-preview/pr-1071/0.9/examples/emojivoto.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 0.9

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voters perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

emojivoto components topology

-

Motivation

-

Using a voting service, users' votes are considered highly sensitive data, as we require -a secret ballot. Also, users are likely interested in the fairness of the ballot. For -both requirements, we can use Confidential Computing and, specifically, workload attestation -to prove to those interested in voting that the app is running in a protected environment -where their votes are processed without leaking to the platform provider or workload owner.

-

Prerequisites

- -

Steps to deploy emojivoto with Contrast

-

Downloading the deployment

-

The emojivoto deployment files are part of Contrast release. You can download the -latest deployment by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v0.9.0/emojivoto-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/runtime.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/coordinator.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc-<platform>-<runtime-hash> -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Voter's perspective: Verifying the ballot

-

As voters, we want to verify the fairness and confidentiality of the deployment before -deciding to vote. Regardless of the scale of our distributed deployment, Contrast only -needs a single remote attestation step to verify the deployment. By doing remote attestation -of the Coordinator, we transitively verify those systems the Coordinator has already attested -or will attest in the future. Successful verification of the Coordinator means that -we can be sure it will enforce the configured manifest.

-

Attest the Coordinator

-

A potential voter can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will attest the Coordinator using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-

Manifest history and artifact audit

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Confidential connection to the attested workload

-

After ensuring the configuration of the Coordinator fits the expectation, you can securely connect -to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Certificate SAN and manifest update (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configure the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
-

Update the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/features-limitations.html b/pr-preview/pr-1071/0.9/features-limitations.html deleted file mode 100644 index 4f3ff76902..0000000000 --- a/pr-preview/pr-1071/0.9/features-limitations.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Skip to main content
Version: 0.9

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Contrast only supports volumes with volumeMode: Block. These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
-

Automatic recovery and high availability

-

The Contrast Coordinator is a singleton and can't be scaled to more than one instance. -When this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually. -In a future release, we plan to support distributed Coordinator instances that can recover automatically.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/getting-started/cluster-setup.html b/pr-preview/pr-1071/0.9/getting-started/cluster-setup.html deleted file mode 100644 index 544e8e64dd..0000000000 --- a/pr-preview/pr-1071/0.9/getting-started/cluster-setup.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 0.9

Create a cluster

-

Prerequisites

-

Install the latest version of the Azure CLI.

-

Login to your account, which needs -to have the permissions to create an AKS cluster, by executing:

-
az login
-

Prepare using the AKS preview

-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a -non-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool.

-

We'll first start by creating the non-CoCo cluster:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.29 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--node-count 1 \
--generate-ssh-keys
-

We then add a second node pool with CoCo support:

-
az aks nodepool add \
--resource-group "${azResourceGroup:?}" \
--name nodepool2 \
--cluster-name "${azClusterName:?}" \
--node-count 1 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation
-

Optionally, we can now remove the non-CoCo node pool:

-
az aks nodepool delete \
--resource-group "${azResourceGroup:?}" \
--cluster-name "${azClusterName:?}" \
--name nodepool1
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show two nodes:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
aks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0
-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/getting-started/install.html b/pr-preview/pr-1071/0.9/getting-started/install.html deleted file mode 100644 index f46bce2ca8..0000000000 --- a/pr-preview/pr-1071/0.9/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 0.9

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v0.9.0/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/0.9/troubleshooting.html b/pr-preview/pr-1071/0.9/troubleshooting.html deleted file mode 100644 index e335de6eee..0000000000 --- a/pr-preview/pr-1071/0.9/troubleshooting.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - -Troubleshooting | Contrast - - - - -
Skip to main content
Version: 0.9

Troubleshooting

-

This section contains information on how to debug your Contrast deployment.

-

Logging

-

Collecting logs can be a good first step to identify problems in your -deployment. Both the CLI and the Contrast Coordinator as well as the Initializer -can be configured to emit additional logs.

-

CLI

-

The CLI logs can be configured with the --log-level command-line flag, which -can be set to either debug, info, warn or error. The default is info. -Setting this to debug can get more fine-grained information as to where the -problem lies.

-

Coordinator and Initializer

-

The logs from the Coordinator and the Initializer can be configured via the -environment variables CONTRAST_LOG_LEVEL, CONTRAST_LOG_FORMAT and -CONTRAST_LOG_SUBSYSTEMS.

-
    -
  • CONTRAST_LOG_LEVEL can be set to one of either debug, info, warn, or -error, similar to the CLI (defaults to info).
  • -
  • CONTRAST_LOG_FORMAT can be set to text or json, determining the output -format (defaults to text).
  • -
  • CONTRAST_LOG_SUBSYSTEMS is a comma-seperated list of subsystems that should -be enabled for logging, which are disabled by default. Subsystems include: -kds-getter, issuer and validator. -To enable all subsystems, use * as the value for this environment variable. -Warnings and error messages from subsystems get printed regardless of whether -the subsystem is listed in the CONTRAST_LOG_SUBSYSTEMS environment variable.
  • -
-

To configure debug logging with all subsystems for your Coordinator, add the -following variables to your container definition.

-
spec: # v1.PodSpec
containers:
image: "ghcr.io/edgelesssys/contrast/coordinator:v0.9.0@sha256:7530dcd0bd16b5dbeda915c8ebfeb5d860c2f9e4661acbc70fdaae60bf174e20"
name: coordinator
env:
- name: CONTRAST_LOG_LEVEL
value: debug
- name: CONTRAST_LOG_SUBSYSTEMS
value: "*"
# ...
-
info

While the Contrast Coordinator has a policy that allows certain configurations, -the Initializer and service mesh don't. When changing environment variables of other -parts than the Coordinator, ensure to rerun contrast generate to update the policy.

-

To access the logs generated by the Coordinator, you can use kubectl with the -following command:

-
kubectl logs <coordinator-pod-name>
-

Pod fails to start

-

If the Coordinator or a workload pod fails to even start, it can be helpful to -look at the events of the pod during the startup process using the describe -command.

-
kubectl -n <namespace> events --for pod/<coordinator-pod-name>
-

Example output:

-
LAST SEEN  TYPE     REASON  OBJECT             MESSAGE
32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...
-

A common error, as in this example, is that the container creation was blocked by the -policy. Potential reasons are a modification of the deployment YAML without updating -the policies afterward, or a version mismatch between Contrast components.

-

Regenerating the policies

-

To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated -policies, rerun

-
contrast generate
-

on your deployment. If any of the policy annotations change, re-deploy with the updated policies.

-

Pin container images

-

When generating the policies, Contrast will download the images specified in your deployment -YAML and include their cryptographic identity. If the image tag is moved to another -container image after the policy has been generated, the image downloaded at deploy time -will differ from the one at generation time, and the policy enforcement won't allow the -container to be started in the pod VM.

-

To ensure the correct image is always used, pin the container image to a fixed sha256:

-
image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac
-

This way, the same image will still be pulled when the container tag (22.04) is moved -to another image.

-

Validate Contrast components match

-

A version mismatch between Contrast components can cause policy validation or attestation -to fail. Each Contrast runtime is identifiable based on its (shortened) measurement value -used to name the runtime class version.

-

First, analyze which runtime class is currently installed in your cluster by running

-
kubectl get runtimeclasses
-

This should give you output similar to the following one.

-
NAME                                           HANDLER                                        AGE
contrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h
kata-cc-isolation kata-cc 45d
-

The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided -by the AKS CoCo preview, which isn't used by Contrast).

-

Next, check if the pod that won't start has the correct runtime class configured, and the -Coordinator uses the exact same runtime:

-
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>
-

The output should list the runtime class the pod is using:

-
contrast-cc-aks-clh-snp-7173acb5
-

Version information about the currently used CLI can be obtained via the version flag:

-
contrast --version
-
contrast version v0.X.0

runtime handler: contrast-cc-aks-clh-snp-7173acb5
launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35
genpolicy version: 3.2.0.azl1.genpolicy0
image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...
ghcr.io/edgelesssys/contrast/initializer@sha256:...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0.html b/pr-preview/pr-1071/1.0.html deleted file mode 100644 index dd4902724d..0000000000 --- a/pr-preview/pr-1071/1.0.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 1.0

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/about/telemetry.html b/pr-preview/pr-1071/1.0/about/telemetry.html deleted file mode 100644 index ca32ebacfb..0000000000 --- a/pr-preview/pr-1071/1.0/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 1.0

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/architecture/attestation.html b/pr-preview/pr-1071/1.0/architecture/attestation.html deleted file mode 100644 index 5590a9a805..0000000000 --- a/pr-preview/pr-1071/1.0/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 1.0

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -On AMD SEV-SNP the hash of the policy is then added to the attestation report via the HOSTDATA field by the hypervisor. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/architecture/certificates.html b/pr-preview/pr-1071/1.0/architecture/certificates.html deleted file mode 100644 index dbca2f9fc5..0000000000 --- a/pr-preview/pr-1071/1.0/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 1.0

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/architecture/observability.html b/pr-preview/pr-1071/1.0/architecture/observability.html deleted file mode 100644 index 45b87f8ccf..0000000000 --- a/pr-preview/pr-1071/1.0/architecture/observability.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Skip to main content
Version: 1.0

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator exports gRPC metrics under the prefix contrast_grpc_server_. -These metrics are labeled with the gRPC service name and method name. -Metrics of interest include contrast_grpc_server_handled_total, which counts -the number of requests by return code, and -contrast_grpc_server_handling_seconds_bucket, which produces a histogram of
-request latency.

-

The gRPC service userapi.UserAPI records metrics for the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively.

-

The meshapi.MeshAPI service records metrics for the method NewMeshCert, which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures_total.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/architecture/secrets.html b/pr-preview/pr-1071/1.0/architecture/secrets.html deleted file mode 100644 index b9f6b8402a..0000000000 --- a/pr-preview/pr-1071/1.0/architecture/secrets.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Secrets & recovery | Contrast - - - - -
Skip to main content
Version: 1.0

Secrets & recovery

-

When the Coordinator is configured with the initial manifest, it generates a random secret seed. -From this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history. -This derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state.

-

The secret seed is returned to the user on the first call to contrast set, encrypted with the user's public seed share owner key. -If no seed share owner key is provided, a key is generated and stored in the working directory.

-

Persistence

-

The Coordinator runs as a StatefulSet with a dynamically provisioned persistent volume. -This volume stores the manifest history and the associated runtime policies. -The manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads. -However, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users. -Thus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed.

-

Recovery

-

When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests. -It needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures. -This procedure is called recovery and is initiated by the workload owner. -The CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the Recover method. -The Coordinator recovers its key material and verifies the manifest history signature.

-

Workload Secrets

-

The Coordinator provides each workload a secret seed during attestation. This secret can be used by the workload to derive additional secrets for example to -encrypt persistent data. Like the workload certificates it's mounted in the shared Kubernetes volume contrast-secrets in the path <mountpoint>/secrets/workload-secret-seed.

-
warning

The workload owner can decrypt data encrypted with secrets derived from the workload secret. -The workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner. -If the data owner and the workload owner is the same entity, then they can safely use the workload secrets.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/basics/confidential-containers.html b/pr-preview/pr-1071/1.0/basics/confidential-containers.html deleted file mode 100644 index 04f8484aa1..0000000000 --- a/pr-preview/pr-1071/1.0/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 1.0

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/basics/features.html b/pr-preview/pr-1071/1.0/basics/features.html deleted file mode 100644 index c79435fb18..0000000000 --- a/pr-preview/pr-1071/1.0/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Skip to main content
Version: 1.0

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/basics/security-benefits.html b/pr-preview/pr-1071/1.0/basics/security-benefits.html deleted file mode 100644 index bebabbea8f..0000000000 --- a/pr-preview/pr-1071/1.0/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Skip to main content
Version: 1.0

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/components/overview.html b/pr-preview/pr-1071/1.0/components/overview.html deleted file mode 100644 index 7f21dec24c..0000000000 --- a/pr-preview/pr-1071/1.0/components/overview.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
Version: 1.0

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/components/policies.html b/pr-preview/pr-1071/1.0/components/policies.html deleted file mode 100644 index 0777b94c83..0000000000 --- a/pr-preview/pr-1071/1.0/components/policies.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Skip to main content
Version: 1.0

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/components/runtime.html b/pr-preview/pr-1071/1.0/components/runtime.html deleted file mode 100644 index a272fc9476..0000000000 --- a/pr-preview/pr-1071/1.0/components/runtime.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Skip to main content
Version: 1.0

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

cloud-hypervisor virtual machine manager (VMM)

-

The containerd shim uses cloud-hypervisor to create a confidential virtual machine for every pod. -This requires the cloud-hypervisor binary to be installed on every node (responsibility of the node-installer).

-

Tardev snapshotter

-

Contrast uses a special containerd snapshotter (tardev) to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor as the virtual machine manager (VMM)
  • -
  • Install an IGVM file for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/components/service-mesh.html b/pr-preview/pr-1071/1.0/components/service-mesh.html deleted file mode 100644 index 1425716d6b..0000000000 --- a/pr-preview/pr-1071/1.0/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Skip to main content
Version: 1.0

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables CONTRAST_INGRESS_PROXY_CONFIG, -CONTRAST_EGRESS_PROXY_CONFIG and CONTRAST_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: CONTRAST_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v1.0.0@sha256:2aa3a6711ed8dee36a8dcdae63dd10b9fd5bb9aac6dba688ed1be8ab1fbb310e"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-secrets
mountPath: /contrast
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/deployment.html b/pr-preview/pr-1071/1.0/deployment.html deleted file mode 100644 index 9247f2aa05..0000000000 --- a/pr-preview/pr-1071/1.0/deployment.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 1.0

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set it up.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/runtime.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/coordinator.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-secrets shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate --reference-values aks-clh-snp resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --reference-values aks-clh-snp --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-secrets volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:v1.0.0@sha256:a86b8637016aff07fe157f6334f58033707f2d657263e956f195a5254e1ee9b5"
name: contrast-initializer
volumeMounts:
- mountPath: /contrast
name: contrast-secrets
volumes:
- emptyDir: {}
name: contrast-secrets
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

This will use the reference values from the manifest file to attest the Coordinator. -After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the -service mesh root certificate and the history of manifests into the verify/ directory. In addition, the policies -referenced in the active manifest are also written to the directory. The verification will fail if the active -manifest at the Coordinator doesn't match the manifest passed to the CLI.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Recover the Coordinator

-

If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material. -For demonstration purposes, you can simulate this scenario by deleting the Coordinator pod.

-
kubectl delete pod -l app.kubernetes.io/name=coordinator
-

Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet. -You can confirm this by running verify again, or you can restart a workload pod, which should stay in the initialization phase. -However, the secret seed in your working directory is sufficient to recover the coordinator.

-
contrast recover -c "${coordinator}:1313"
-

Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state. -You can now verify the Coordinator again, which should return the same manifest you set before.

-
warning

The recovery process invalidates the mesh CA certificate: -existing workloads won't be able to communicate with workloads newly spawned. -All workloads should be restarted after the recovery succeeded.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/examples/emojivoto.html b/pr-preview/pr-1071/1.0/examples/emojivoto.html deleted file mode 100644 index 21d15eba1b..0000000000 --- a/pr-preview/pr-1071/1.0/examples/emojivoto.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 1.0

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voters perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

emojivoto components topology

-

Motivation

-

Using a voting service, users' votes are considered highly sensitive data, as we require -a secret ballot. Also, users are likely interested in the fairness of the ballot. For -both requirements, we can use Confidential Computing and, specifically, workload attestation -to prove to those interested in voting that the app is running in a protected environment -where their votes are processed without leaking to the platform provider or workload owner.

-

Prerequisites

- -

Steps to deploy emojivoto with Contrast

-

Downloading the deployment

-

The emojivoto deployment files are part of Contrast release. You can download the -latest deployment by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.0.0/emojivoto-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/runtime.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/coordinator.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc-<platform>-<runtime-hash> -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Voter's perspective: Verifying the ballot

-

As voters, we want to verify the fairness and confidentiality of the deployment before -deciding to vote. Regardless of the scale of our distributed deployment, Contrast only -needs a single remote attestation step to verify the deployment. By doing remote attestation -of the Coordinator, we transitively verify those systems the Coordinator has already attested -or will attest in the future. Successful verification of the Coordinator means that -we can be sure it will enforce the configured manifest.

-

Attest the Coordinator

-

A potential voter can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will attest the Coordinator using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-

Manifest history and artifact audit

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Confidential connection to the attested workload

-

After ensuring the configuration of the Coordinator fits the expectation, you can securely connect -to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Certificate SAN and manifest update (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configure the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {
"SANs": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
"WorkloadSecretID": "web"
},
-

Update the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/features-limitations.html b/pr-preview/pr-1071/1.0/features-limitations.html deleted file mode 100644 index e64365308d..0000000000 --- a/pr-preview/pr-1071/1.0/features-limitations.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Skip to main content
Version: 1.0

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Contrast only supports volumes with volumeMode: Block. These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
-

Automatic recovery and high availability

-

The Contrast Coordinator is a singleton and can't be scaled to more than one instance. -When this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually. -In a future release, we plan to support distributed Coordinator instances that can recover automatically.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/getting-started/cluster-setup.html b/pr-preview/pr-1071/1.0/getting-started/cluster-setup.html deleted file mode 100644 index c83fadf547..0000000000 --- a/pr-preview/pr-1071/1.0/getting-started/cluster-setup.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 1.0

Create a cluster

-

Prerequisites

-

Install the latest version of the Azure CLI.

-

Login to your account, which needs -to have the permissions to create an AKS cluster, by executing:

-
az login
-

Prepare using the AKS preview

-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a -non-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool.

-

We'll first start by creating the non-CoCo cluster:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.29 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--node-count 1 \
--generate-ssh-keys
-

We then add a second node pool with CoCo support:

-
az aks nodepool add \
--resource-group "${azResourceGroup:?}" \
--name nodepool2 \
--cluster-name "${azClusterName:?}" \
--node-count 1 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation
-

Optionally, we can now remove the non-CoCo node pool:

-
az aks nodepool delete \
--resource-group "${azResourceGroup:?}" \
--cluster-name "${azClusterName:?}" \
--name nodepool1
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show two nodes:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
aks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0
-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/getting-started/install.html b/pr-preview/pr-1071/1.0/getting-started/install.html deleted file mode 100644 index 563eddd5d4..0000000000 --- a/pr-preview/pr-1071/1.0/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 1.0

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v1.0.0/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.0/troubleshooting.html b/pr-preview/pr-1071/1.0/troubleshooting.html deleted file mode 100644 index 8117df597e..0000000000 --- a/pr-preview/pr-1071/1.0/troubleshooting.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - -Troubleshooting | Contrast - - - - -
Skip to main content
Version: 1.0

Troubleshooting

-

This section contains information on how to debug your Contrast deployment.

-

Logging

-

Collecting logs can be a good first step to identify problems in your -deployment. Both the CLI and the Contrast Coordinator as well as the Initializer -can be configured to emit additional logs.

-

CLI

-

The CLI logs can be configured with the --log-level command-line flag, which -can be set to either debug, info, warn or error. The default is info. -Setting this to debug can get more fine-grained information as to where the -problem lies.

-

Coordinator and Initializer

-

The logs from the Coordinator and the Initializer can be configured via the -environment variables CONTRAST_LOG_LEVEL, CONTRAST_LOG_FORMAT and -CONTRAST_LOG_SUBSYSTEMS.

-
    -
  • CONTRAST_LOG_LEVEL can be set to one of either debug, info, warn, or -error, similar to the CLI (defaults to info).
  • -
  • CONTRAST_LOG_FORMAT can be set to text or json, determining the output -format (defaults to text).
  • -
  • CONTRAST_LOG_SUBSYSTEMS is a comma-seperated list of subsystems that should -be enabled for logging, which are disabled by default. Subsystems include: -kds-getter, issuer and validator. -To enable all subsystems, use * as the value for this environment variable. -Warnings and error messages from subsystems get printed regardless of whether -the subsystem is listed in the CONTRAST_LOG_SUBSYSTEMS environment variable.
  • -
-

To configure debug logging with all subsystems for your Coordinator, add the -following variables to your container definition.

-
spec: # v1.PodSpec
containers:
image: "ghcr.io/edgelesssys/contrast/coordinator:v1.0.0@sha256:36766ae51dbafa4ef5e90c3e24698bdfbb3b4d765e13c14bdee190a1a7638c35"
name: coordinator
env:
- name: CONTRAST_LOG_LEVEL
value: debug
- name: CONTRAST_LOG_SUBSYSTEMS
value: "*"
# ...
-
info

While the Contrast Coordinator has a policy that allows certain configurations, -the Initializer and service mesh don't. When changing environment variables of other -parts than the Coordinator, ensure to rerun contrast generate to update the policy.

-

To access the logs generated by the Coordinator, you can use kubectl with the -following command:

-
kubectl logs <coordinator-pod-name>
-

Pod fails to start

-

If the Coordinator or a workload pod fails to even start, it can be helpful to -look at the events of the pod during the startup process using the describe -command.

-
kubectl -n <namespace> events --for pod/<coordinator-pod-name>
-

Example output:

-
LAST SEEN  TYPE     REASON  OBJECT             MESSAGE
32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...
-

A common error, as in this example, is that the container creation was blocked by the -policy. Potential reasons are a modification of the deployment YAML without updating -the policies afterward, or a version mismatch between Contrast components.

-

Regenerating the policies

-

To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated -policies, rerun

-
contrast generate
-

on your deployment. If any of the policy annotations change, re-deploy with the updated policies.

-

Pin container images

-

When generating the policies, Contrast will download the images specified in your deployment -YAML and include their cryptographic identity. If the image tag is moved to another -container image after the policy has been generated, the image downloaded at deploy time -will differ from the one at generation time, and the policy enforcement won't allow the -container to be started in the pod VM.

-

To ensure the correct image is always used, pin the container image to a fixed sha256:

-
image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac
-

This way, the same image will still be pulled when the container tag (22.04) is moved -to another image.

-

Validate Contrast components match

-

A version mismatch between Contrast components can cause policy validation or attestation -to fail. Each Contrast runtime is identifiable based on its (shortened) measurement value -used to name the runtime class version.

-

First, analyze which runtime class is currently installed in your cluster by running

-
kubectl get runtimeclasses
-

This should give you output similar to the following one.

-
NAME                                           HANDLER                                        AGE
contrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h
kata-cc-isolation kata-cc 45d
-

The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided -by the AKS CoCo preview, which isn't used by Contrast).

-

Next, check if the pod that won't start has the correct runtime class configured, and the -Coordinator uses the exact same runtime:

-
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>
-

The output should list the runtime class the pod is using:

-
contrast-cc-aks-clh-snp-7173acb5
-

Version information about the currently used CLI can be obtained via the version flag:

-
contrast --version
-
contrast version v0.X.0

runtime handler: contrast-cc-aks-clh-snp-7173acb5
launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35
genpolicy version: 3.2.0.azl1.genpolicy0
image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...
ghcr.io/edgelesssys/contrast/initializer@sha256:...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1.html b/pr-preview/pr-1071/1.1.html deleted file mode 100644 index 2b661814ca..0000000000 --- a/pr-preview/pr-1071/1.1.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Skip to main content
Version: 1.1

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/about/telemetry.html b/pr-preview/pr-1071/1.1/about/telemetry.html deleted file mode 100644 index 6a49174e20..0000000000 --- a/pr-preview/pr-1071/1.1/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 1.1

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/architecture/attestation.html b/pr-preview/pr-1071/1.1/architecture/attestation.html deleted file mode 100644 index d68ccc2d39..0000000000 --- a/pr-preview/pr-1071/1.1/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 1.1

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -The hypervisor adds the hash of the policy to the attestation report via the HOSTDATA (on AMD SEV-SNP) or MRCONFIGID (Intel TDX) fields. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA/MRCONFIGID field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP or Intel TDX to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/architecture/certificates.html b/pr-preview/pr-1071/1.1/architecture/certificates.html deleted file mode 100644 index 01908e1e5a..0000000000 --- a/pr-preview/pr-1071/1.1/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 1.1

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/architecture/observability.html b/pr-preview/pr-1071/1.1/architecture/observability.html deleted file mode 100644 index d42a036649..0000000000 --- a/pr-preview/pr-1071/1.1/architecture/observability.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Skip to main content
Version: 1.1

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator exports gRPC metrics under the prefix contrast_grpc_server_. -These metrics are labeled with the gRPC service name and method name. -Metrics of interest include contrast_grpc_server_handled_total, which counts -the number of requests by return code, and -contrast_grpc_server_handling_seconds_bucket, which produces a histogram of
-request latency.

-

The gRPC service userapi.UserAPI records metrics for the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively.

-

The meshapi.MeshAPI service records metrics for the method NewMeshCert, which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures_total.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/architecture/secrets.html b/pr-preview/pr-1071/1.1/architecture/secrets.html deleted file mode 100644 index d0bea1b0e0..0000000000 --- a/pr-preview/pr-1071/1.1/architecture/secrets.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Secrets & recovery | Contrast - - - - -
Skip to main content
Version: 1.1

Secrets & recovery

-

When the Coordinator is configured with the initial manifest, it generates a random secret seed. -From this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history. -This derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state.

-

The secret seed is returned to the user on the first call to contrast set, encrypted with the user's public seed share owner key. -If no seed share owner key is provided, a key is generated and stored in the working directory.

-

Persistence

-

The Coordinator runs as a StatefulSet with a dynamically provisioned persistent volume. -This volume stores the manifest history and the associated runtime policies. -The manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads. -However, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users. -Thus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed.

-

Recovery

-

When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests. -It needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures. -This procedure is called recovery and is initiated by the workload owner. -The CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the Recover method. -The Coordinator recovers its key material and verifies the manifest history signature.

-

Workload Secrets

-

The Coordinator provides each workload a secret seed during attestation. This secret can be used by the workload to derive additional secrets for example to -encrypt persistent data. Like the workload certificates it's mounted in the shared Kubernetes volume contrast-secrets in the path <mountpoint>/secrets/workload-secret-seed.

-
warning

The workload owner can decrypt data encrypted with secrets derived from the workload secret. -The workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner. -If the data owner and the workload owner is the same entity, then they can safely use the workload secrets.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/architecture/security-considerations.html b/pr-preview/pr-1071/1.1/architecture/security-considerations.html deleted file mode 100644 index e5075dd262..0000000000 --- a/pr-preview/pr-1071/1.1/architecture/security-considerations.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Security Considerations | Contrast - - - - -
Skip to main content
Version: 1.1

Security Considerations

-

Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits). -However, care must be taken when interacting with the outside of Contrast's confidential environment. -This page presents some tips for writing secure applications and outlines the trust boundaries app developers need to know.

-

General recommendations

-

Authentication

-

The application receives credentials from the Contrast Coordinator during initialization. -This allows to authenticate towards peers and to verify credentials received from peers. -The application should use the certificate bundle to authenticate incoming requests and be wary of unauthenticated requests or requests with a different root of trust (for example the internet PKI).

-

The recommendation to authenticate not only applies to network traffic, but also to volumes, GPUs and other devices. -Generally speaking, all information provided by the world outside the confidential VM should be treated with due scepticism, especially if it's not authenticated. -Common cases where Kubernetes apps interact with external services include DNS, Kubernetes API clients and cloud storage endpoints.

-

Encryption

-

Any external persistence should be encrypted with an authenticated cipher. -This recommendation applies to block devices or filesystems mounted into the container, but also to cloud blob storage or external databases.

-

Contrast security guarantees

-

If an application authenticates with a certificate signed by the Contrast Mesh CA of a given manifest, Contrast provides the following guarantees:

-
    -
  1. The container images used by the app are the images specified in the resource definitions.
  2. -
  3. The command line arguments of containers are exactly the arguments specified in the resource definitions.
  4. -
  5. All environment variables are either specified in resource definitions, in the container image manifest or in a settings file for the Contrast CLI.
  6. -
  7. The containers run in a confidential VM that matches the reference values in the manifest.
  8. -
  9. The containers' root filesystems are mounted in encrypted memory.
  10. -
-

Limitations inherent to policy checking

-

Workload policies serve as workload identities. -From the perspective of the Contrast Coordinator, all workloads that authenticate with the same policy are equal. -Thus, it's not possible to disambiguate, for example, pods spawned from a deployment or to limit the amount of certificates issued per policy.

-

Container image references from Kubernetes resource definitions are taken into account when generating the policy. -A mutable reference may lead to policy failures or unverified image content, depending on the Contrast runtime. -Reliability and security can only be ensured with a full image reference, including digest. -The docker pull documentation explains pinned image references in detail.

-

Policies can only verify what can be inferred at generation time. -Some attributes of Kubernetes pods can't be predicted and thus can't be verified. -Particularly the downward API contains many fields that are dynamic or depend on the host environment, rendering it unsafe for process environment or arguments. -The same goes for ConfigMap and Secret resources, which can also be used to populate container fields. -If the application requires such external information, it should be injected as a mount point and carefully inspected before use.

-

Another type of dynamic content are persistent volumes. -Any volumes mounted to the pod need to be scrutinized, and sensitive data must not be written to unprotected volumes. -Ideally, a volume is mounted as a raw block device and authenticated encryption is added within the confidential container.

-

Logs

-

By default, container logs are visible to the host. -Sensitive information shouldn't be logged.

-

As of right now, hiding logs isn't natively supported. -If ReadStreamRequest is denied in the policy, the Kata Agent stops reading the logs. -This causes the pipes used for standard out and standard error to fill up and potentially deadlock the container. -If absolutely required, standard out and standard error should be manually redirected to /dev/null inside the container.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/basics/confidential-containers.html b/pr-preview/pr-1071/1.1/basics/confidential-containers.html deleted file mode 100644 index 63950e0949..0000000000 --- a/pr-preview/pr-1071/1.1/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Skip to main content
Version: 1.1

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/basics/features.html b/pr-preview/pr-1071/1.1/basics/features.html deleted file mode 100644 index 035eb6c3c3..0000000000 --- a/pr-preview/pr-1071/1.1/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Skip to main content
Version: 1.1

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/basics/security-benefits.html b/pr-preview/pr-1071/1.1/basics/security-benefits.html deleted file mode 100644 index dc70b341f8..0000000000 --- a/pr-preview/pr-1071/1.1/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Skip to main content
Version: 1.1

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/components/overview.html b/pr-preview/pr-1071/1.1/components/overview.html deleted file mode 100644 index 020badf01a..0000000000 --- a/pr-preview/pr-1071/1.1/components/overview.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Skip to main content
Version: 1.1

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/components/policies.html b/pr-preview/pr-1071/1.1/components/policies.html deleted file mode 100644 index 39b4afb942..0000000000 --- a/pr-preview/pr-1071/1.1/components/policies.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Skip to main content
Version: 1.1

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA or TDX MRCONFIGID for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA or MRCONFIGID, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA/MRCONFIGID.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA/MRCONFIGID.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA/MRCONFIGID field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

-

Platform Differences

-

Contrast uses different rules and data sections for different platforms. -This results in different policy hashes for different platforms.

-

The generate command automatically derives the correct set of rules and data sections from the reference-values flag.

-

The verify, set, and recover commands need to know the coordinator's expected policy hash to verify its identity. -By default these commands assume that the coordinator is using the policy for the AKS-CLH-SNP platform. -If the coordinator is running on a different platform, the correct policy hash can be looked up in the coordinator-policy.hash file bundled with the Contrast release. -The coordinator policy hash can be overwritten using the --coordinator-policy-hash flag.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/components/runtime.html b/pr-preview/pr-1071/1.1/components/runtime.html deleted file mode 100644 index 8f75a5a8f5..0000000000 --- a/pr-preview/pr-1071/1.1/components/runtime.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Skip to main content
Version: 1.1

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled/TDX-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

Virtual machine manager (VMM)

-

The containerd shim uses a virtual machine monitor to create a confidential virtual machine for every pod. -On AKS, Contrast uses cloud-hypervisor. -On bare metal, Contrast uses QEMU. -The appropriate files are installed on every node by the node-installer.

-

Snapshotters

-

Contrast uses containerd snapshotters to provide container images to the pod-VM. -Each snapshotter consists of a host component that pulls container images and a guest component used to mount/pull container images.

-

On AKS, Contrast uses the tardev snapshotter to provide container images as block devices to the pod-VM. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

On bare metal, Contrast uses the nydus snapshotter to store metadata about the images. This metadata is communicated to the guest, so that it can pull the images itself.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor or QEMU as the virtual machine manager (VMM)
  • -
  • Install an IGVM file or separate firmware and kernel files for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/components/service-mesh.html b/pr-preview/pr-1071/1.1/components/service-mesh.html deleted file mode 100644 index 4b67f36c89..0000000000 --- a/pr-preview/pr-1071/1.1/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Skip to main content
Version: 1.1

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables CONTRAST_INGRESS_PROXY_CONFIG, -CONTRAST_EGRESS_PROXY_CONFIG and CONTRAST_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: CONTRAST_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v1.1.1@sha256:5906c67f89afa7b79bc5e68df523f7f309adf2f66583e5f702ebbcf5545ef0d9"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-secrets
mountPath: /contrast
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/deployment.html b/pr-preview/pr-1071/1.1/deployment.html deleted file mode 100644 index 482efc57e7..0000000000 --- a/pr-preview/pr-1071/1.1/deployment.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Skip to main content
Version: 1.1

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set up a cluster on AKS.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-aks-clh-snp.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

Security review

-

Contrast ensures integrity and confidentiality of the applications, but interactions with untrusted systems require the developers' attention. -Review the security considerations and the certificates section for writing secure Contrast application.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-secrets shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate --reference-values aks-clh-snp resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --reference-values aks-clh-snp --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-secrets volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:v1.1.1@sha256:d89d4f5113c8869088ff3a28e02802d7b72304d4bbb50fb664f1c6cba7fcb722"
name: contrast-initializer
volumeMounts:
- mountPath: /contrast
name: contrast-secrets
volumes:
- emptyDir: {}
name: contrast-secrets
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

This will use the reference values from the manifest file to attest the Coordinator. -After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the -service mesh root certificate and the history of manifests into the verify/ directory. In addition, the policies -referenced in the active manifest are also written to the directory. The verification will fail if the active -manifest at the Coordinator doesn't match the manifest passed to the CLI.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Recover the Coordinator

-

If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material. -For demonstration purposes, you can simulate this scenario by deleting the Coordinator pod.

-
kubectl delete pod -l app.kubernetes.io/name=coordinator
-

Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet. -You can confirm this by running verify again, or you can restart a workload pod, which should stay in the initialization phase. -However, the secret seed in your working directory is sufficient to recover the coordinator.

-
contrast recover -c "${coordinator}:1313"
-

Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state. -You can now verify the Coordinator again, which should return the same manifest you set before.

-
warning

The recovery process invalidates the mesh CA certificate: -existing workloads won't be able to communicate with workloads newly spawned. -All workloads should be restarted after the recovery succeeded.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/examples/emojivoto.html b/pr-preview/pr-1071/1.1/examples/emojivoto.html deleted file mode 100644 index 15418eca4a..0000000000 --- a/pr-preview/pr-1071/1.1/examples/emojivoto.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Skip to main content
Version: 1.1

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voter's perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

Emojivoto can be seen as a lighthearted example of an app dealing with sensitive data. -Contrast protects emojivoto in two ways. First, it shields emojivoto as a whole from the infrastructure, for example, Azure. -Second, it can be configured to also prevent data access even from the administrator of the app. In the case of emojivoto, this gives assurance to users that their votes remain secret.

-

emojivoto components topology

-

Prerequisites

-
    -
  • Installed Contrast CLI
  • -
  • A running Kubernetes cluster with support for confidential containers, either on AKS or on bare metal.
  • -
-

Steps to deploy emojivoto with Contrast

-

Download the deployment files

-

The emojivoto deployment files are part of the Contrast release. You can download them by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.1.1/emojivoto-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass, -which needs to be installed to the cluster initially. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-aks-clh-snp.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc-<platform>-<runtime-hash> -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Verifying the deployment as a user

-

In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before casting a vote. -With Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment. -Contrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future. -Successful verification of the Coordinator means that the user can be sure that the given manifest will be enforced.

-

Verifying the Coordinator

-

A user can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Auditing the manifest history and artifacts

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Connecting securely to the application

-

After ensuring the configuration of the Coordinator fits the expectation, the user can securely connect -to the application using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Updating the certificate SAN and the manifest (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configuring the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {
"SANs": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
"WorkloadSecretID": "web"
},
-

Updating the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/features-limitations.html b/pr-preview/pr-1071/1.1/features-limitations.html deleted file mode 100644 index 533e0fe106..0000000000 --- a/pr-preview/pr-1071/1.1/features-limitations.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Skip to main content
Version: 1.1

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes is available for AMD SEV-SNP and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Contrast only supports volumes with volumeMode: Block. These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
-

Automatic recovery and high availability

-

The Contrast Coordinator is a singleton and can't be scaled to more than one instance. -When this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually. -In a future release, we plan to support distributed Coordinator instances that can recover automatically.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/getting-started/bare-metal.html b/pr-preview/pr-1071/1.1/getting-started/bare-metal.html deleted file mode 100644 index c8f48a37ec..0000000000 --- a/pr-preview/pr-1071/1.1/getting-started/bare-metal.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -Prepare a bare-metal instance | Contrast - - - - -
Skip to main content
Version: 1.1

Prepare a bare-metal instance

-

Hardware and firmware setup

-
    -
  1. Update your BIOS to a version that supports AMD SEV-SNP. Updating to the latest available version is recommended as newer versions will likely contain security patches for AMD SEV-SNP.
  2. -
  3. Enter BIOS setup to enable SMEE, IOMMU, RMP coverage, and SEV-SNP. Set the SEV-ES ASID Space Limit to a non-zero number (higher is better).
  4. -
  5. Download the latest firmware version for your processor from AMD, unpack it, and place it in /lib/firmware/amd.
  6. -

Consult AMD's Using SEV with AMD EPYC Processors user guide for more information.

-

Kernel Setup

-

Install a kernel with version 6.11 or greater. If you're following this guide before 6.11 has been released, use 6.11-rc3. Don't use 6.11-rc4 - 6.11-rc6 as they contain a regression. 6.11-rc7+ might work.

-

Increase the user.max_inotify_instances sysctl limit by adding user.max_inotify_instances=8192 to /etc/sysctl.d/99-sysctl.conf and running sysctl --system.

-

K3s Setup

-
    -
  1. Follow the K3s setup instructions to create a cluster.
  2. -
  3. Install a block storage provider such as Longhorn and mark it as the default storage class.
  4. -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/getting-started/cluster-setup.html b/pr-preview/pr-1071/1.1/getting-started/cluster-setup.html deleted file mode 100644 index 2834cbc20d..0000000000 --- a/pr-preview/pr-1071/1.1/getting-started/cluster-setup.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Skip to main content
Version: 1.1

Create a cluster

-

Prerequisites

-
    -
  • Install version 2.44.1 or newer of the Azure CLI. Note that your package manager will likely install an outdated version.
  • -
  • Install a recent version of kubectl.
  • -
-

Prepare using the AKS preview

-

First, log in to your Azure subscription:

-
az login
-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, create a CoCo enabled AKS cluster with:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.30 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation \
--node-count 1 \
--generate-ssh-keys
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show a single node:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
-

🥳 Congratulations. You're now ready to set up your first application with Contrast. Follow this example to learn how.

-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/getting-started/install.html b/pr-preview/pr-1071/1.1/getting-started/install.html deleted file mode 100644 index d68a0e43fa..0000000000 --- a/pr-preview/pr-1071/1.1/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Skip to main content
Version: 1.1

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v1.1.1/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/1.1/troubleshooting.html b/pr-preview/pr-1071/1.1/troubleshooting.html deleted file mode 100644 index 1be75873d2..0000000000 --- a/pr-preview/pr-1071/1.1/troubleshooting.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - -Troubleshooting | Contrast - - - - -
Skip to main content
Version: 1.1

Troubleshooting

-

This section contains information on how to debug your Contrast deployment.

-

Logging

-

Collecting logs can be a good first step to identify problems in your -deployment. Both the CLI and the Contrast Coordinator as well as the Initializer -can be configured to emit additional logs.

-

CLI

-

The CLI logs can be configured with the --log-level command-line flag, which -can be set to either debug, info, warn or error. The default is info. -Setting this to debug can get more fine-grained information as to where the -problem lies.

-

Coordinator and Initializer

-

The logs from the Coordinator and the Initializer can be configured via the -environment variables CONTRAST_LOG_LEVEL, CONTRAST_LOG_FORMAT and -CONTRAST_LOG_SUBSYSTEMS.

-
    -
  • CONTRAST_LOG_LEVEL can be set to one of either debug, info, warn, or -error, similar to the CLI (defaults to info).
  • -
  • CONTRAST_LOG_FORMAT can be set to text or json, determining the output -format (defaults to text).
  • -
  • CONTRAST_LOG_SUBSYSTEMS is a comma-seperated list of subsystems that should -be enabled for logging, which are disabled by default. Subsystems include: -kds-getter, issuer and validator. -To enable all subsystems, use * as the value for this environment variable. -Warnings and error messages from subsystems get printed regardless of whether -the subsystem is listed in the CONTRAST_LOG_SUBSYSTEMS environment variable.
  • -
-

To configure debug logging with all subsystems for your Coordinator, add the -following variables to your container definition.

-
spec: # v1.PodSpec
containers:
image: "ghcr.io/edgelesssys/contrast/coordinator:v1.1.1@sha256:272bf0910ad9ce8f0f0bd6865487dd062e53361cd2e3852c7d864a2018d2a461"
name: coordinator
env:
- name: CONTRAST_LOG_LEVEL
value: debug
- name: CONTRAST_LOG_SUBSYSTEMS
value: "*"
# ...
-
info

While the Contrast Coordinator has a policy that allows certain configurations, -the Initializer and service mesh don't. When changing environment variables of other -parts than the Coordinator, ensure to rerun contrast generate to update the policy.

-

To access the logs generated by the Coordinator, you can use kubectl with the -following command:

-
kubectl logs <coordinator-pod-name>
-

Pod fails to start

-

If the Coordinator or a workload pod fails to even start, it can be helpful to -look at the events of the pod during the startup process using the describe -command.

-
kubectl -n <namespace> events --for pod/<coordinator-pod-name>
-

Example output:

-
LAST SEEN  TYPE     REASON  OBJECT             MESSAGE
32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...
-

A common error, as in this example, is that the container creation was blocked by the -policy. Potential reasons are a modification of the deployment YAML without updating -the policies afterward, or a version mismatch between Contrast components.

-

Regenerating the policies

-

To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated -policies, rerun

-
contrast generate
-

on your deployment. If any of the policy annotations change, re-deploy with the updated policies.

-

Pin container images

-

When generating the policies, Contrast will download the images specified in your deployment -YAML and include their cryptographic identity. If the image tag is moved to another -container image after the policy has been generated, the image downloaded at deploy time -will differ from the one at generation time, and the policy enforcement won't allow the -container to be started in the pod VM.

-

To ensure the correct image is always used, pin the container image to a fixed sha256:

-
image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac
-

This way, the same image will still be pulled when the container tag (22.04) is moved -to another image.

-

Validate Contrast components match

-

A version mismatch between Contrast components can cause policy validation or attestation -to fail. Each Contrast runtime is identifiable based on its (shortened) measurement value -used to name the runtime class version.

-

First, analyze which runtime class is currently installed in your cluster by running

-
kubectl get runtimeclasses
-

This should give you output similar to the following one.

-
NAME                                           HANDLER                                        AGE
contrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h
kata-cc-isolation kata-cc 45d
-

The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided -by the AKS CoCo preview, which isn't used by Contrast).

-

Next, check if the pod that won't start has the correct runtime class configured, and the -Coordinator uses the exact same runtime:

-
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>
-

The output should list the runtime class the pod is using:

-
contrast-cc-aks-clh-snp-7173acb5
-

Version information about the currently used CLI can be obtained via the version flag:

-
contrast --version
-
contrast version v0.X.0

runtime handler: contrast-cc-aks-clh-snp-7173acb5
launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35
genpolicy version: 3.2.0.azl1.genpolicy0
image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...
ghcr.io/edgelesssys/contrast/initializer@sha256:...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/404.html b/pr-preview/pr-1071/404.html deleted file mode 100644 index 4af2866954..0000000000 --- a/pr-preview/pr-1071/404.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Contrast - - - - -
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/about/telemetry.html b/pr-preview/pr-1071/about/telemetry.html deleted file mode 100644 index d3fac3f41a..0000000000 --- a/pr-preview/pr-1071/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Skip to main content
Version: 1.2

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/architecture/attestation.html b/pr-preview/pr-1071/architecture/attestation.html deleted file mode 100644 index 4e841b508f..0000000000 --- a/pr-preview/pr-1071/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Skip to main content
Version: 1.2

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -The hypervisor adds the hash of the policy to the attestation report via the HOSTDATA (on AMD SEV-SNP) or MRCONFIGID (Intel TDX) fields. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA/MRCONFIGID field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP or Intel TDX to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/architecture/certificates.html b/pr-preview/pr-1071/architecture/certificates.html deleted file mode 100644 index 4aa63cfed8..0000000000 --- a/pr-preview/pr-1071/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Skip to main content
Version: 1.2

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/architecture/observability.html b/pr-preview/pr-1071/architecture/observability.html deleted file mode 100644 index 2d3dd75e07..0000000000 --- a/pr-preview/pr-1071/architecture/observability.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Skip to main content
Version: 1.2

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator exports gRPC metrics under the prefix contrast_grpc_server_. -These metrics are labeled with the gRPC service name and method name. -Metrics of interest include contrast_grpc_server_handled_total, which counts -the number of requests by return code, and -contrast_grpc_server_handling_seconds_bucket, which produces a histogram of
-request latency.

-

The gRPC service userapi.UserAPI records metrics for the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively.

-

The meshapi.MeshAPI service records metrics for the method NewMeshCert, which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures_total.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/architecture/secrets.html b/pr-preview/pr-1071/architecture/secrets.html deleted file mode 100644 index 1bfac427cf..0000000000 --- a/pr-preview/pr-1071/architecture/secrets.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - -Secrets & recovery | Contrast - - - - -
Skip to main content
Version: 1.2

Secrets & recovery

-

When the Coordinator is configured with the initial manifest, it generates a random secret seed. -From this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history. -This derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state.

-

The secret seed is returned to the user on the first call to contrast set, encrypted with the user's public seed share owner key. -If no seed share owner key is provided, a key is generated and stored in the working directory.

-

Persistence

-

The Coordinator runs as a StatefulSet with a dynamically provisioned persistent volume. -This volume stores the manifest history and the associated runtime policies. -The manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads. -However, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users. -Thus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed.

-

Recovery

-

When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests. -It needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures. -This procedure is called recovery and is initiated by the workload owner. -The CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the Recover method. -The Coordinator recovers its key material and verifies the manifest history signature.

-

Workload Secrets

-

The Coordinator provides each workload a secret seed during attestation. -This secret can be used by the workload to derive additional secrets for example to encrypt persistent data. -Like the workload certificates, it's written to the secrets/workload-secret-seed path under the shared Kubernetes volume contrast-secrets.

-
warning

The workload owner can decrypt data encrypted with secrets derived from the workload secret. -The workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner. -If the data owner and the workload owner is the same entity, then they can safely use the workload secrets.

-

Secure persistence

-

Remember that persistent volumes from the cloud provider are untrusted. -Using the workload secret, applications can set up trusted storage on top of untrusted block devices. -The following, slightly abbreviated resource outlines how this could be realized:

-
warning

This configuration snippet is intended to be educational and needs to be refined and adapted to your production environment. -Using it as-is may result in data corruption or data loss.

-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: volume-tester
spec:
template:
spec:
containers:
- name: main
image: my.registry/my-image@sha256:0123...
command:
- /bin/sh
- -ec
- | # <-- Custom script that mounts the encrypted disk and then calls the original application.
device=/dev/csi0
if ! cryptsetup isLuks $device; then
cryptsetup luksFormat $device /contrast/secrets/workload-secret-seed
cryptsetup open $device state -d /contrast/secrets/workload-secret-seed
mkfs.ext4 /dev/mapper/state
cryptsetup close state
fi
cryptsetup open $device state -d /contrast/secrets/workload-secret-seed
/path/to/original/app
name: volume-tester
volumeDevices:
- name: state
devicePath: /dev/csi0
securityContext:
privileged: true # <-- This is necessary for mounting devices.
runtimeClassName: contrast-cc
volumeClaimTemplates:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: state
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
volumeMode: Block # <-- The requested volume needs to be a raw block device.
-
note

This example assumes that you can modify the container image to include a shell and the cryptsetup utility. -Alternatively, you can set up a secure mount from a sidecar container inside an emptyDir mount shared with the main container. -The Contrast end-to-end tests include an example of this type of mount.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/architecture/security-considerations.html b/pr-preview/pr-1071/architecture/security-considerations.html deleted file mode 100644 index d4adb509e3..0000000000 --- a/pr-preview/pr-1071/architecture/security-considerations.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Security Considerations | Contrast - - - - -
Skip to main content
Version: 1.2

Security Considerations

-

Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits). -However, care must be taken when interacting with the outside of Contrast's confidential environment. -This page presents some tips for writing secure applications and outlines the trust boundaries app developers need to know.

-

General recommendations

-

Authentication

-

The application receives credentials from the Contrast Coordinator during initialization. -This allows to authenticate towards peers and to verify credentials received from peers. -The application should use the certificate bundle to authenticate incoming requests and be wary of unauthenticated requests or requests with a different root of trust (for example the internet PKI).

-

The recommendation to authenticate not only applies to network traffic, but also to volumes, GPUs and other devices. -Generally speaking, all information provided by the world outside the confidential VM should be treated with due scepticism, especially if it's not authenticated. -Common cases where Kubernetes apps interact with external services include DNS, Kubernetes API clients and cloud storage endpoints.

-

Encryption

-

Any external persistence should be encrypted with an authenticated cipher. -This recommendation applies to block devices or filesystems mounted into the container, but also to cloud blob storage or external databases.

-

Contrast security guarantees

-

If an application authenticates with a certificate signed by the Contrast Mesh CA of a given manifest, Contrast provides the following guarantees:

-
    -
  1. The container images used by the app are the images specified in the resource definitions.
  2. -
  3. The command line arguments of containers are exactly the arguments specified in the resource definitions.
  4. -
  5. All environment variables are either specified in resource definitions, in the container image manifest or in a settings file for the Contrast CLI.
  6. -
  7. The containers run in a confidential VM that matches the reference values in the manifest.
  8. -
  9. The containers' root filesystems are mounted in encrypted memory.
  10. -
-

Limitations inherent to policy checking

-

Workload policies serve as workload identities. -From the perspective of the Contrast Coordinator, all workloads that authenticate with the same policy are equal. -Thus, it's not possible to disambiguate, for example, pods spawned from a deployment or to limit the amount of certificates issued per policy.

-

Container image references from Kubernetes resource definitions are taken into account when generating the policy. -A mutable reference may lead to policy failures or unverified image content, depending on the Contrast runtime. -Reliability and security can only be ensured with a full image reference, including digest. -The docker pull documentation explains pinned image references in detail.

-

Policies can only verify what can be inferred at generation time. -Some attributes of Kubernetes pods can't be predicted and thus can't be verified. -Particularly the downward API contains many fields that are dynamic or depend on the host environment, rendering it unsafe for process environment or arguments. -The same goes for ConfigMap and Secret resources, which can also be used to populate container fields. -If the application requires such external information, it should be injected as a mount point and carefully inspected before use.

-

Another type of dynamic content are persistent volumes. -Any volumes mounted to the pod need to be scrutinized, and sensitive data must not be written to unprotected volumes. -Ideally, a volume is mounted as a raw block device and authenticated encryption is added within the confidential container.

-

Logs

-

By default, container logs are visible to the host. -Sensitive information shouldn't be logged.

-

As of right now, hiding logs isn't natively supported. -If ReadStreamRequest is denied in the policy, the Kata Agent stops reading the logs. -This causes the pipes used for standard out and standard error to fill up and potentially deadlock the container. -If absolutely required, standard out and standard error should be manually redirected to /dev/null inside the container.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/css/styles.e9486642.css b/pr-preview/pr-1071/assets/css/styles.e9486642.css deleted file mode 100644 index f8f10faf4c..0000000000 --- a/pr-preview/pr-1071/assets/css/styles.e9486642.css +++ /dev/null @@ -1 +0,0 @@ -@import url(https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap);.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}:root,body.dark,body[data-theme=dark]{--aa-icon-color-rgb:119,119,163;--aa-scrollbar-thumb-background-color-rgb:var(--aa-background-color-rgb)}.aa-List,.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#8b04dd;--ifm-color-primary-dark:#58089e;--ifm-color-primary-darker:#330663;--ifm-color-primary-darkest:#1c033c;--ifm-color-primary-light:#8b04dd;--ifm-color-primary-lighter:#b873f4;--ifm-color-primary-lightest:#e3d2ff;--ifm-font-family-base:"Inter",sans-serif;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-announcement-bar-height:auto;--aa-search-input-height:44px;--aa-input-icon-size:20px;--aa-base-unit:16;--aa-spacing-factor:1;--aa-spacing:calc(var(--aa-base-unit)*var(--aa-spacing-factor)*1px);--aa-spacing-half:calc(var(--aa-spacing)/2);--aa-panel-max-height:650px;--aa-base-z-index:9999;--aa-font-size:calc(var(--aa-base-unit)*1px);--aa-font-family:inherit;--aa-font-weight-medium:500;--aa-font-weight-semibold:600;--aa-font-weight-bold:700;--aa-icon-size:20px;--aa-icon-stroke-width:1.6;--aa-icon-color-alpha:1;--aa-action-icon-size:20px;--aa-text-color-rgb:38,38,39;--aa-text-color-alpha:1;--aa-primary-color-rgb:62,52,211;--aa-primary-color-alpha:0.2;--aa-muted-color-rgb:128,126,163;--aa-muted-color-alpha:0.6;--aa-panel-border-color-rgb:128,126,163;--aa-panel-border-color-alpha:0.3;--aa-input-border-color-rgb:128,126,163;--aa-input-border-color-alpha:0.8;--aa-background-color-rgb:255,255,255;--aa-background-color-alpha:1;--aa-input-background-color-rgb:255,255,255;--aa-input-background-color-alpha:1;--aa-selected-color-rgb:179,173,214;--aa-selected-color-alpha:0.205;--aa-description-highlight-background-color-rgb:245,223,77;--aa-description-highlight-background-color-alpha:0.5;--aa-detached-media-query:(max-width:680px);--aa-detached-modal-media-query:(min-width:680px);--aa-detached-modal-max-width:680px;--aa-detached-modal-max-height:500px;--aa-overlay-color-rgb:115,114,129;--aa-overlay-color-alpha:0.4;--aa-panel-shadow:0 0 0 1px #23263b1a,0 6px 16px -4px #23263b26;--aa-scrollbar-width:13px;--aa-scrollbar-track-background-color-rgb:234,234,234;--aa-scrollbar-track-background-color-alpha:1;--aa-scrollbar-thumb-background-color-alpha:1;--aa-search-input-height:36px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*,.aa-Autocomplete *,.aa-DetachedFormContainer *,.aa-Panel *{box-sizing:border-box}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.list_eTzJ article:last-child,.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}.container_lyt7,.container_lyt7>svg,img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){-webkit-text-decoration:none;text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item,blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);-webkit-text-decoration:none;text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.aa-ItemLink,.aa-SourceFooterSeeAll,.dropdown__link--active,.dropdown__link:hover,.menu__link:hover,.navbar__brand:hover,.navbar__link--active,.navbar__link:hover,.pagination-nav__link:hover,.pagination__link:hover,.tag_zVej:hover{-webkit-text-decoration:none;text-decoration:none}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);-webkit-text-decoration:none;text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color)}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.admonitionContent_BuS1>:last-child,.cardContainer_fWXF :last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;top:0;visibility:hidden;left:0}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color)}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color)}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color)}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:1rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover)}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#90ff99;--ifm-color-primary-dark:#5bc95b;--ifm-color-primary-darker:#238723;--ifm-color-primary-darkest:#124c12;--ifm-color-primary-light:#90ff99;--ifm-color-primary-lighter:#d2ffd3;--ifm-color-primary-lightest:#d2ffd3;--docusaurus-highlighted-code-line-bg:#0000004d}.header-github-link:hover{opacity:.6}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:24px;width:24px}html[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.tabs-container{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);padding:var(--ifm-global-spacing)}.tabs{border-bottom:1px solid var(--ifm-color-emphasis-300)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white);background-color:#000}.asciinema-theme-edgeless .asciinema-terminal{background-color:#000;border-color:#000;color:#fff}.asciinema-theme-edgeless .fg-bg{color:#000}.asciinema-theme-edgeless .bg-fg{background-color:#fff}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.lastUpdated_JAkA{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}.docSidebarContainer_YfHR,.sidebarLogo_isFc,.themedComponent_mlkZ{display:none}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.iconExternalLink_nPIU{margin-left:.3rem}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.cardContainer_fWXF{--ifm-link-color:var(--ifm-color-emphasis-800);--ifm-link-hover-color:var(--ifm-color-emphasis-700);--ifm-link-hover-decoration:none;border:1px solid var(--ifm-color-emphasis-200);box-shadow:0 1.5px 3px 0 #00000026;transition:all var(--ifm-transition-fast) ease;transition-property:border,box-shadow}.cardContainer_fWXF:hover{border-color:var(--ifm-color-primary);box-shadow:0 3px 6px 0 #0003}.cardTitle_rnsV{font-size:1.2rem}.cardDescription_PWke{font-size:.8rem}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;-webkit-text-decoration:underline;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.aa-ClearButton[hidden],.aa-ItemContent:empty,.aa-LoadingIndicator[hidden],.aa-Source:empty,.aa-SourceHeader:empty,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.aa-Form,.toggleButton_gllP{align-items:center;width:100%;display:flex}.toggleButton_gllP{border-radius:50%;height:100%;justify-content:center;transition:background var(--ifm-transition-fast)}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}.dropdownNavbarItemMobile_S0Fm{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}body.dark,body[data-theme=dark]{--aa-text-color-rgb:183,192,199;--aa-primary-color-rgb:146,138,255;--aa-muted-color-rgb:146,138,255;--aa-input-background-color-rgb:0,3,9;--aa-background-color-rgb:21,24,42;--aa-selected-color-rgb:146,138,255;--aa-selected-color-alpha:0.25;--aa-description-highlight-background-color-rgb:0 255 255;--aa-description-highlight-background-color-alpha:0.25;--aa-panel-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--aa-scrollbar-track-background-color-rgb:44,46,64;--aa-muted-color-alpha:1}.aa-Autocomplete,.aa-DetachedFormContainer,.aa-Panel{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-family:inherit;font-family:var(--aa-font-family);font-size:16px;font-size:var(--aa-font-size);font-weight:400;line-height:1em;margin:0;padding:0;text-align:left}.aa-Form{background-color:#fff;background-color:rgba(var(--aa-input-background-color-rgb),var(--aa-input-background-color-alpha));border:1px solid #807ea3cc;border:1px solid rgba(var(--aa-input-border-color-rgb),var(--aa-input-border-color-alpha));border-radius:3px;line-height:1em;margin:0;position:relative}.aa-ClearButton,.aa-Input,.aa-SubmitButton{border:0;background:none}.aa-Form:focus-within{border-color:#3e34d3;border-color:rgba(var(--aa-primary-color-rgb),1);box-shadow:0 0 0 2px #3e34d333,inset 0 0 0 2px #3e34d333;box-shadow:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px,inset rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px;outline:currentColor}.aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;height:44px;height:var(--aa-search-input-height);order:1}.aa-Label,.aa-LoadingIndicator{cursor:auto;flex-shrink:0;height:100%;padding:0;text-align:left}.aa-Label svg,.aa-LoadingIndicator svg{color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1);height:auto;max-height:20px;max-height:var(--aa-input-icon-size);stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);width:20px;width:var(--aa-input-icon-size)}.aa-LoadingIndicator,.aa-SubmitButton{height:100%;padding-left:11px;padding-left:calc(var(--aa-spacing)*.75 - 1px);padding-right:8px;padding-right:var(--aa-spacing-half);width:47px;width:calc(var(--aa-spacing)*1.75 + var(--aa-icon-size) - 1px)}.aa-SubmitButton{appearance:none;margin:0}.aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-InputWrapper{order:3;position:relative;width:100%}.aa-Input{appearance:none;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font:inherit;height:44px;height:var(--aa-search-input-height);padding:0;width:100%}.aa-Input::placeholder{color:#807ea399;color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));opacity:1}.aa-Input:focus{border-color:none;box-shadow:none;outline:0}.aa-Input::-webkit-search-cancel-button,.aa-Input::-webkit-search-decoration,.aa-Input::-webkit-search-results-button,.aa-Input::-webkit-search-results-decoration{appearance:none}.aa-InputWrapperSuffix{align-items:center;display:flex;height:44px;height:var(--aa-search-input-height);order:4}.aa-ClearButton{align-items:center;color:#807ea399;color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));cursor:pointer;display:flex;height:100%;margin:0;padding:0 12.83328px;padding:0 calc(var(--aa-spacing)*.83333 - .5px)}.aa-Item,.aa-ItemIcon{align-items:center;border-radius:3px}.aa-ClearButton:focus,.aa-ClearButton:hover,.aa-ItemActionButton:focus svg,.aa-ItemActionButton:hover svg{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha))}.aa-ClearButton svg{stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);width:20px;width:var(--aa-icon-size)}.aa-Panel{background-color:#fff;background-color:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));border-radius:4px;border-radius:calc(var(--aa-spacing)/4);box-shadow:0 0 0 1px #23263b1a,0 6px 16px -4px #23263b26;box-shadow:var(--aa-panel-shadow);margin:8px 0 0;overflow:hidden;position:absolute;transition:opacity .2s ease-in,filter .2s ease-in}.aa-Panel button{appearance:none;background:none;border:0;margin:0;padding:0}.aa-PanelLayout{height:100%;margin:0;max-height:650px;max-height:var(--aa-panel-max-height);overflow-y:auto;padding:0;position:relative;text-align:left}.aa-PanelLayoutColumns--twoGolden{display:grid;grid-template-columns:39.2% auto;overflow:hidden;padding:0}.aa-PanelLayoutColumns--two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow:hidden;padding:0}.aa-PanelLayoutColumns--three{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));overflow:hidden;padding:0}.aa-Panel--stalled .aa-Source{filter:grayscale(1);opacity:.8}.aa-Panel--scrollable{margin:0;max-height:650px;max-height:var(--aa-panel-max-height);overflow-x:hidden;overflow-y:auto;padding:8px;padding:var(--aa-spacing-half);scrollbar-color:#fff #eaeaea;scrollbar-color:rgba(var(--aa-scrollbar-thumb-background-color-rgb),var(--aa-scrollbar-thumb-background-color-alpha)) rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha));scrollbar-width:thin}.aa-Panel--scrollable::-webkit-scrollbar{width:13px;width:var(--aa-scrollbar-width)}.aa-Panel--scrollable::-webkit-scrollbar-track{background-color:#eaeaea;background-color:rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha))}.aa-Panel--scrollable::-webkit-scrollbar-thumb{background-color:#fff;background-color:rgba(var(--aa-scrollbar-thumb-background-color-rgb),var(--aa-scrollbar-thumb-background-color-alpha));border:3px solid #eaeaea;border:3px solid rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha));border-radius:9999px;border-right-width:2px}.aa-Source{margin:0;padding:0;position:relative;width:100%}.aa-SourceNoResults{font-size:1em;margin:0;padding:16px;padding:var(--aa-spacing)}.aa-List{margin:0}.aa-List,.aa-SourceHeader{padding:0;position:relative}.aa-SourceHeader{margin:8px .5em 8px 0;margin:var(--aa-spacing-half) .5em var(--aa-spacing-half) 0}.aa-SourceHeaderTitle{background:#fff;background:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1);display:inline-block;font-size:.8em;font-weight:600;font-weight:var(--aa-font-weight-semibold);margin:0;padding:0 8px 0 0;padding:0 var(--aa-spacing-half) 0 0;position:relative;z-index:9999;z-index:var(--aa-base-z-index)}.aa-SourceHeaderLine{border-bottom:1px solid #3e34d3;border-bottom:1px solid rgba(var(--aa-primary-color-rgb),1);display:block;height:2px;left:0;margin:0;opacity:.3;padding:0;position:absolute;right:0;top:8px;top:var(--aa-spacing-half);z-index:9998;z-index:calc(var(--aa-base-z-index) - 1)}.aa-SourceFooterSeeAll{background:linear-gradient(180deg,#fff,#807ea324);background:linear-gradient(180deg,rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha)),#807ea324);border:1px solid #807ea399;border:1px solid rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));border-radius:5px;box-shadow:inset 0 0 2px #fff,0 2px 2px -1px #4c455826;color:inherit;font-size:.95em;font-weight:500;font-weight:var(--aa-font-weight-medium);padding:.475em 1em .6em}.aa-SourceFooterSeeAll:focus,.aa-SourceFooterSeeAll:hover{border:1px solid #3e34d3;border:1px solid rgba(var(--aa-primary-color-rgb),1);color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1)}.aa-Item{cursor:pointer;display:grid;min-height:40px;min-height:calc(var(--aa-spacing)*2.5);padding:4px;padding:calc(var(--aa-spacing-half)/2)}.aa-Item[aria-selected=true]{background-color:rgba(179,173,214,.205);background-color:rgba(var(--aa-selected-color-rgb),var(--aa-selected-color-alpha))}.aa-Item[aria-selected=true] .aa-ActiveOnly,.aa-Item[aria-selected=true] .aa-ItemActionButton{visibility:visible}.aa-ItemIcon{background:#fff;background:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));box-shadow:inset 0 0 0 1px #807ea34d;box-shadow:inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha));color:#7777a3;color:rgba(var(--aa-icon-color-rgb),var(--aa-icon-color-alpha));display:flex;flex-shrink:0;font-size:.7em;height:28px;height:calc(var(--aa-icon-size) + var(--aa-spacing-half));justify-content:center;overflow:hidden;stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);text-align:center;width:28px;width:calc(var(--aa-icon-size) + var(--aa-spacing-half))}.aa-ItemIcon img{height:auto;max-height:20px;max-height:calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px);max-width:20px;max-width:calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px);width:auto}.aa-ItemIcon svg{height:20px;height:var(--aa-icon-size);width:20px;width:var(--aa-icon-size)}.aa-ItemIcon--alignTop{align-self:flex-start}.aa-ItemIcon--noBorder{background:none;box-shadow:none}.aa-ItemIcon--picture{height:96px;width:96px}.aa-ItemIcon--picture img{max-height:100%;max-width:100%;padding:8px;padding:var(--aa-spacing-half)}.aa-ItemContent{align-items:center;cursor:pointer;display:grid;gap:8px;grid-gap:8px;grid-gap:var(--aa-spacing-half);gap:var(--aa-spacing-half);grid-auto-flow:column;line-height:1.25em;overflow:hidden}.aa-ItemContent mark{background:none;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-style:normal;font-weight:700;font-weight:var(--aa-font-weight-bold)}.aa-ItemContent--dual{display:flex;flex-direction:column;justify-content:space-between;text-align:left}.aa-ItemContent--dual .aa-ItemContentSubtitle,.aa-ItemContent--dual .aa-ItemContentTitle{display:block}.aa-ItemContent--indented{padding-left:36px;padding-left:calc(var(--aa-icon-size) + var(--aa-spacing))}.aa-ItemContentBody{display:grid;gap:4px;grid-gap:4px;grid-gap:calc(var(--aa-spacing-half)/2);gap:calc(var(--aa-spacing-half)/2)}.aa-ItemContentTitle{display:inline-block;margin:0 .5em 0 0;max-width:100%;overflow:hidden;padding:0;text-overflow:ellipsis;white-space:nowrap}.aa-ItemContentSubtitle{font-size:.92em}.aa-ItemContentSubtitleIcon:before{border-color:#807ea3a3;border-color:rgba(var(--aa-muted-color-rgb),.64);border-style:solid;content:"";display:inline-block;left:1px;position:relative;top:-3px}.aa-PanelFooter:after,.aa-PanelHeader:after{content:"";position:absolute;left:0;pointer-events:none;right:0}.aa-ItemContentSubtitle--inline .aa-ItemContentSubtitleIcon:before{border-width:0 0 1.5px;margin-left:8px;margin-left:var(--aa-spacing-half);margin-right:4px;margin-right:calc(var(--aa-spacing-half)/2);width:10px;width:calc(var(--aa-spacing-half) + 2px)}.aa-ItemContentSubtitle--standalone{align-items:center;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));display:grid;gap:8px;grid-gap:8px;grid-gap:var(--aa-spacing-half);gap:var(--aa-spacing-half);grid-auto-flow:column;justify-content:start}#__docusaurus-base-url-issue-banner-container,.aa-DetachedContainer--modal .aa-PanelLayout:empty,.aa-DetachedSearchButtonPlaceholder[hidden],.aa-ItemContentDescription:empty,.navbarSearchContainer_Bca1:empty{display:none}.aa-ItemContentSubtitle--standalone .aa-ItemContentSubtitleIcon:before{border-radius:0 0 0 3px;border-width:0 0 1.5px 1.5px;height:8px;height:var(--aa-spacing-half);width:8px;width:var(--aa-spacing-half)}.aa-ItemContentSubtitleCategory{color:#807ea3;color:rgba(var(--aa-muted-color-rgb),1);font-weight:500}.aa-ItemContentDescription{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-size:.85em;max-width:100%;overflow-x:hidden;text-overflow:ellipsis}.aa-ItemContentDescription mark{background:#f5df4d80;background:rgba(var(--aa-description-highlight-background-color-rgb),var(--aa-description-highlight-background-color-alpha));color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-style:normal;font-weight:500;font-weight:var(--aa-font-weight-medium)}.aa-ItemContentDash{color:#807ea399;color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));display:none;opacity:.4}.aa-ItemContentTag{background-color:#3e34d333;background-color:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha));border-radius:3px;margin:0 .4em 0 0;padding:.08em .3em}.aa-ItemLink,.aa-ItemWrapper{align-items:center;color:inherit;display:grid;gap:4px;grid-gap:4px;grid-gap:calc(var(--aa-spacing-half)/2);gap:calc(var(--aa-spacing-half)/2);grid-auto-flow:column;justify-content:space-between;width:100%}.aa-ItemLink{color:inherit}.aa-ItemActions{display:grid;grid-auto-flow:column;height:100%;justify-self:end;margin:0 -5.33333px;margin:0 calc(var(--aa-spacing)/-3);padding:0 2px 0 0}.aa-ItemActionButton{align-items:center;background:none;border:0;color:#807ea399;color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));cursor:pointer;display:flex;flex-shrink:0;padding:0}.aa-ItemActionButton svg{color:#807ea399;color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));margin:5.33333px;margin:calc(var(--aa-spacing)/3);stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);width:20px;width:var(--aa-action-icon-size)}.aa-ActiveOnly{visibility:hidden}.aa-PanelHeader{align-items:center;background:#3e34d3;background:rgba(var(--aa-primary-color-rgb),1);color:#fff;display:grid;height:var(--aa-modal-header-height);margin:0;padding:8px 16px;padding:var(--aa-spacing-half) var(--aa-spacing);position:relative}.aa-PanelHeader:after{background-image:linear-gradient(#fff,#fff0);background-image:linear-gradient(rgba(var(--aa-background-color-rgb),1),rgba(var(--aa-background-color-rgb),0));bottom:-8px;bottom:calc(var(--aa-spacing-half)*-1);height:8px;height:var(--aa-spacing-half)}.aa-PanelFooter,.aa-PanelHeader:after{z-index:9999;z-index:var(--aa-base-z-index)}.aa-PanelFooter{background-color:#fff;background-color:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));box-shadow:inset 0 1px 0 #807ea34d;box-shadow:inset 0 1px 0 rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha));display:flex;justify-content:space-between;margin:0;padding:16px;padding:var(--aa-spacing);position:relative}.aa-PanelFooter:after{background-image:linear-gradient(#fff0,#807ea399);background-image:linear-gradient(rgba(var(--aa-background-color-rgb),0),rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha)));height:16px;height:var(--aa-spacing);opacity:.12;top:-16px;top:calc(var(--aa-spacing)*-1);z-index:9998;z-index:calc(var(--aa-base-z-index) - 1)}.aa-DetachedContainer{background:#fff;background:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));bottom:0;box-shadow:0 0 0 1px #23263b1a,0 6px 16px -4px #23263b26;box-shadow:var(--aa-panel-shadow);display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:9999;z-index:var(--aa-base-z-index)}.aa-DetachedContainer:after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:8px 0 8px 2px;margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;background-color:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{border-bottom:1px solid #807ea34d;border-bottom:1px solid rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha));display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:8px;padding:var(--aa-spacing-half)}.aa-DetachedCancelButton{background:none;border:0;border-radius:3px;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));cursor:pointer;font:inherit;margin:0 0 0 8px;margin:0 0 0 var(--aa-spacing-half);padding:0 8px;padding:0 var(--aa-spacing-half)}.aa-DetachedCancelButton:focus,.aa-DetachedCancelButton:hover{box-shadow:inset 0 0 0 1px #807ea34d;box-shadow:inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha))}.aa-DetachedContainer--modal{border-radius:6px;bottom:inherit;height:auto;margin:0 auto;max-width:680px;max-width:var(--aa-detached-modal-max-width);position:absolute;top:3%}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:500px;max-height:var(--aa-detached-modal-max-height);padding-bottom:8px;padding-bottom:var(--aa-spacing-half);position:static}.aa-DetachedSearchButton{align-items:center;background-color:#fff;background-color:rgba(var(--aa-input-background-color-rgb),var(--aa-input-background-color-alpha));border:1px solid #807ea3cc;border:1px solid rgba(var(--aa-input-border-color-rgb),var(--aa-input-border-color-alpha));border-radius:3px;color:#807ea399;color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));cursor:pointer;display:flex;font:inherit;font-family:inherit;font-family:var(--aa-font-family);font-size:16px;font-size:var(--aa-font-size);height:44px;height:var(--aa-search-input-height);margin:0;padding:0 5.5px;padding:0 calc(var(--aa-search-input-height)/8);position:relative;text-align:left;width:100%}.aa-DetachedSearchButton:focus{border-color:#3e34d3;border-color:rgba(var(--aa-primary-color-rgb),1);box-shadow:0 0 0 3px #3e34d333,inset 0 0 0 2px #3e34d333;box-shadow:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 3px,inset rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px;outline:currentColor}.aa-DetachedSearchButtonIcon{align-items:center;color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1);cursor:auto;display:flex;flex-shrink:0;height:100%;justify-content:center;width:36px;width:calc(var(--aa-icon-size) + var(--aa-spacing))}.aa-DetachedSearchButtonQuery{color:#262627;color:rgba(var(--aa-text-color-rgb),1);line-height:1.25em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:#73728166;background-color:rgba(var(--aa-overlay-color-rgb),var(--aa-overlay-color-alpha));height:100vh;left:0;margin:0;padding:0;position:fixed;right:0;top:0;z-index:9998;z-index:calc(var(--aa-base-z-index) - 1)}.aa-GradientBottom,.aa-GradientTop{height:8px;height:var(--aa-spacing-half);left:0;pointer-events:none;position:absolute;right:0;z-index:9999;z-index:var(--aa-base-z-index)}.aa-GradientTop{background-image:linear-gradient(#fff,#fff0);background-image:linear-gradient(rgba(var(--aa-background-color-rgb),1),rgba(var(--aa-background-color-rgb),0));top:0}.aa-GradientBottom{background-image:linear-gradient(#fff0,#fff);background-image:linear-gradient(rgba(var(--aa-background-color-rgb),0),rgba(var(--aa-background-color-rgb),1));border-bottom-left-radius:4px;border-bottom-left-radius:calc(var(--aa-spacing)/4);border-bottom-right-radius:4px;border-bottom-right-radius:calc(var(--aa-spacing)/4);bottom:0}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.title_kItE{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-leading)*1.25)}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}.lastUpdated_JAkA{text-align:right}.tocMobile_ITEo{display:none}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);-webkit-text-decoration:none!important;text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.docItemCol_VOVn,.generatedIndexPage_vN6x{max-width:75%!important}.list_eTzJ article:nth-last-child(-n+2){margin-bottom:0!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block;width:max-content}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.docItemContainer_F8PC{padding:0 .3rem}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}.aa-TouchOnly{display:none}}@media (hover:none) and (pointer:coarse){:root{--aa-spacing-factor:1.2;--aa-action-icon-size:22px}.aa-LoadingIndicator,.aa-SubmitButton{padding-left:3px;padding-left:calc(var(--aa-spacing-half)/ 2 - 1px);width:39px;width:calc(var(--aa-icon-size) + var(--aa-spacing)*1.25 - 1px)}.aa-ClearButton{padding:0 10.16672px;padding:0 calc(var(--aa-spacing)*.66667 - .5px)}.aa-ItemActionButton:focus svg,.aa-ItemActionButton:hover svg{color:inherit}.aa-DesktopOnly{display:none}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion){.aa-Panel{transition:none}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg b/pr-preview/pr-1071/assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg deleted file mode 100644 index f76b674710..0000000000 --- a/pr-preview/pr-1071/assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg +++ /dev/null @@ -1,1127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pr-preview/pr-1071/assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg b/pr-preview/pr-1071/assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg deleted file mode 100644 index 4149941117..0000000000 --- a/pr-preview/pr-1071/assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg +++ /dev/null @@ -1,1737 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pr-preview/pr-1071/assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg b/pr-preview/pr-1071/assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg deleted file mode 100644 index 7e291b4696..0000000000 --- a/pr-preview/pr-1071/assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg +++ /dev/null @@ -1,1417 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pr-preview/pr-1071/assets/images/components-dd64f006e7d6b6facb9eb16f1af59d39.svg b/pr-preview/pr-1071/assets/images/components-dd64f006e7d6b6facb9eb16f1af59d39.svg deleted file mode 100644 index 33f1df4223..0000000000 --- a/pr-preview/pr-1071/assets/images/components-dd64f006e7d6b6facb9eb16f1af59d39.svg +++ /dev/null @@ -1,798 +0,0 @@ - - diff --git a/pr-preview/pr-1071/assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg b/pr-preview/pr-1071/assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg deleted file mode 100644 index bd65c768ef..0000000000 --- a/pr-preview/pr-1071/assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg +++ /dev/null @@ -1,766 +0,0 @@ - - diff --git a/pr-preview/pr-1071/assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg b/pr-preview/pr-1071/assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg deleted file mode 100644 index af04ecafab..0000000000 --- a/pr-preview/pr-1071/assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pr-preview/pr-1071/assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg b/pr-preview/pr-1071/assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg deleted file mode 100644 index 386d2215c2..0000000000 --- a/pr-preview/pr-1071/assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
Root CA








Root CA Certificate
Root CA
Private Key
Intermediate CA








Intermediate CA
Certificate
Intermediate CA
Private Key
Mesh CA
Certificate
Mesh








Mesh Certificate
Mesh Private Key
signs
signs
signs
signs
diff --git a/pr-preview/pr-1071/assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png b/pr-preview/pr-1071/assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png deleted file mode 100644 index 9779306e04..0000000000 Binary files a/pr-preview/pr-1071/assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png and /dev/null differ diff --git a/pr-preview/pr-1071/assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg b/pr-preview/pr-1071/assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg deleted file mode 100644 index c14341047f..0000000000 --- a/pr-preview/pr-1071/assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg +++ /dev/null @@ -1,568 +0,0 @@ - - diff --git a/pr-preview/pr-1071/assets/images/personas-1c9f2b217e0b94e0c3057df96d96b3f0.svg b/pr-preview/pr-1071/assets/images/personas-1c9f2b217e0b94e0c3057df96d96b3f0.svg deleted file mode 100644 index 19988f631c..0000000000 --- a/pr-preview/pr-1071/assets/images/personas-1c9f2b217e0b94e0c3057df96d96b3f0.svg +++ /dev/null @@ -1,573 +0,0 @@ - - diff --git a/pr-preview/pr-1071/assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg b/pr-preview/pr-1071/assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg deleted file mode 100644 index b13d79e3ae..0000000000 --- a/pr-preview/pr-1071/assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg +++ /dev/null @@ -1,1376 +0,0 @@ - - diff --git a/pr-preview/pr-1071/assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg b/pr-preview/pr-1071/assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg deleted file mode 100644 index b20ac5284c..0000000000 --- a/pr-preview/pr-1071/assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg +++ /dev/null @@ -1,547 +0,0 @@ - - diff --git a/pr-preview/pr-1071/assets/js/014daffb.aacfa15a.js b/pr-preview/pr-1071/assets/js/014daffb.aacfa15a.js deleted file mode 100644 index c3da45e3e4..0000000000 --- a/pr-preview/pr-1071/assets/js/014daffb.aacfa15a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1955],{89204:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","source":"@site/docs/architecture/secrets.md","sourceDirName":"architecture","slug":"/architecture/secrets","permalink":"/contrast/pr-preview/pr-1071/next/architecture/secrets","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/architecture/secrets.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/next/architecture/attestation"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/next/architecture/certificates"}}');var r=s(74848),i=s(28453);const o={},a="Secrets & recovery",c={},d=[{value:"Persistence",id:"persistence",level:2},{value:"Recovery",id:"recovery",level:2},{value:"Workload Secrets",id:"workload-secrets",level:2},{value:"Secure persistence",id:"secure-persistence",level:3}];function h(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"secrets--recovery",children:"Secrets & recovery"})}),"\n",(0,r.jsx)(t.p,{children:"When the Coordinator is configured with the initial manifest, it generates a random secret seed.\nFrom this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history.\nThis derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state."}),"\n",(0,r.jsxs)(t.p,{children:["The secret seed is returned to the user on the first call to ",(0,r.jsx)(t.code,{children:"contrast set"}),", encrypted with the user's public seed share owner key.\nIf no seed share owner key is provided, a key is generated and stored in the working directory."]}),"\n",(0,r.jsx)(t.h2,{id:"persistence",children:"Persistence"}),"\n",(0,r.jsxs)(t.p,{children:["The Coordinator runs as a ",(0,r.jsx)(t.code,{children:"StatefulSet"})," with a dynamically provisioned persistent volume.\nThis volume stores the manifest history and the associated runtime policies.\nThe manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads.\nHowever, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users.\nThus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed."]}),"\n",(0,r.jsx)(t.h2,{id:"recovery",children:"Recovery"}),"\n",(0,r.jsxs)(t.p,{children:["When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests.\nIt needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures.\nThis procedure is called recovery and is initiated by the workload owner.\nThe CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the ",(0,r.jsx)(t.code,{children:"Recover"})," method.\nThe Coordinator recovers its key material and verifies the manifest history signature."]}),"\n",(0,r.jsx)(t.h2,{id:"workload-secrets",children:"Workload Secrets"}),"\n",(0,r.jsxs)(t.p,{children:["The Coordinator provides each workload a secret seed during attestation.\nThis secret can be used by the workload to derive additional secrets for example to encrypt persistent data.\nLike the workload certificates, it's written to the ",(0,r.jsx)(t.code,{children:"secrets/workload-secret-seed"})," path under the shared Kubernetes volume ",(0,r.jsx)(t.code,{children:"contrast-secrets"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsx)(t.p,{children:"The workload owner can decrypt data encrypted with secrets derived from the workload secret.\nThe workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner.\nIf the data owner and the workload owner is the same entity, then they can safely use the workload secrets."})}),"\n",(0,r.jsx)(t.h3,{id:"secure-persistence",children:"Secure persistence"}),"\n",(0,r.jsx)(t.p,{children:"Remember that persistent volumes from the cloud provider are untrusted.\nUsing the workload secret, applications can set up trusted storage on top of untrusted block devices.\nThe following, slightly abbreviated resource outlines how this could be realized:"}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsx)(t.p,{children:"This configuration snippet is intended to be educational and needs to be refined and adapted to your production environment.\nUsing it as-is may result in data corruption or data loss."})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-yaml",children:"apiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n name: volume-tester\nspec:\n template:\n spec:\n containers:\n - name: main\n image: my.registry/my-image@sha256:0123...\n command:\n - /bin/sh\n - -ec\n - | # <-- Custom script that mounts the encrypted disk and then calls the original application.\n device=/dev/csi0\n if ! cryptsetup isLuks $device; then\n cryptsetup luksFormat $device /contrast/secrets/workload-secret-seed\n cryptsetup open $device state -d /contrast/secrets/workload-secret-seed\n mkfs.ext4 /dev/mapper/state\n cryptsetup close state\n fi\n cryptsetup open $device state -d /contrast/secrets/workload-secret-seed\n /path/to/original/app\n name: volume-tester\n volumeDevices:\n - name: state\n devicePath: /dev/csi0\n securityContext:\n privileged: true # <-- This is necessary for mounting devices.\n runtimeClassName: contrast-cc\n volumeClaimTemplates:\n - apiVersion: v1\n kind: PersistentVolumeClaim\n metadata:\n name: state\n spec:\n accessModes:\n - ReadWriteOnce\n resources:\n requests:\n storage: 1Gi\n volumeMode: Block # <-- The requested volume needs to be a raw block device.\n"})}),"\n",(0,r.jsx)(t.admonition,{type:"note",children:(0,r.jsxs)(t.p,{children:["This example assumes that you can modify the container image to include a shell and the ",(0,r.jsx)(t.code,{children:"cryptsetup"})," utility.\nAlternatively, you can set up a secure mount from a sidecar container inside an ",(0,r.jsx)(t.code,{children:"emptyDir"})," mount shared with the main container.\nThe Contrast end-to-end tests include ",(0,r.jsx)(t.a,{href:"https://github.com/edgelesssys/contrast/blob/0662a2e/internal/kuberesource/sets.go#L504",children:"an example"})," of this type of mount."]})})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},28453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>a});var n=s(96540);const r={},i=n.createContext(r);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/018595b3.6fec9739.js b/pr-preview/pr-1071/assets/js/018595b3.6fec9739.js deleted file mode 100644 index 29312c637b..0000000000 --- a/pr-preview/pr-1071/assets/js/018595b3.6fec9739.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3876],{59763:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>l,default:()=>m,frontMatter:()=>c,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"examples/index","title":"Examples","description":"","source":"@site/versioned_docs/version-0.5/examples/index.md","sourceDirName":"examples","slug":"/examples/","permalink":"/contrast/pr-preview/pr-1071/0.5/examples/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/examples/index.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"First steps","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto"}}');var s=n(74848),o=n(28453),i=n(44074);const c={},l="Examples",a={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"examples",children:"Examples"})}),"\n","\n",(0,s.jsx)(i.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>b});var r=n(96540),s=n(34164),o=n(45357),i=n(14783),c=n(97639);const l=["zero","one","two","few","many","other"];function a(e){return l.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:a(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,c.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:a(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function m(){const e=d();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=n(74848);function j(e){let{href:t,children:n}=e;return(0,g.jsx)(i.A,{href:t,className:(0,s.A)("card padding--lg",x.cardContainer),children:n})}function v(e){let{href:t,icon:n,title:r,description:o}=e;return(0,g.jsxs)(j,{href:t,children:[(0,g.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",x.cardTitle),title:r,children:[n," ",r]}),o&&(0,g.jsx)("p",{className:(0,s.A)("text--truncate",x.cardDescription),title:o,children:o})]})}function w(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,g.jsx)(v,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function y(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,g.jsx)(v,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function C(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(y,{item:t});case"category":return(0,g.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const n=(0,o.$S)();return(0,g.jsx)(b,{items:n.items,className:t})}function b(e){const{items:t,className:n}=e;if(!t)return(0,g.jsx)(N,{...e});const r=(0,o.d1)(t);return(0,g.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(C,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>c});var r=n(96540);const s={},o=r.createContext(s);function i(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/04102e85.9c299feb.js b/pr-preview/pr-1071/assets/js/04102e85.9c299feb.js deleted file mode 100644 index b29dd70f50..0000000000 --- a/pr-preview/pr-1071/assets/js/04102e85.9c299feb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1158],{30612:(t,e,r)=>{r.r(e),r.d(e,{assets:()=>i,contentTitle:()=>c,default:()=>p,frontMatter:()=>s,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/attestation/hardware","title":"hardware","description":"","source":"@site/versioned_docs/version-0.5/architecture/attestation/hardware.md","sourceDirName":"architecture/attestation","slug":"/architecture/attestation/hardware","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/attestation/hardware.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.5/category/attestation"},"next":{"title":"Pod VM","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm"}}');var a=r(74848),o=r(28453);const s={},c=void 0,i={},d=[];function u(t){return(0,a.jsx)(a.Fragment,{})}function p(t={}){const{wrapper:e}={...(0,o.R)(),...t.components};return e?(0,a.jsx)(e,{...t,children:(0,a.jsx)(u,{...t})}):u()}},28453:(t,e,r)=>{r.d(e,{R:()=>s,x:()=>c});var n=r(96540);const a={},o=n.createContext(a);function s(t){const e=n.useContext(o);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function c(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(a):t.components||a:s(t.components),n.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/046575a6.0f7f0430.js b/pr-preview/pr-1071/assets/js/046575a6.0f7f0430.js deleted file mode 100644 index 11851f0b08..0000000000 --- a/pr-preview/pr-1071/assets/js/046575a6.0f7f0430.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2285],{30182:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-1.2/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/about/telemetry.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/features-limitations"}}');var r=n(74848),o=n(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/06354bbe.69f65616.js b/pr-preview/pr-1071/assets/js/06354bbe.69f65616.js deleted file mode 100644 index b774508a23..0000000000 --- a/pr-preview/pr-1071/assets/js/06354bbe.69f65616.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8204],{18733:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-0.9/components/overview.md","sourceDirName":"components","slug":"/components/overview","permalink":"/contrast/pr-preview/pr-1071/0.9/components/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/components/overview.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/0.9/troubleshooting"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.9/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},l=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(77998).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},77998:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/06eada7a.2bde985a.js b/pr-preview/pr-1071/assets/js/06eada7a.2bde985a.js deleted file mode 100644 index dfb43d25ae..0000000000 --- a/pr-preview/pr-1071/assets/js/06eada7a.2bde985a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6470],{28601:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-0.7/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/0.7/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/components/policies.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.7/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.7/components/service-mesh"}}');var s=n(74848),o=n(28453);const r={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(96540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/078f57bf.102e2128.js b/pr-preview/pr-1071/assets/js/078f57bf.102e2128.js deleted file mode 100644 index 88af743c20..0000000000 --- a/pr-preview/pr-1071/assets/js/078f57bf.102e2128.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1690],{30569:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/versioned_docs/version-0.9/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/architecture/observability.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/certificates"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/0.9/features-limitations"}}');var s=r(74848),i=r(28453);const o={},c="Observability",a={},d=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function h(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator exports gRPC metrics under the prefix ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_"}),".\nThese metrics are labeled with the gRPC service name and method name.\nMetrics of interest include ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handled_total"}),", which counts\nthe number of requests by return code, and\n",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handling_seconds_bucket"}),", which produces a histogram of",(0,s.jsx)(t.br,{}),"\n","request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["The gRPC service ",(0,s.jsx)(t.code,{children:"userapi.UserAPI"})," records metrics for the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"meshapi.MeshAPI"})," service records metrics for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"}),", which\ngets called by the ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures_total"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/098bf236.7fb3130f.js b/pr-preview/pr-1071/assets/js/098bf236.7fb3130f.js deleted file mode 100644 index 1b754a8d4d..0000000000 --- a/pr-preview/pr-1071/assets/js/098bf236.7fb3130f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8259],{32284:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-0.8/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/0.8/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/intro.md","tags":[],"version":"0.8","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/getting-started/install",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/0a09f1f2.8c4c401c.js b/pr-preview/pr-1071/assets/js/0a09f1f2.8c4c401c.js deleted file mode 100644 index 5dfc340e76..0000000000 --- a/pr-preview/pr-1071/assets/js/0a09f1f2.8c4c401c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7e3],{35787:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-1.1/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/1.1/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/deployment.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto"},"next":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/1.1/troubleshooting"}}');var r=t(74848),a=t(28453);const i={},o="Workload deployment",l={},c=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"Security review",id:"security-review",level:3},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2},{value:"Recover the Coordinator",id:"recover-the-coordinator",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components},{TabItem:t,Tabs:s}=n;return t||u("TabItem",!0),s||u("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,r.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup",children:"setup guide"})," on how to set up a cluster on AKS."]})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal",children:"setup guide"})," on how to set up a bare-metal cluster."]})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal",children:"setup guide"})," on how to set up a bare-metal cluster."]})})]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast depends on a ",(0,r.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:["custom Kubernetes ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," (",(0,r.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,r.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-aks-clh-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-aks-clh-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,r.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,r.jsx)(n.h3,{id:"security-review",children:"Security review"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast ensures integrity and confidentiality of the applications, but interactions with untrusted systems require the developers' attention.\nReview the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations",children:"security considerations"})," and the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates",children:"certificates"})," section for writing secure Contrast application."]}),"\n",(0,r.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,r.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,r.jsxs)(s,{groupId:"yaml-source",children:[(0,r.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"helm",label:"helm",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"copy",label:"copy",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,r.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,r.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,r.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,r.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,r.jsxs)(n.p,{children:["In the initialization process, the ",(0,r.jsx)(n.code,{children:"contrast-secrets"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,r.jsxs)(s,{groupId:"tls",children:[(0,r.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,r.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,r.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,r.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,r.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,r.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,r.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,r.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,r.jsxs)(n.p,{children:["During the ",(0,r.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,r.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,r.jsxs)(t,{value:"go",label:"Go integration",children:[(0,r.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,r.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,r.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,r.jsxs)(s,{groupId:"golang-tls-setup",children:[(0,r.jsx)(t,{value:"client",label:"Client",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,r.jsx)(t,{value:"server",label:"Server",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(n.p,{children:["Run the ",(0,r.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,r.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp resources/\n"})})}),(0,r.jsxs)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp resources/\n"})}),(0,r.jsx)(n.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(n.p,{children:["On bare-metal SEV-SNP, ",(0,r.jsx)(n.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(n.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(n.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,r.jsxs)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx resources/\n"})}),(0,r.jsx)(n.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(n.p,{children:["On bare-metal TDX, ",(0,r.jsx)(n.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(n.code,{children:"MinimumTeeTcbSvn"})," and ",(0,r.jsx)(n.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(n.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,r.jsx)(n.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,r.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,r.jsxs)(s,{groupId:"injection",children:[(0,r.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,r.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,r.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,r.jsx)(n.code,{children:"generate"})," command."]}),(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp --skip-initializer resources/\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp --skip-initializer resources/\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx --skip-initializer resources/\n"})})})]})]}),(0,r.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,r.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,r.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,r.jsx)(n.code,{children:"contrast-secrets"})," ",(0,r.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:v1.1.1@sha256:d89d4f5113c8869088ff3a28e02802d7b72304d4bbb50fb664f1c6cba7fcb722"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /contrast\n name: contrast-secrets\n volumes:\n - emptyDir: {}\n name: contrast-secrets\n'})}),"\n",(0,r.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,r.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,r.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,r.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,r.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,r.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,r.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,r.jsx)(n.p,{children:"This will use the reference values from the manifest file to attest the Coordinator.\nAfter this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,r.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,r.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the\nservice mesh root certificate and the history of manifests into the ",(0,r.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies\nreferenced in the active manifest are also written to the directory. The verification will fail if the active\nmanifest at the Coordinator doesn't match the manifest passed to the CLI."]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,r.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,r.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,r.jsxs)(n.p,{children:["Using ",(0,r.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,r.jsx)(n.h2,{id:"recover-the-coordinator",children:"Recover the Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material.\nFor demonstration purposes, you can simulate this scenario by deleting the Coordinator pod."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl delete pod -l app.kubernetes.io/name=coordinator\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet.\nYou can confirm this by running ",(0,r.jsx)(n.code,{children:"verify"})," again, or you can restart a workload pod, which should stay in the initialization phase.\nHowever, the secret seed in your working directory is sufficient to recover the coordinator."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast recover -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsx)(n.p,{children:"Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state.\nYou can now verify the Coordinator again, which should return the same manifest you set before."}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The recovery process invalidates the mesh CA certificate:\nexisting workloads won't be able to communicate with workloads newly spawned.\nAll workloads should be restarted after the recovery succeeded."})}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function u(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>o});var s=t(96540);const r={},a=s.createContext(r);function i(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/0a7a212e.cb47d607.js b/pr-preview/pr-1071/assets/js/0a7a212e.cb47d607.js deleted file mode 100644 index bd1e306df0..0000000000 --- a/pr-preview/pr-1071/assets/js/0a7a212e.cb47d607.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3702],{4949:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-0.8/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/basics/confidential-containers.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"What is Contrast?","permalink":"/contrast/pr-preview/pr-1071/0.8/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/0b1c872d.46cf372e.js b/pr-preview/pr-1071/assets/js/0b1c872d.46cf372e.js deleted file mode 100644 index 6871a830c7..0000000000 --- a/pr-preview/pr-1071/assets/js/0b1c872d.46cf372e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3188],{25776:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-1.1/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/1.1/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/components/policies.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/1.1/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/1.1/components/service-mesh"}}');var s=n(74848),r=n(28453);const o={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2},{value:"Platform Differences",id:"platform-differences",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," or TDX ",(0,s.jsx)(t.code,{children:"MRCONFIGID"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," or ",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."}),"\n",(0,s.jsx)(t.h2,{id:"platform-differences",children:"Platform Differences"}),"\n",(0,s.jsx)(t.p,{children:"Contrast uses different rules and data sections for different platforms.\nThis results in different policy hashes for different platforms."}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"generate"})," command automatically derives the correct set of rules and data sections from the ",(0,s.jsx)(t.code,{children:"reference-values"})," flag."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"verify"}),", ",(0,s.jsx)(t.code,{children:"set"}),", and ",(0,s.jsx)(t.code,{children:"recover"})," commands need to know the coordinator's expected policy hash to verify its identity.\nBy default these commands assume that the coordinator is using the policy for the ",(0,s.jsx)(t.code,{children:"AKS-CLH-SNP"})," platform.\nIf the coordinator is running on a different platform, the correct policy hash can be looked up in the ",(0,s.jsx)(t.code,{children:"coordinator-policy.hash"})," file bundled with the ",(0,s.jsx)(t.a,{href:"https://github.com/edgelesssys/contrast/releases",children:"Contrast release"}),".\nThe coordinator policy hash can be overwritten using the ",(0,s.jsx)(t.code,{children:"--coordinator-policy-hash"})," flag."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const s={},r=i.createContext(s);function o(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/0ba7602a.036d984e.js b/pr-preview/pr-1071/assets/js/0ba7602a.036d984e.js deleted file mode 100644 index e232e39b84..0000000000 --- a/pr-preview/pr-1071/assets/js/0ba7602a.036d984e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7368],{37154:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/versioned_docs/version-0.9/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/0.9/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/features-limitations.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/observability"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/0.9/about/telemetry"}}');var r=t(74848),s=t(28453);const o={},a="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2},{value:"Automatic recovery and high availability",id:"automatic-recovery-and-high-availability",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,r.jsx)(n.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,r.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,r.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Bare-metal support"}),": Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Persistent volumes"}),": Contrast only supports volumes with ",(0,r.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode",children:(0,r.jsx)(n.code,{children:"volumeMode: Block"})}),". These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Port forwarding"}),": This feature ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,r.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,r.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,r.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Volume integrity checks"}),": While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ",(0,r.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,r.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,r.jsx)(n.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"automatic-recovery-and-high-availability",children:"Automatic recovery and high availability"}),"\n",(0,r.jsx)(n.p,{children:"The Contrast Coordinator is a singleton and can't be scaled to more than one instance.\nWhen this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually.\nIn a future release, we plan to support distributed Coordinator instances that can recover automatically."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var i=t(96540);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/0c24bc66.c5075be6.js b/pr-preview/pr-1071/assets/js/0c24bc66.c5075be6.js deleted file mode 100644 index 9a268c8fbd..0000000000 --- a/pr-preview/pr-1071/assets/js/0c24bc66.c5075be6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6739],{73521:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-0.6/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/basics/security-benefits.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(34696).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(95662).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},95662:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-1c9f2b217e0b94e0c3057df96d96b3f0.svg"},34696:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/0e384e19.68c56d44.js b/pr-preview/pr-1071/assets/js/0e384e19.68c56d44.js deleted file mode 100644 index 1f895a816e..0000000000 --- a/pr-preview/pr-1071/assets/js/0e384e19.68c56d44.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3976],{73700:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/docs/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/next/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/intro.md","tags":[],"version":"current","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/next/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/install",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/10257d90.4ab1db5d.js b/pr-preview/pr-1071/assets/js/10257d90.4ab1db5d.js deleted file mode 100644 index 7babb8edbe..0000000000 --- a/pr-preview/pr-1071/assets/js/10257d90.4ab1db5d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3477],{45013:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-1.1/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/basics/security-benefits.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(94074).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(72168).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},72168:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},94074:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1057c3b3.c2e3952a.js b/pr-preview/pr-1071/assets/js/1057c3b3.c2e3952a.js deleted file mode 100644 index bfe8639122..0000000000 --- a/pr-preview/pr-1071/assets/js/1057c3b3.c2e3952a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5811],{26033:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-1.1/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/basics/confidential-containers.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"What is Contrast?","permalink":"/contrast/pr-preview/pr-1071/1.1/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1478.f7519b53.js b/pr-preview/pr-1071/assets/js/1478.f7519b53.js deleted file mode 100644 index 68543d3778..0000000000 --- a/pr-preview/pr-1071/assets/js/1478.f7519b53.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1478],{96474:(t,e,s)=>{s.d(e,{A:()=>u,P:()=>a});var n=s(10009),i=s(20007),u=(0,n.K2)(((t,e)=>{let s;"sandbox"===e&&(s=(0,i.Ltv)("#i"+t));return("sandbox"===e?(0,i.Ltv)(s.nodes()[0].contentDocument.body):(0,i.Ltv)("body")).select(`[id="${t}"]`)}),"getDiagramElement"),a=(0,n.K2)(((t,e,s,i)=>{t.attr("class",s);const{width:u,height:a,x:l,y:c}=r(t,e);(0,n.a$)(t,a,u,i);const h=o(l,c,u,a,e);t.attr("viewBox",h),n.Rm.debug(`viewBox configured: ${h} with padding: ${e}`)}),"setupViewPortForSVG"),r=(0,n.K2)(((t,e)=>{const s=t.node()?.getBBox()||{width:0,height:0,x:0,y:0};return{width:s.width+2*e,height:s.height+2*e,x:s.x,y:s.y}}),"calculateDimensionsWithPadding"),o=(0,n.K2)(((t,e,s,n,i)=>`${t-i} ${e-i} ${s} ${n}`),"createViewBox")},66240:(t,e,s)=>{s.d(e,{Lh:()=>ot,_$:()=>l,tM:()=>at,z2:()=>ut});var n=s(96474),i=s(87308),u=s(8159),a=s(10009),r=s(20007),o=function(){var t=(0,a.K2)((function(t,e,s,n){for(s=s||{},n=t.length;n--;s[t[n]]=e);return s}),"o"),e=[1,18],s=[1,19],n=[1,20],i=[1,41],u=[1,42],r=[1,26],o=[1,24],l=[1,25],c=[1,32],h=[1,33],p=[1,34],d=[1,45],A=[1,35],y=[1,36],g=[1,37],m=[1,38],C=[1,27],f=[1,28],E=[1,29],b=[1,30],k=[1,31],T=[1,44],D=[1,46],F=[1,43],B=[1,47],_=[1,9],S=[1,8,9],N=[1,58],L=[1,59],$=[1,60],x=[1,61],O=[1,62],v=[1,63],I=[1,64],K=[1,8,9,41],w=[1,76],R=[1,8,9,12,13,22,39,41,44,66,67,68,69,70,71,72,77,79],P=[1,8,9,12,13,17,20,22,39,41,44,48,58,66,67,68,69,70,71,72,77,79,84,99,101,102],M=[13,58,84,99,101,102],G=[13,58,71,72,84,99,101,102],U=[13,58,66,67,68,69,70,84,99,101,102],Y=[1,98],z=[1,115],Q=[1,107],W=[1,113],X=[1,108],j=[1,109],V=[1,110],q=[1,111],H=[1,112],J=[1,114],Z=[22,58,59,80,84,85,86,87,88,89],tt=[1,8,9,39,41,44],et=[1,8,9,22],st=[1,143],nt=[1,8,9,59],it=[1,8,9,22,58,59,80,84,85,86,87,88,89],ut={trace:(0,a.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,statements:5,graphConfig:6,CLASS_DIAGRAM:7,NEWLINE:8,EOF:9,statement:10,classLabel:11,SQS:12,STR:13,SQE:14,namespaceName:15,alphaNumToken:16,DOT:17,className:18,classLiteralName:19,GENERICTYPE:20,relationStatement:21,LABEL:22,namespaceStatement:23,classStatement:24,memberStatement:25,annotationStatement:26,clickStatement:27,styleStatement:28,cssClassStatement:29,noteStatement:30,classDefStatement:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,namespaceIdentifier:38,STRUCT_START:39,classStatements:40,STRUCT_STOP:41,NAMESPACE:42,classIdentifier:43,STYLE_SEPARATOR:44,members:45,CLASS:46,ANNOTATION_START:47,ANNOTATION_END:48,MEMBER:49,SEPARATOR:50,relation:51,NOTE_FOR:52,noteText:53,NOTE:54,CLASSDEF:55,classList:56,stylesOpt:57,ALPHA:58,COMMA:59,direction_tb:60,direction_bt:61,direction_rl:62,direction_lr:63,relationType:64,lineType:65,AGGREGATION:66,EXTENSION:67,COMPOSITION:68,DEPENDENCY:69,LOLLIPOP:70,LINE:71,DOTTED_LINE:72,CALLBACK:73,LINK:74,LINK_TARGET:75,CLICK:76,CALLBACK_NAME:77,CALLBACK_ARGS:78,HREF:79,STYLE:80,CSSCLASS:81,style:82,styleComponent:83,NUM:84,COLON:85,UNIT:86,SPACE:87,BRKT:88,PCT:89,commentToken:90,textToken:91,graphCodeTokens:92,textNoTagsToken:93,TAGSTART:94,TAGEND:95,"==":96,"--":97,DEFAULT:98,MINUS:99,keywords:100,UNICODE_TEXT:101,BQUOTE_STR:102,$accept:0,$end:1},terminals_:{2:"error",7:"CLASS_DIAGRAM",8:"NEWLINE",9:"EOF",12:"SQS",13:"STR",14:"SQE",17:"DOT",20:"GENERICTYPE",22:"LABEL",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",39:"STRUCT_START",41:"STRUCT_STOP",42:"NAMESPACE",44:"STYLE_SEPARATOR",46:"CLASS",47:"ANNOTATION_START",48:"ANNOTATION_END",49:"MEMBER",50:"SEPARATOR",52:"NOTE_FOR",54:"NOTE",55:"CLASSDEF",58:"ALPHA",59:"COMMA",60:"direction_tb",61:"direction_bt",62:"direction_rl",63:"direction_lr",66:"AGGREGATION",67:"EXTENSION",68:"COMPOSITION",69:"DEPENDENCY",70:"LOLLIPOP",71:"LINE",72:"DOTTED_LINE",73:"CALLBACK",74:"LINK",75:"LINK_TARGET",76:"CLICK",77:"CALLBACK_NAME",78:"CALLBACK_ARGS",79:"HREF",80:"STYLE",81:"CSSCLASS",84:"NUM",85:"COLON",86:"UNIT",87:"SPACE",88:"BRKT",89:"PCT",92:"graphCodeTokens",94:"TAGSTART",95:"TAGEND",96:"==",97:"--",98:"DEFAULT",99:"MINUS",100:"keywords",101:"UNICODE_TEXT",102:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[4,1],[6,4],[5,1],[5,2],[5,3],[11,3],[15,1],[15,3],[15,2],[18,1],[18,3],[18,1],[18,2],[18,2],[18,2],[10,1],[10,2],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,2],[10,1],[23,4],[23,5],[38,2],[40,1],[40,2],[40,3],[24,1],[24,3],[24,4],[24,6],[43,2],[43,3],[26,4],[45,1],[45,2],[25,1],[25,2],[25,1],[25,1],[21,3],[21,4],[21,4],[21,5],[30,3],[30,2],[31,3],[56,1],[56,3],[32,1],[32,1],[32,1],[32,1],[51,3],[51,2],[51,2],[51,1],[64,1],[64,1],[64,1],[64,1],[64,1],[65,1],[65,1],[27,3],[27,4],[27,3],[27,4],[27,4],[27,5],[27,3],[27,4],[27,4],[27,5],[27,4],[27,5],[27,5],[27,6],[28,3],[29,3],[57,1],[57,3],[82,1],[82,2],[83,1],[83,1],[83,1],[83,1],[83,1],[83,1],[83,1],[83,1],[83,1],[90,1],[90,1],[91,1],[91,1],[91,1],[91,1],[91,1],[91,1],[91,1],[93,1],[93,1],[93,1],[93,1],[16,1],[16,1],[16,1],[16,1],[19,1],[53,1]],performAction:(0,a.K2)((function(t,e,s,n,i,u,a){var r=u.length-1;switch(i){case 8:this.$=u[r-1];break;case 9:case 12:case 14:this.$=u[r];break;case 10:case 13:this.$=u[r-2]+"."+u[r];break;case 11:case 15:case 95:this.$=u[r-1]+u[r];break;case 16:case 17:this.$=u[r-1]+"~"+u[r]+"~";break;case 18:n.addRelation(u[r]);break;case 19:u[r-1].title=n.cleanupLabel(u[r]),n.addRelation(u[r-1]);break;case 30:this.$=u[r].trim(),n.setAccTitle(this.$);break;case 31:case 32:this.$=u[r].trim(),n.setAccDescription(this.$);break;case 33:n.addClassesToNamespace(u[r-3],u[r-1]);break;case 34:n.addClassesToNamespace(u[r-4],u[r-1]);break;case 35:this.$=u[r],n.addNamespace(u[r]);break;case 36:case 46:case 59:case 92:this.$=[u[r]];break;case 37:this.$=[u[r-1]];break;case 38:u[r].unshift(u[r-2]),this.$=u[r];break;case 40:n.setCssClass(u[r-2],u[r]);break;case 41:n.addMembers(u[r-3],u[r-1]);break;case 42:n.setCssClass(u[r-5],u[r-3]),n.addMembers(u[r-5],u[r-1]);break;case 43:this.$=u[r],n.addClass(u[r]);break;case 44:this.$=u[r-1],n.addClass(u[r-1]),n.setClassLabel(u[r-1],u[r]);break;case 45:n.addAnnotation(u[r],u[r-2]);break;case 47:u[r].push(u[r-1]),this.$=u[r];break;case 48:case 50:case 51:break;case 49:n.addMember(u[r-1],n.cleanupLabel(u[r]));break;case 52:this.$={id1:u[r-2],id2:u[r],relation:u[r-1],relationTitle1:"none",relationTitle2:"none"};break;case 53:this.$={id1:u[r-3],id2:u[r],relation:u[r-1],relationTitle1:u[r-2],relationTitle2:"none"};break;case 54:this.$={id1:u[r-3],id2:u[r],relation:u[r-2],relationTitle1:"none",relationTitle2:u[r-1]};break;case 55:this.$={id1:u[r-4],id2:u[r],relation:u[r-2],relationTitle1:u[r-3],relationTitle2:u[r-1]};break;case 56:n.addNote(u[r],u[r-1]);break;case 57:n.addNote(u[r]);break;case 58:this.$=u[r-2],n.defineClass(u[r-1],u[r]);break;case 60:this.$=u[r-2].concat([u[r]]);break;case 61:n.setDirection("TB");break;case 62:n.setDirection("BT");break;case 63:n.setDirection("RL");break;case 64:n.setDirection("LR");break;case 65:this.$={type1:u[r-2],type2:u[r],lineType:u[r-1]};break;case 66:this.$={type1:"none",type2:u[r],lineType:u[r-1]};break;case 67:this.$={type1:u[r-1],type2:"none",lineType:u[r]};break;case 68:this.$={type1:"none",type2:"none",lineType:u[r]};break;case 69:this.$=n.relationType.AGGREGATION;break;case 70:this.$=n.relationType.EXTENSION;break;case 71:this.$=n.relationType.COMPOSITION;break;case 72:this.$=n.relationType.DEPENDENCY;break;case 73:this.$=n.relationType.LOLLIPOP;break;case 74:this.$=n.lineType.LINE;break;case 75:this.$=n.lineType.DOTTED_LINE;break;case 76:case 82:this.$=u[r-2],n.setClickEvent(u[r-1],u[r]);break;case 77:case 83:this.$=u[r-3],n.setClickEvent(u[r-2],u[r-1]),n.setTooltip(u[r-2],u[r]);break;case 78:this.$=u[r-2],n.setLink(u[r-1],u[r]);break;case 79:this.$=u[r-3],n.setLink(u[r-2],u[r-1],u[r]);break;case 80:this.$=u[r-3],n.setLink(u[r-2],u[r-1]),n.setTooltip(u[r-2],u[r]);break;case 81:this.$=u[r-4],n.setLink(u[r-3],u[r-2],u[r]),n.setTooltip(u[r-3],u[r-1]);break;case 84:this.$=u[r-3],n.setClickEvent(u[r-2],u[r-1],u[r]);break;case 85:this.$=u[r-4],n.setClickEvent(u[r-3],u[r-2],u[r-1]),n.setTooltip(u[r-3],u[r]);break;case 86:this.$=u[r-3],n.setLink(u[r-2],u[r]);break;case 87:this.$=u[r-4],n.setLink(u[r-3],u[r-1],u[r]);break;case 88:this.$=u[r-4],n.setLink(u[r-3],u[r-1]),n.setTooltip(u[r-3],u[r]);break;case 89:this.$=u[r-5],n.setLink(u[r-4],u[r-2],u[r]),n.setTooltip(u[r-4],u[r-1]);break;case 90:this.$=u[r-2],n.setCssStyle(u[r-1],u[r]);break;case 91:n.setCssClass(u[r-1],u[r]);break;case 93:u[r-2].push(u[r]),this.$=u[r-2]}}),"anonymous"),table:[{3:1,4:2,5:3,6:4,7:[1,6],10:5,16:39,18:21,19:40,21:7,23:8,24:9,25:10,26:11,27:12,28:13,29:14,30:15,31:16,32:17,33:e,35:s,37:n,38:22,42:i,43:23,46:u,47:r,49:o,50:l,52:c,54:h,55:p,58:d,60:A,61:y,62:g,63:m,73:C,74:f,76:E,80:b,81:k,84:T,99:D,101:F,102:B},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,3]},t(_,[2,5],{8:[1,48]}),{8:[1,49]},t(S,[2,18],{22:[1,50]}),t(S,[2,20]),t(S,[2,21]),t(S,[2,22]),t(S,[2,23]),t(S,[2,24]),t(S,[2,25]),t(S,[2,26]),t(S,[2,27]),t(S,[2,28]),t(S,[2,29]),{34:[1,51]},{36:[1,52]},t(S,[2,32]),t(S,[2,48],{51:53,64:56,65:57,13:[1,54],22:[1,55],66:N,67:L,68:$,69:x,70:O,71:v,72:I}),{39:[1,65]},t(K,[2,39],{39:[1,67],44:[1,66]}),t(S,[2,50]),t(S,[2,51]),{16:68,58:d,84:T,99:D,101:F},{16:39,18:69,19:40,58:d,84:T,99:D,101:F,102:B},{16:39,18:70,19:40,58:d,84:T,99:D,101:F,102:B},{16:39,18:71,19:40,58:d,84:T,99:D,101:F,102:B},{58:[1,72]},{13:[1,73]},{16:39,18:74,19:40,58:d,84:T,99:D,101:F,102:B},{13:w,53:75},{56:77,58:[1,78]},t(S,[2,61]),t(S,[2,62]),t(S,[2,63]),t(S,[2,64]),t(R,[2,12],{16:39,19:40,18:80,17:[1,79],20:[1,81],58:d,84:T,99:D,101:F,102:B}),t(R,[2,14],{20:[1,82]}),{15:83,16:84,58:d,84:T,99:D,101:F},{16:39,18:85,19:40,58:d,84:T,99:D,101:F,102:B},t(P,[2,118]),t(P,[2,119]),t(P,[2,120]),t(P,[2,121]),t([1,8,9,12,13,20,22,39,41,44,66,67,68,69,70,71,72,77,79],[2,122]),t(_,[2,6],{10:5,21:7,23:8,24:9,25:10,26:11,27:12,28:13,29:14,30:15,31:16,32:17,18:21,38:22,43:23,16:39,19:40,5:86,33:e,35:s,37:n,42:i,46:u,47:r,49:o,50:l,52:c,54:h,55:p,58:d,60:A,61:y,62:g,63:m,73:C,74:f,76:E,80:b,81:k,84:T,99:D,101:F,102:B}),{5:87,10:5,16:39,18:21,19:40,21:7,23:8,24:9,25:10,26:11,27:12,28:13,29:14,30:15,31:16,32:17,33:e,35:s,37:n,38:22,42:i,43:23,46:u,47:r,49:o,50:l,52:c,54:h,55:p,58:d,60:A,61:y,62:g,63:m,73:C,74:f,76:E,80:b,81:k,84:T,99:D,101:F,102:B},t(S,[2,19]),t(S,[2,30]),t(S,[2,31]),{13:[1,89],16:39,18:88,19:40,58:d,84:T,99:D,101:F,102:B},{51:90,64:56,65:57,66:N,67:L,68:$,69:x,70:O,71:v,72:I},t(S,[2,49]),{65:91,71:v,72:I},t(M,[2,68],{64:92,66:N,67:L,68:$,69:x,70:O}),t(G,[2,69]),t(G,[2,70]),t(G,[2,71]),t(G,[2,72]),t(G,[2,73]),t(U,[2,74]),t(U,[2,75]),{8:[1,94],24:95,40:93,43:23,46:u},{16:96,58:d,84:T,99:D,101:F},{45:97,49:Y},{48:[1,99]},{13:[1,100]},{13:[1,101]},{77:[1,102],79:[1,103]},{22:z,57:104,58:Q,80:W,82:105,83:106,84:X,85:j,86:V,87:q,88:H,89:J},{58:[1,116]},{13:w,53:117},t(S,[2,57]),t(S,[2,123]),{22:z,57:118,58:Q,59:[1,119],80:W,82:105,83:106,84:X,85:j,86:V,87:q,88:H,89:J},t(Z,[2,59]),{16:39,18:120,19:40,58:d,84:T,99:D,101:F,102:B},t(R,[2,15]),t(R,[2,16]),t(R,[2,17]),{39:[2,35]},{15:122,16:84,17:[1,121],39:[2,9],58:d,84:T,99:D,101:F},t(tt,[2,43],{11:123,12:[1,124]}),t(_,[2,7]),{9:[1,125]},t(et,[2,52]),{16:39,18:126,19:40,58:d,84:T,99:D,101:F,102:B},{13:[1,128],16:39,18:127,19:40,58:d,84:T,99:D,101:F,102:B},t(M,[2,67],{64:129,66:N,67:L,68:$,69:x,70:O}),t(M,[2,66]),{41:[1,130]},{24:95,40:131,43:23,46:u},{8:[1,132],41:[2,36]},t(K,[2,40],{39:[1,133]}),{41:[1,134]},{41:[2,46],45:135,49:Y},{16:39,18:136,19:40,58:d,84:T,99:D,101:F,102:B},t(S,[2,76],{13:[1,137]}),t(S,[2,78],{13:[1,139],75:[1,138]}),t(S,[2,82],{13:[1,140],78:[1,141]}),{13:[1,142]},t(S,[2,90],{59:st}),t(nt,[2,92],{83:144,22:z,58:Q,80:W,84:X,85:j,86:V,87:q,88:H,89:J}),t(it,[2,94]),t(it,[2,96]),t(it,[2,97]),t(it,[2,98]),t(it,[2,99]),t(it,[2,100]),t(it,[2,101]),t(it,[2,102]),t(it,[2,103]),t(it,[2,104]),t(S,[2,91]),t(S,[2,56]),t(S,[2,58],{59:st}),{58:[1,145]},t(R,[2,13]),{15:146,16:84,58:d,84:T,99:D,101:F},{39:[2,11]},t(tt,[2,44]),{13:[1,147]},{1:[2,4]},t(et,[2,54]),t(et,[2,53]),{16:39,18:148,19:40,58:d,84:T,99:D,101:F,102:B},t(M,[2,65]),t(S,[2,33]),{41:[1,149]},{24:95,40:150,41:[2,37],43:23,46:u},{45:151,49:Y},t(K,[2,41]),{41:[2,47]},t(S,[2,45]),t(S,[2,77]),t(S,[2,79]),t(S,[2,80],{75:[1,152]}),t(S,[2,83]),t(S,[2,84],{13:[1,153]}),t(S,[2,86],{13:[1,155],75:[1,154]}),{22:z,58:Q,80:W,82:156,83:106,84:X,85:j,86:V,87:q,88:H,89:J},t(it,[2,95]),t(Z,[2,60]),{39:[2,10]},{14:[1,157]},t(et,[2,55]),t(S,[2,34]),{41:[2,38]},{41:[1,158]},t(S,[2,81]),t(S,[2,85]),t(S,[2,87]),t(S,[2,88],{75:[1,159]}),t(nt,[2,93],{83:144,22:z,58:Q,80:W,84:X,85:j,86:V,87:q,88:H,89:J}),t(tt,[2,8]),t(K,[2,42]),t(S,[2,89])],defaultActions:{2:[2,1],3:[2,2],4:[2,3],83:[2,35],122:[2,11],125:[2,4],135:[2,47],146:[2,10],150:[2,38]},parseError:(0,a.K2)((function(t,e){if(!e.recoverable){var s=new Error(t);throw s.hash=e,s}this.trace(t)}),"parseError"),parse:(0,a.K2)((function(t){var e=this,s=[0],n=[],i=[null],u=[],r=this.table,o="",l=0,c=0,h=0,p=u.slice.call(arguments,1),d=Object.create(this.lexer),A={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(A.yy[y]=this.yy[y]);d.setInput(t,A.yy),A.yy.lexer=d,A.yy.parser=this,void 0===d.yylloc&&(d.yylloc={});var g=d.yylloc;u.push(g);var m=d.options&&d.options.ranges;function C(){var t;return"number"!=typeof(t=n.pop()||d.lex()||1)&&(t instanceof Array&&(t=(n=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof A.yy.parseError?this.parseError=A.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,a.K2)((function(t){s.length=s.length-2*t,i.length=i.length-t,u.length=u.length-t}),"popStack"),(0,a.K2)(C,"lex");for(var f,E,b,k,T,D,F,B,_,S={};;){if(b=s[s.length-1],this.defaultActions[b]?k=this.defaultActions[b]:(null==f&&(f=C()),k=r[b]&&r[b][f]),void 0===k||!k.length||!k[0]){var N="";for(D in _=[],r[b])this.terminals_[D]&&D>2&&_.push("'"+this.terminals_[D]+"'");N=d.showPosition?"Parse error on line "+(l+1)+":\n"+d.showPosition()+"\nExpecting "+_.join(", ")+", got '"+(this.terminals_[f]||f)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==f?"end of input":"'"+(this.terminals_[f]||f)+"'"),this.parseError(N,{text:d.match,token:this.terminals_[f]||f,line:d.yylineno,loc:g,expected:_})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+b+", token: "+f);switch(k[0]){case 1:s.push(f),i.push(d.yytext),u.push(d.yylloc),s.push(k[1]),f=null,E?(f=E,E=null):(c=d.yyleng,o=d.yytext,l=d.yylineno,g=d.yylloc,h>0&&h--);break;case 2:if(F=this.productions_[k[1]][1],S.$=i[i.length-F],S._$={first_line:u[u.length-(F||1)].first_line,last_line:u[u.length-1].last_line,first_column:u[u.length-(F||1)].first_column,last_column:u[u.length-1].last_column},m&&(S._$.range=[u[u.length-(F||1)].range[0],u[u.length-1].range[1]]),void 0!==(T=this.performAction.apply(S,[o,c,l,A.yy,k[1],i,u].concat(p))))return T;F&&(s=s.slice(0,-1*F*2),i=i.slice(0,-1*F),u=u.slice(0,-1*F)),s.push(this.productions_[k[1]][0]),i.push(S.$),u.push(S._$),B=r[s[s.length-2]][s[s.length-1]],s.push(B);break;case 3:return!0}}return!0}),"parse")},at=function(){return{EOF:1,parseError:(0,a.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,a.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,a.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,a.K2)((function(t){var e=t.length,s=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),s.length-1&&(this.yylineno-=s.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:s?(s.length===n.length?this.yylloc.first_column:0)+n[n.length-s.length].length-s[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,a.K2)((function(){return this._more=!0,this}),"more"),reject:(0,a.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,a.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,a.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,a.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,a.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,a.K2)((function(t,e){var s,n,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(n=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=n.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-n[n.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],s=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),s)return s;if(this._backtrack){for(var u in i)this[u]=i[u];return!1}return!1}),"test_match"),next:(0,a.K2)((function(){if(this.done)return this.EOF;var t,e,s,n;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),u=0;ue[0].length)){if(e=s,n=u,this.options.backtrack_lexer){if(!1!==(t=this.test_match(s,i[u])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[n]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,a.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,a.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,a.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,a.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,a.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,a.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,a.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{},performAction:(0,a.K2)((function(t,e,s,n){switch(s){case 0:return 60;case 1:return 61;case 2:return 62;case 3:return 63;case 4:case 5:case 14:case 31:case 36:case 40:case 47:break;case 6:return this.begin("acc_title"),33;case 7:return this.popState(),"acc_title_value";case 8:return this.begin("acc_descr"),35;case 9:return this.popState(),"acc_descr_value";case 10:this.begin("acc_descr_multiline");break;case 11:case 19:case 22:case 24:case 58:case 61:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:case 35:return 8;case 15:case 16:return 7;case 17:case 37:case 45:return"EDGE_STATE";case 18:this.begin("callback_name");break;case 20:this.popState(),this.begin("callback_args");break;case 21:return 77;case 23:return 78;case 25:return"STR";case 26:this.begin("string");break;case 27:return 80;case 28:return 55;case 29:return this.begin("namespace"),42;case 30:case 39:return this.popState(),8;case 32:return this.begin("namespace-body"),39;case 33:case 43:return this.popState(),41;case 34:case 44:return"EOF_IN_STRUCT";case 38:return this.begin("class"),46;case 41:return this.popState(),this.popState(),41;case 42:return this.begin("class-body"),39;case 46:return"OPEN_IN_STRUCT";case 48:return"MEMBER";case 49:return 81;case 50:return 73;case 51:return 74;case 52:return 76;case 53:return 52;case 54:return 54;case 55:return 47;case 56:return 48;case 57:return 79;case 59:return"GENERICTYPE";case 60:this.begin("generic");break;case 62:return"BQUOTE_STR";case 63:this.begin("bqstring");break;case 64:case 65:case 66:case 67:return 75;case 68:case 69:return 67;case 70:case 71:return 69;case 72:return 68;case 73:return 66;case 74:return 70;case 75:return 71;case 76:return 72;case 77:return 22;case 78:return 44;case 79:return 99;case 80:return 17;case 81:return"PLUS";case 82:return 85;case 83:return 59;case 84:case 85:return 88;case 86:return 89;case 87:case 88:return"EQUALS";case 89:return 58;case 90:return 12;case 91:return 14;case 92:return"PUNCTUATION";case 93:return 84;case 94:return 101;case 95:case 96:return 87;case 97:return 9}}),"anonymous"),rules:[/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:\[\*\])/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:["])/,/^(?:[^"]*)/,/^(?:["])/,/^(?:style\b)/,/^(?:classDef\b)/,/^(?:namespace\b)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:[{])/,/^(?:[}])/,/^(?:$)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:\[\*\])/,/^(?:class\b)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:[}])/,/^(?:[{])/,/^(?:[}])/,/^(?:$)/,/^(?:\[\*\])/,/^(?:[{])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:note for\b)/,/^(?:note\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:href\b)/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:~)/,/^(?:[`])/,/^(?:[^`]+)/,/^(?:[`])/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:\s*\(\))/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?::)/,/^(?:,)/,/^(?:#)/,/^(?:#)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:\[)/,/^(?:\])/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\s)/,/^(?:\s)/,/^(?:$)/],conditions:{"namespace-body":{rules:[26,33,34,35,36,37,38,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},namespace:{rules:[26,29,30,31,32,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},"class-body":{rules:[26,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},class:{rules:[26,39,40,41,42,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},acc_descr_multiline:{rules:[11,12,26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},acc_descr:{rules:[9,26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},acc_title:{rules:[7,26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},callback_args:{rules:[22,23,26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},callback_name:{rules:[19,20,21,26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},href:{rules:[26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},struct:{rules:[26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},generic:{rules:[26,49,50,51,52,53,54,55,56,57,58,59,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},bqstring:{rules:[26,49,50,51,52,53,54,55,56,57,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},string:{rules:[24,25,26,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,94,95,97],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,8,10,13,14,15,16,17,18,26,27,28,29,38,49,50,51,52,53,54,55,56,57,60,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97],inclusive:!0}}}}();function rt(){this.yy={}}return ut.lexer=at,(0,a.K2)(rt,"Parser"),rt.prototype=ut,ut.Parser=rt,new rt}();o.parser=o;var l=o,c=["#","+","~","-",""],h=class{static{(0,a.K2)(this,"ClassMember")}constructor(t,e){this.memberType=e,this.visibility="",this.classifier="",this.text="";const s=(0,a.jZ)(t,(0,a.D7)());this.parseMember(s)}getDisplayDetails(){let t=this.visibility+(0,a.QO)(this.id);"method"===this.memberType&&(t+=`(${(0,a.QO)(this.parameters.trim())})`,this.returnType&&(t+=" : "+(0,a.QO)(this.returnType))),t=t.trim();return{displayText:t,cssStyle:this.parseClassifier()}}parseMember(t){let e="";if("method"===this.memberType){const s=/([#+~-])?(.+)\((.*)\)([\s$*])?(.*)([$*])?/.exec(t);if(s){const t=s[1]?s[1].trim():"";if(c.includes(t)&&(this.visibility=t),this.id=s[2],this.parameters=s[3]?s[3].trim():"",e=s[4]?s[4].trim():"",this.returnType=s[5]?s[5].trim():"",""===e){const t=this.returnType.substring(this.returnType.length-1);/[$*]/.exec(t)&&(e=t,this.returnType=this.returnType.substring(0,this.returnType.length-1))}}}else{const s=t.length,n=t.substring(0,1),i=t.substring(s-1);c.includes(n)&&(this.visibility=n),/[$*]/.exec(i)&&(e=i),this.id=t.substring(""===this.visibility?0:1,""===e?s:s-1)}this.classifier=e,this.id=this.id.startsWith(" ")?" "+this.id.trim():this.id.trim();const s=`${this.visibility?"\\"+this.visibility:""}${(0,a.QO)(this.id)}${"method"===this.memberType?`(${(0,a.QO)(this.parameters)})${this.returnType?" : "+(0,a.QO)(this.returnType):""}`:""}`;this.text=s.replaceAll("<","<").replaceAll(">",">"),this.text.startsWith("\\<")&&(this.text=this.text.replace("\\<","~"))}parseClassifier(){switch(this.classifier){case"*":return"font-style:italic;";case"$":return"text-decoration:underline;";default:return""}}},p="classId-",d=[],A=new Map,y=new Map,g=[],m=[],C=0,f=new Map,E=0,b=[],k=(0,a.K2)((t=>a.Y2.sanitizeText(t,(0,a.D7)())),"sanitizeText"),T=(0,a.K2)((function(t){const e=a.Y2.sanitizeText(t,(0,a.D7)());let s="",n=e;if(e.indexOf("~")>0){const t=e.split("~");n=k(t[0]),s=k(t[1])}return{className:n,type:s}}),"splitClassNameAndType"),D=(0,a.K2)((function(t,e){const s=a.Y2.sanitizeText(t,(0,a.D7)());e&&(e=k(e));const{className:n}=T(s);A.get(n).label=e,A.get(n).text=`${e}${A.get(n).type?`<${A.get(n).type}>`:""}`}),"setClassLabel"),F=(0,a.K2)((function(t){const e=a.Y2.sanitizeText(t,(0,a.D7)()),{className:s,type:n}=T(e);if(A.has(s))return;const i=a.Y2.sanitizeText(s,(0,a.D7)());A.set(i,{id:i,type:n,label:i,text:`${i}${n?`<${n}>`:""}`,shape:"classBox",cssClasses:"default",methods:[],members:[],annotations:[],styles:[],domId:p+i+"-"+C}),C++}),"addClass"),B=(0,a.K2)((function(t,e){const s={id:`interface${m.length}`,label:t,classId:e};m.push(s)}),"addInterface"),_=(0,a.K2)((function(t){const e=a.Y2.sanitizeText(t,(0,a.D7)());if(A.has(e))return A.get(e).domId;throw new Error("Class not found: "+e)}),"lookUpDomId"),S=(0,a.K2)((function(){d=[],A=new Map,g=[],m=[],(b=[]).push(j),f=new Map,E=0,V="TB",(0,a.IU)()}),"clear"),N=(0,a.K2)((function(t){return A.get(t)}),"getClass"),L=(0,a.K2)((function(){return A}),"getClasses"),$=(0,a.K2)((function(){return d}),"getRelations"),x=(0,a.K2)((function(){return g}),"getNotes"),O=(0,a.K2)((function(t){a.Rm.debug("Adding relation: "+JSON.stringify(t));const e=[X.LOLLIPOP,X.AGGREGATION,X.COMPOSITION,X.DEPENDENCY,X.EXTENSION];t.relation.type1!==X.LOLLIPOP||e.includes(t.relation.type2)?t.relation.type2!==X.LOLLIPOP||e.includes(t.relation.type1)?(F(t.id1),F(t.id2)):(F(t.id1),B(t.id2,t.id1),t.id2="interface"+(m.length-1)):(F(t.id2),B(t.id1,t.id2),t.id1="interface"+(m.length-1)),t.id1=T(t.id1).className,t.id2=T(t.id2).className,t.relationTitle1=a.Y2.sanitizeText(t.relationTitle1.trim(),(0,a.D7)()),t.relationTitle2=a.Y2.sanitizeText(t.relationTitle2.trim(),(0,a.D7)()),d.push(t)}),"addRelation"),v=(0,a.K2)((function(t,e){const s=T(t).className;A.get(s).annotations.push(e)}),"addAnnotation"),I=(0,a.K2)((function(t,e){F(t);const s=T(t).className,n=A.get(s);if("string"==typeof e){const t=e.trim();t.startsWith("<<")&&t.endsWith(">>")?n.annotations.push(k(t.substring(2,t.length-2))):t.indexOf(")")>0?n.methods.push(new h(t,"method")):t&&n.members.push(new h(t,"attribute"))}}),"addMember"),K=(0,a.K2)((function(t,e){Array.isArray(e)&&(e.reverse(),e.forEach((e=>I(t,e))))}),"addMembers"),w=(0,a.K2)((function(t,e){const s={id:`note${g.length}`,class:e,text:t};g.push(s)}),"addNote"),R=(0,a.K2)((function(t){return t.startsWith(":")&&(t=t.substring(1)),k(t.trim())}),"cleanupLabel"),P=(0,a.K2)((function(t,e){t.split(",").forEach((function(t){let s=t;/\d/.exec(t[0])&&(s=p+s);const n=A.get(s);n&&(n.cssClasses+=" "+e)}))}),"setCssClass"),M=(0,a.K2)((function(t,e){for(const s of t){let t=y.get(s);void 0===t&&(t={id:s,styles:[],textStyles:[]},y.set(s,t)),e&&e.forEach((function(e){if(/color/.exec(e)){const s=e.replace("fill","bgFill");t.textStyles.push(s)}t.styles.push(e)})),A.forEach((t=>{t.cssClasses.includes(s)&&t.styles.push(...e.flatMap((t=>t.split(","))))}))}}),"defineClass"),G=(0,a.K2)((function(t,e){t.split(",").forEach((function(t){void 0!==e&&(A.get(t).tooltip=k(e))}))}),"setTooltip"),U=(0,a.K2)((function(t,e){return e&&f.has(e)?f.get(e).classes.get(t).tooltip:A.get(t).tooltip}),"getTooltip"),Y=(0,a.K2)((function(t,e,s){const n=(0,a.D7)();t.split(",").forEach((function(t){let i=t;/\d/.exec(t[0])&&(i=p+i);const a=A.get(i);a&&(a.link=u._K.formatUrl(e,n),"sandbox"===n.securityLevel?a.linkTarget="_top":a.linkTarget="string"==typeof s?k(s):"_blank")})),P(t,"clickable")}),"setLink"),z=(0,a.K2)((function(t,e,s){t.split(",").forEach((function(t){Q(t,e,s),A.get(t).haveCallback=!0})),P(t,"clickable")}),"setClickEvent"),Q=(0,a.K2)((function(t,e,s){const n=a.Y2.sanitizeText(t,(0,a.D7)());if("loose"!==(0,a.D7)().securityLevel)return;if(void 0===e)return;const i=n;if(A.has(i)){const t=_(i);let n=[];if("string"==typeof s){n=s.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let t=0;t")),t.classed("hover",!0)})).on("mouseout",(function(){e.transition().duration(500).style("opacity",0);(0,r.Ltv)(this).classed("hover",!1)}))}),"setupToolTips");b.push(j);var V="TB",q=(0,a.K2)((()=>V),"getDirection"),H=(0,a.K2)((t=>{V=t}),"setDirection"),J=(0,a.K2)((function(t){f.has(t)||(f.set(t,{id:t,classes:new Map,children:{},domId:p+t+"-"+E}),E++)}),"addNamespace"),Z=(0,a.K2)((function(t){return f.get(t)}),"getNamespace"),tt=(0,a.K2)((function(){return f}),"getNamespaces"),et=(0,a.K2)((function(t,e){if(f.has(t))for(const s of e){const{className:e}=T(s);A.get(e).parent=t,f.get(t).classes.set(e,A.get(e))}}),"addClassesToNamespace"),st=(0,a.K2)((function(t,e){const s=A.get(t);if(e&&s)for(const n of e)n.includes(",")?s.styles.push(...n.split(",")):s.styles.push(n)}),"setCssStyle");function nt(t){let e;switch(t){case 0:e="aggregation";break;case 1:e="extension";break;case 2:e="composition";break;case 3:e="dependency";break;case 4:e="lollipop";break;default:e="none"}return e}(0,a.K2)(nt,"getArrowMarker");var it=(0,a.K2)((()=>{const t=[],e=[],s=(0,a.D7)();for(const i of f.keys()){const e=f.get(i);if(e){const n={id:e.id,label:e.id,isGroup:!0,padding:s.class.padding??16,shape:"rect",cssStyles:["fill: none","stroke: black"],look:s.look};t.push(n)}}for(const i of A.keys()){const e=A.get(i);if(e){const n=e;n.parentId=e.parent,n.look=s.look,t.push(n)}}let n=0;for(const i of g){n++;const u={id:i.id,label:i.text,isGroup:!1,shape:"note",padding:s.class.padding??6,cssStyles:["text-align: left","white-space: nowrap",`fill: ${s.themeVariables.noteBkgColor}`,`stroke: ${s.themeVariables.noteBorderColor}`],look:s.look};t.push(u);const a=A.get(i.class)?.id??"";if(a){const t={id:`edgeNote${n}`,start:i.id,end:a,type:"normal",thickness:"normal",classes:"relation",arrowTypeStart:"none",arrowTypeEnd:"none",arrowheadStyle:"",labelStyle:[""],style:["fill: none"],pattern:"dotted",look:s.look};e.push(t)}}for(const i of m){const e={id:i.id,label:i.label,isGroup:!1,shape:"rect",cssStyles:["opacity: 0;"],look:s.look};t.push(e)}n=0;for(const i of d){n++;const t={id:(0,u.rY)(i.id1,i.id2,{prefix:"id",counter:n}),start:i.id1,end:i.id2,type:"normal",label:i.title,labelpos:"c",thickness:"normal",classes:"relation",arrowTypeStart:nt(i.relation.type1),arrowTypeEnd:nt(i.relation.type2),startLabelRight:"none"===i.relationTitle1?"":i.relationTitle1,endLabelLeft:"none"===i.relationTitle2?"":i.relationTitle2,arrowheadStyle:"",labelStyle:["display: inline-block"],style:i.style||"",pattern:1==i.relation.lineType?"dashed":"solid",look:s.look};e.push(t)}return{nodes:t,edges:e,other:{},config:s,direction:q()}}),"getData"),ut={setAccTitle:a.SV,getAccTitle:a.iN,getAccDescription:a.m7,setAccDescription:a.EI,getConfig:(0,a.K2)((()=>(0,a.D7)().class),"getConfig"),addClass:F,bindFunctions:W,clear:S,getClass:N,getClasses:L,getNotes:x,addAnnotation:v,addNote:w,getRelations:$,addRelation:O,getDirection:q,setDirection:H,addMember:I,addMembers:K,cleanupLabel:R,lineType:{LINE:0,DOTTED_LINE:1},relationType:X,setClickEvent:z,setCssClass:P,defineClass:M,setLink:Y,getTooltip:U,setTooltip:G,lookUpDomId:_,setDiagramTitle:a.ke,getDiagramTitle:a.ab,setClassLabel:D,addNamespace:J,addClassesToNamespace:et,getNamespace:Z,getNamespaces:tt,setCssStyle:st,getData:it},at=(0,a.K2)((t=>`g.classGroup text {\n fill: ${t.nodeBorder||t.classText};\n stroke: none;\n font-family: ${t.fontFamily};\n font-size: 10px;\n\n .title {\n font-weight: bolder;\n }\n\n}\n\n.nodeLabel, .edgeLabel {\n color: ${t.classText};\n}\n.edgeLabel .label rect {\n fill: ${t.mainBkg};\n}\n.label text {\n fill: ${t.classText};\n}\n\n.labelBkg {\n background: ${t.mainBkg};\n}\n.edgeLabel .label span {\n background: ${t.mainBkg};\n}\n\n.classTitle {\n font-weight: bolder;\n}\n.node rect,\n .node circle,\n .node ellipse,\n .node polygon,\n .node path {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n stroke-width: 1px;\n }\n\n\n.divider {\n stroke: ${t.nodeBorder};\n stroke-width: 1;\n}\n\ng.clickable {\n cursor: pointer;\n}\n\ng.classGroup rect {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n}\n\ng.classGroup line {\n stroke: ${t.nodeBorder};\n stroke-width: 1;\n}\n\n.classLabel .box {\n stroke: none;\n stroke-width: 0;\n fill: ${t.mainBkg};\n opacity: 0.5;\n}\n\n.classLabel .label {\n fill: ${t.nodeBorder};\n font-size: 10px;\n}\n\n.relation {\n stroke: ${t.lineColor};\n stroke-width: 1;\n fill: none;\n}\n\n.dashed-line{\n stroke-dasharray: 3;\n}\n\n.dotted-line{\n stroke-dasharray: 1 2;\n}\n\n#compositionStart, .composition {\n fill: ${t.lineColor} !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#compositionEnd, .composition {\n fill: ${t.lineColor} !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#dependencyStart, .dependency {\n fill: ${t.lineColor} !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#dependencyStart, .dependency {\n fill: ${t.lineColor} !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#extensionStart, .extension {\n fill: transparent !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#extensionEnd, .extension {\n fill: transparent !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#aggregationStart, .aggregation {\n fill: transparent !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#aggregationEnd, .aggregation {\n fill: transparent !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#lollipopStart, .lollipop {\n fill: ${t.mainBkg} !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n#lollipopEnd, .lollipop {\n fill: ${t.mainBkg} !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n}\n\n.edgeTerminals {\n font-size: 11px;\n line-height: initial;\n}\n\n.classTitleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.textColor};\n}\n`),"getStyles"),rt=(0,a.K2)(((t,e="TB")=>{if(!t.doc)return e;let s=e;for(const n of t.doc)"dir"===n.stmt&&(s=n.value);return s}),"getDir"),ot={getClasses:(0,a.K2)((function(t,e){return e.db.getClasses()}),"getClasses"),draw:(0,a.K2)((async function(t,e,s,r){a.Rm.info("REF0:"),a.Rm.info("Drawing class diagram (v3)",e);const{securityLevel:o,state:l,layout:c}=(0,a.D7)(),h=r.db.getData(),p=(0,n.A)(e,o);h.type=r.type,h.layoutAlgorithm=(0,i.q7)(c),h.nodeSpacing=l?.nodeSpacing||50,h.rankSpacing=l?.rankSpacing||50,h.markers=["aggregation","extension","composition","dependency","lollipop"],h.diagramId=e,await(0,i.XX)(h,p);u._K.insertTitle(p,"classDiagramTitleText",l?.titleTopMargin??25,r.db.getDiagramTitle()),(0,n.P)(p,8,"classDiagram",l?.useMaxWidth??!0)}),"draw"),getDir:rt}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/14a9ce33.ad4e3471.js b/pr-preview/pr-1071/assets/js/14a9ce33.ad4e3471.js deleted file mode 100644 index 62a9cd1bc2..0000000000 --- a/pr-preview/pr-1071/assets/js/14a9ce33.ad4e3471.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7924],{50499:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-0.8/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/architecture/attestation.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.8/components/service-mesh"},"next":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/secrets"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(55732).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(15601).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nOn AMD SEV-SNP the hash of the policy is then added to the attestation report via the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field by the hypervisor.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(92084).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},92084:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},15601:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},55732:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/14eb3368.65875b1f.js b/pr-preview/pr-1071/assets/js/14eb3368.65875b1f.js deleted file mode 100644 index da6b8575df..0000000000 --- a/pr-preview/pr-1071/assets/js/14eb3368.65875b1f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6969],{44168:(e,t,n)=>{n.d(t,{A:()=>g});n(96540);var s=n(34164),r=n(18630),i=n(45357),a=n(80260),l=n(14783),o=n(23230),c=n(98180),d=n(74848);function u(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,d.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const m={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function h(){const e=(0,c.Ay)("/");return(0,d.jsx)("li",{className:"breadcrumbs__item",children:(0,d.jsx)(l.A,{"aria-label":(0,o.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,d.jsx)(u,{className:m.breadcrumbHomeIcon})})})}const b={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function x(e){let{children:t,href:n,isLast:s}=e;const r="breadcrumbs__link";return s?(0,d.jsx)("span",{className:r,itemProp:"name",children:t}):n?(0,d.jsx)(l.A,{className:r,href:n,itemProp:"item",children:(0,d.jsx)("span",{itemProp:"name",children:t})}):(0,d.jsx)("span",{className:r,children:t})}function p(e){let{children:t,active:n,index:r,addMicrodata:i}=e;return(0,d.jsxs)("li",{...i&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},className:(0,s.A)("breadcrumbs__item",{"breadcrumbs__item--active":n}),children:[t,(0,d.jsx)("meta",{itemProp:"position",content:String(r+1)})]})}function g(){const e=(0,i.OF)(),t=(0,a.Dt)();return e?(0,d.jsx)("nav",{className:(0,s.A)(r.G.docs.docBreadcrumbs,b.breadcrumbsContainer),"aria-label":(0,o.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,d.jsxs)("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList",children:[t&&(0,d.jsx)(h,{}),e.map(((t,n)=>{const s=n===e.length-1,r="category"===t.type&&t.linkUnlisted?void 0:t.href;return(0,d.jsx)(p,{active:s,index:n,addMicrodata:!!r,children:(0,d.jsx)(x,{href:r,isLast:s,children:t.label})},n)}))]})}):null}},44074:(e,t,n)=>{n.d(t,{A:()=>_});var s=n(96540),r=n(34164),i=n(45357),a=n(14783),l=n(97639);const o=["zero","one","two","few","many","other"];function c(e){return o.filter((t=>e.includes(t)))}const d={locale:"en",pluralForms:c(["one","other"]),select:e=>1===e?"one":"other"};function u(){const{i18n:{currentLocale:e}}=(0,l.A)();return(0,s.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:c(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),d}}),[e])}function m(){const e=u();return{selectMessage:(t,n)=>function(e,t,n){const s=e.split("|");if(1===s.length)return s[0];s.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${s.length}: ${e}`);const r=n.select(t),i=n.pluralForms.indexOf(r);return s[Math.min(i,s.length-1)]}(n,t,e)}}var h=n(40877),b=n(23230),x=n(85225);const p={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=n(74848);function v(e){let{href:t,children:n}=e;return(0,g.jsx)(a.A,{href:t,className:(0,r.A)("card padding--lg",p.cardContainer),children:n})}function f(e){let{href:t,icon:n,title:s,description:i}=e;return(0,g.jsxs)(v,{href:t,children:[(0,g.jsxs)(x.A,{as:"h2",className:(0,r.A)("text--truncate",p.cardTitle),title:s,children:[n," ",s]}),i&&(0,g.jsx)("p",{className:(0,r.A)("text--truncate",p.cardDescription),title:i,children:i})]})}function j(e){let{item:t}=e;const n=(0,i.Nr)(t),s=function(){const{selectMessage:e}=m();return t=>e(t,(0,b.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,g.jsx)(f,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??s(t.items.length)}):null}function A(e){let{item:t}=e;const n=(0,h.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",s=(0,i.cC)(t.docId??void 0);return(0,g.jsx)(f,{href:t.href,icon:n,title:t.label,description:t.description??s?.description})}function N(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(A,{item:t});case"category":return(0,g.jsx)(j,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function T(e){let{className:t}=e;const n=(0,i.$S)();return(0,g.jsx)(_,{items:n.items,className:t})}function _(e){const{items:t,className:n}=e;if(!t)return(0,g.jsx)(T,{...e});const s=(0,i.d1)(t);return(0,g.jsx)("section",{className:(0,r.A)("row",n),children:s.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(N,{item:e})},t)))})}},97449:(e,t,n)=>{n.r(t),n.d(t,{default:()=>p});n(96540);var s=n(69817),r=n(45357),i=n(98180),a=n(44074),l=n(62400),o=n(84799),c=n(79436),d=n(44168),u=n(85225);const m={generatedIndexPage:"generatedIndexPage_vN6x",list:"list_eTzJ",title:"title_kItE"};var h=n(74848);function b(e){let{categoryGeneratedIndex:t}=e;return(0,h.jsx)(s.be,{title:t.title,description:t.description,keywords:t.keywords,image:(0,i.Ay)(t.image)})}function x(e){let{categoryGeneratedIndex:t}=e;const n=(0,r.$S)();return(0,h.jsxs)("div",{className:m.generatedIndexPage,children:[(0,h.jsx)(o.A,{}),(0,h.jsx)(d.A,{}),(0,h.jsx)(c.A,{}),(0,h.jsxs)("header",{children:[(0,h.jsx)(u.A,{as:"h1",className:m.title,children:t.title}),t.description&&(0,h.jsx)("p",{children:t.description})]}),(0,h.jsx)("article",{className:"margin-top--lg",children:(0,h.jsx)(a.A,{items:n.items,className:m.list})}),(0,h.jsx)("footer",{className:"margin-top--lg",children:(0,h.jsx)(l.A,{previous:t.navigation.previous,next:t.navigation.next})})]})}function p(e){return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(b,{...e}),(0,h.jsx)(x,{...e})]})}},62400:(e,t,n)=>{n.d(t,{A:()=>o});n(96540);var s=n(23230),r=n(34164),i=n(14783),a=n(74848);function l(e){const{permalink:t,title:n,subLabel:s,isNext:l}=e;return(0,a.jsxs)(i.A,{className:(0,r.A)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t,children:[s&&(0,a.jsx)("div",{className:"pagination-nav__sublabel",children:s}),(0,a.jsx)("div",{className:"pagination-nav__label",children:n})]})}function o(e){const{previous:t,next:n}=e;return(0,a.jsxs)("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,s.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[t&&(0,a.jsx)(l,{...t,subLabel:(0,a.jsx)(s.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),n&&(0,a.jsx)(l,{...n,subLabel:(0,a.jsx)(s.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}},79436:(e,t,n)=>{n.d(t,{A:()=>o});n(96540);var s=n(34164),r=n(23230),i=n(18630),a=n(91704),l=n(74848);function o(e){let{className:t}=e;const n=(0,a.r)();return n.badge?(0,l.jsx)("span",{className:(0,s.A)(t,i.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,l.jsx)(r.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label},children:"Version: {versionLabel}"})}):null}},84799:(e,t,n)=>{n.d(t,{A:()=>p});n(96540);var s=n(34164),r=n(97639),i=n(14783),a=n(23230),l=n(19802),o=n(18630),c=n(86457),d=n(91704),u=n(74848);const m={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return(0,u.jsx)(a.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:(0,u.jsx)("b",{children:n.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return(0,u.jsx)(a.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:(0,u.jsx)("b",{children:n.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function h(e){const t=m[e.versionMetadata.banner];return(0,u.jsx)(t,{...e})}function b(e){let{versionLabel:t,to:n,onClick:s}=e;return(0,u.jsx)(a.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:(0,u.jsx)("b",{children:(0,u.jsx)(i.A,{to:n,onClick:s,children:(0,u.jsx)(a.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function x(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:i}}=(0,r.A)(),{pluginId:a}=(0,l.vT)({failfast:!0}),{savePreferredVersionName:d}=(0,c.g1)(a),{latestDocSuggestion:m,latestVersionSuggestion:x}=(0,l.HW)(a),p=m??(g=x).docs.find((e=>e.id===g.mainDocId));var g;return(0,u.jsxs)("div",{className:(0,s.A)(t,o.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,u.jsx)("div",{children:(0,u.jsx)(h,{siteTitle:i,versionMetadata:n})}),(0,u.jsx)("div",{className:"margin-top--md",children:(0,u.jsx)(b,{versionLabel:x.label,to:p.path,onClick:()=>d(x.name)})})]})}function p(e){let{className:t}=e;const n=(0,d.r)();return n.banner?(0,u.jsx)(x,{className:t,versionMetadata:n}):null}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/15b9bf06.8dd25a08.js b/pr-preview/pr-1071/assets/js/15b9bf06.8dd25a08.js deleted file mode 100644 index af6ba811a2..0000000000 --- a/pr-preview/pr-1071/assets/js/15b9bf06.8dd25a08.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5388],{12988:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>i,metadata:()=>r,toc:()=>d});const r=JSON.parse('{"id":"architecture/confidential-containers","title":"confidential-containers","description":"","source":"@site/versioned_docs/version-0.5/architecture/confidential-containers.md","sourceDirName":"architecture","slug":"/architecture/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/confidential-containers.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"CLI","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.5/category/attestation"}}');var o=n(74848),c=n(28453);const i={},s=void 0,a={},d=[];function u(t){return(0,o.jsx)(o.Fragment,{})}function l(t={}){const{wrapper:e}={...(0,c.R)(),...t.components};return e?(0,o.jsx)(e,{...t,children:(0,o.jsx)(u,{...t})}):u()}},28453:(t,e,n)=>{n.d(e,{R:()=>i,x:()=>s});var r=n(96540);const o={},c=r.createContext(o);function i(t){const e=r.useContext(c);return r.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function s(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:i(t.components),r.createElement(c.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/165.786b0b5b.js b/pr-preview/pr-1071/assets/js/165.786b0b5b.js deleted file mode 100644 index 37d705ad9b..0000000000 --- a/pr-preview/pr-1071/assets/js/165.786b0b5b.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 165.786b0b5b.js.LICENSE.txt */ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[165],{90165:(e,t,n)=>{function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,o=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return o=e.done,e},e:function(e){s=!0,i=e},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw i}}}}n.d(t,{A:()=>Xc});var h="undefined"==typeof window?null:window,p=h?h.navigator:null;h&&h.document;var f=r(""),g=r({}),v=r((function(){})),y="undefined"==typeof HTMLElement?"undefined":r(HTMLElement),m=function(e){return e&&e.instanceString&&x(e.instanceString)?e.instanceString():null},b=function(e){return null!=e&&r(e)==f},x=function(e){return null!=e&&r(e)===v},w=function(e){return!S(e)&&(Array.isArray?Array.isArray(e):null!=e&&e instanceof Array)},E=function(e){return null!=e&&r(e)===g&&!w(e)&&e.constructor===Object},k=function(e){return null!=e&&r(e)===r(1)&&!isNaN(e)},C=function(e){return"undefined"===y?void 0:null!=e&&e instanceof HTMLElement},S=function(e){return P(e)||D(e)},P=function(e){return"collection"===m(e)&&e._private.single},D=function(e){return"collection"===m(e)&&!e._private.single},T=function(e){return"core"===m(e)},_=function(e){return"stylesheet"===m(e)},M=function(e){return null==e||!(""!==e&&!e.match(/^\s+$/))},B=function(e){return function(e){return null!=e&&r(e)===g}(e)&&x(e.then)},N=function(e,t){t||(t=function(){if(1===arguments.length)return arguments[0];if(0===arguments.length)return"undefined";for(var e=[],t=0;tt?1:0},Y=null!=Object.assign?Object.assign.bind(Object):function(e){for(var t=arguments,n=1;n255)return;t.push(Math.floor(i))}var o=r[1]||r[2]||r[3],s=r[1]&&r[2]&&r[3];if(o&&!s)return;var l=n[4];if(void 0!==l){if((l=parseFloat(l))<0||l>1)return;t.push(l)}}return t}(e)||function(e){var t,n,r,a,i,o,s,l;function u(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e}var c=new RegExp("^"+F+"$").exec(e);if(c){if((n=parseInt(c[1]))<0?n=(360- -1*n%360)%360:n>360&&(n%=360),n/=360,(r=parseFloat(c[2]))<0||r>100)return;if(r/=100,(a=parseFloat(c[3]))<0||a>100)return;if(a/=100,void 0!==(i=c[4])&&((i=parseFloat(i))<0||i>1))return;if(0===r)o=s=l=Math.round(255*a);else{var d=a<.5?a*(1+r):a+r-a*r,h=2*a-d;o=Math.round(255*u(h,d,n+1/3)),s=Math.round(255*u(h,d,n)),l=Math.round(255*u(h,d,n-1/3))}t=[o,s,l,i]}return t}(e)},W={transparent:[0,0,0,0],aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],grey:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},H=function(e){for(var t=e.map,n=e.keys,r=n.length,a=0;a=t||n<0||d&&e-u>=i}function g(){var e=J();if(f(e))return v(e);s=setTimeout(g,function(e){var n=t-(e-l);return d?Ee(n,i-(e-u)):n}(e))}function v(e){return s=void 0,h&&r?p(e):(r=a=void 0,o)}function y(){var e=J(),n=f(e);if(r=arguments,a=this,l=e,n){if(void 0===s)return function(e){return u=e,s=setTimeout(g,t),c?p(e):o}(l);if(d)return clearTimeout(s),s=setTimeout(g,t),p(l)}return void 0===s&&(s=setTimeout(g,t)),o}return t=xe(t)||0,G(n)&&(c=!!n.leading,i=(d="maxWait"in n)?we(xe(n.maxWait)||0,t):i,h="trailing"in n?!!n.trailing:h),y.cancel=function(){void 0!==s&&clearTimeout(s),u=0,r=l=a=s=void 0},y.flush=function(){return void 0===s?o:v(J())},y},Ce=h?h.performance:null,Se=Ce&&Ce.now?function(){return Ce.now()}:function(){return Date.now()},Pe=function(){if(h){if(h.requestAnimationFrame)return function(e){h.requestAnimationFrame(e)};if(h.mozRequestAnimationFrame)return function(e){h.mozRequestAnimationFrame(e)};if(h.webkitRequestAnimationFrame)return function(e){h.webkitRequestAnimationFrame(e)};if(h.msRequestAnimationFrame)return function(e){h.msRequestAnimationFrame(e)}}return function(e){e&&setTimeout((function(){e(Se())}),1e3/60)}}(),De=function(e){return Pe(e)},Te=Se,_e=9261,Me=5381,Be=function(e){for(var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:_e;!(t=e.next()).done;)n=65599*n+t.value|0;return n},Ne=function(e){return 65599*(arguments.length>1&&void 0!==arguments[1]?arguments[1]:_e)+e|0},Ie=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Me;return(t<<5)+t+e|0},ze=function(e){return 2097152*e[0]+e[1]},Ae=function(e,t){return[Ne(e[0],t[0]),Ie(e[1],t[1])]},Le=function(e,t){var n={value:0,done:!1},r=0,a=e.length;return Be({next:function(){return r=0&&(e[r]!==t||(e.splice(r,1),!n));r--);},nt=function(e){e.splice(0,e.length)},rt=function(e,t,n){return n&&(t=A(n,t)),e[t]},at=function(e,t,n,r){n&&(t=A(n,t)),e[t]=r},it="undefined"!=typeof Map?Map:function(){function e(){a(this,e),this._obj={}}return o(e,[{key:"set",value:function(e,t){return this._obj[e]=t,this}},{key:"delete",value:function(e){return this._obj[e]=void 0,this}},{key:"clear",value:function(){this._obj={}}},{key:"has",value:function(e){return void 0!==this._obj[e]}},{key:"get",value:function(e){return this._obj[e]}}]),e}(),ot=function(){function e(t){if(a(this,e),this._obj=Object.create(null),this.size=0,null!=t){var n;n=null!=t.instanceString&&t.instanceString()===this.instanceString()?t.toArray():t;for(var r=0;r2&&void 0!==arguments[2])||arguments[2];if(void 0!==e&&void 0!==t&&T(e)){var r=t.group;if(null==r&&(r=t.data&&null!=t.data.source&&null!=t.data.target?"edges":"nodes"),"nodes"===r||"edges"===r){this.length=1,this[0]=this;var a=this._private={cy:e,single:!0,data:t.data||{},position:t.position||{x:0,y:0},autoWidth:void 0,autoHeight:void 0,autoPadding:void 0,compoundBoundsClean:!1,listeners:[],group:r,style:{},rstyle:{},styleCxts:[],styleKeys:{},removed:!0,selected:!!t.selected,selectable:void 0===t.selectable||!!t.selectable,locked:!!t.locked,grabbed:!1,grabbable:void 0===t.grabbable||!!t.grabbable,pannable:void 0===t.pannable?"edges"===r:!!t.pannable,active:!1,classes:new st,animation:{current:[],queue:[]},rscratch:{},scratch:t.scratch||{},edges:[],children:[],parent:t.parent&&t.parent.isNode()?t.parent:null,traversalCache:{},backgrounding:!1,bbCache:null,bbCacheShift:{x:0,y:0},bodyBounds:null,overlayBounds:null,labelBounds:{all:null,source:null,target:null,main:null},arrowBounds:{source:null,target:null,"mid-source":null,"mid-target":null}};if(null==a.position.x&&(a.position.x=0),null==a.position.y&&(a.position.y=0),t.renderedPosition){var i=t.renderedPosition,o=e.pan(),s=e.zoom();a.position={x:(i.x-o.x)/s,y:(i.y-o.y)/s}}var l=[];w(t.classes)?l=t.classes:b(t.classes)&&(l=t.classes.split(/\s+/));for(var u=0,c=l.length;ut?1:0},u=function(e,t,a,i,o){var s;if(null==a&&(a=0),null==o&&(o=n),a<0)throw new Error("lo must be non-negative");for(null==i&&(i=e.length);an;0<=n?t++:t--)u.push(t);return u}.apply(this).reverse()).length;ig;0<=g?++h:--h)v.push(i(e,r));return v},f=function(e,t,r,a){var i,o,s;for(null==a&&(a=n),i=e[r];r>t&&a(i,o=e[s=r-1>>1])<0;)e[r]=o,r=s;return e[r]=i},g=function(e,t,r){var a,i,o,s,l;for(null==r&&(r=n),i=e.length,l=t,o=e[t],a=2*t+1;a0;){var k=y.pop(),C=g(k),S=k.id();if(d[S]=C,C!==1/0)for(var P=k.neighborhood().intersect(p),D=0;D0)for(n.unshift(t);c[a];){var i=c[a];n.unshift(i.edge),n.unshift(i.node),a=(r=i.node).id()}return o.spawn(n)}}}},gt={kruskal:function(e){e=e||function(e){return 1};for(var t=this.byGroup(),n=t.nodes,r=t.edges,a=n.length,i=new Array(a),o=n,s=function(e){for(var t=0;t0;){if(l=g.pop(),u=l.id(),v.delete(u),w++,u===d){for(var E=[],k=a,C=d,S=m[C];E.unshift(k),null!=S&&E.unshift(S),null!=(k=y[C]);)S=m[C=k.id()];return{found:!0,distance:h[u],path:this.spawn(E),steps:w}}f[u]=!0;for(var P=l._private.edges,D=0;DD&&(p[P]=D,y[P]=S,m[P]=w),!a){var T=S*u+C;!a&&p[T]>D&&(p[T]=D,y[T]=C,m[T]=w)}}}for(var _=0;_1&&void 0!==arguments[1]?arguments[1]:i,r=[],a=m(e);;){if(null==a)return t.spawn();var o=y(a),l=o.edge,u=o.pred;if(r.unshift(a[0]),a.same(n)&&r.length>0)break;null!=l&&r.unshift(l),a=u}return s.spawn(r)},hasNegativeWeightCycle:f,negativeWeightCycles:g}}},Et=Math.sqrt(2),kt=function(e,t,n){0===n.length&&Ke("Karger-Stein must be run on a connected (sub)graph");for(var r=n[e],a=r[1],i=r[2],o=t[a],s=t[i],l=n,u=l.length-1;u>=0;u--){var c=l[u],d=c[1],h=c[2];(t[d]===o&&t[h]===s||t[d]===s&&t[h]===o)&&l.splice(u,1)}for(var p=0;pr;){var a=Math.floor(Math.random()*t.length);t=kt(a,e,t),n--}return t},St={kargerStein:function(){var e=this,t=this.byGroup(),n=t.nodes,r=t.edges;r.unmergeBy((function(e){return e.isLoop()}));var a=n.length,i=r.length,o=Math.ceil(Math.pow(Math.log(a)/Math.LN2,2)),s=Math.floor(a/Et);if(!(a<2)){for(var l=[],u=0;u0?1:e<0?-1:0},Nt=function(e,t){return Math.sqrt(It(e,t))},It=function(e,t){var n=t.x-e.x,r=t.y-e.y;return n*n+r*r},zt=function(e){for(var t=e.length,n=0,r=0;r=e.x1&&e.y2>=e.y1)return{x1:e.x1,y1:e.y1,x2:e.x2,y2:e.y2,w:e.x2-e.x1,h:e.y2-e.y1};if(null!=e.w&&null!=e.h&&e.w>=0&&e.h>=0)return{x1:e.x1,y1:e.y1,x2:e.x1+e.w,y2:e.y1+e.h,w:e.w,h:e.h}}},Vt=function(e,t){e.x1=Math.min(e.x1,t.x1),e.x2=Math.max(e.x2,t.x2),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,t.y1),e.y2=Math.max(e.y2,t.y2),e.h=e.y2-e.y1},Ft=function(e,t,n){e.x1=Math.min(e.x1,t),e.x2=Math.max(e.x2,t),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,n),e.y2=Math.max(e.y2,n),e.h=e.y2-e.y1},jt=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e.x1-=t,e.x2+=t,e.y1-=t,e.y2+=t,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},qt=function(e){var t,n,r,a,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[0];if(1===i.length)t=n=r=a=i[0];else if(2===i.length)t=r=i[0],a=n=i[1];else if(4===i.length){var o=l(i,4);t=o[0],n=o[1],r=o[2],a=o[3]}return e.x1-=a,e.x2+=n,e.y1-=t,e.y2+=r,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},Yt=function(e,t){e.x1=t.x1,e.y1=t.y1,e.x2=t.x2,e.y2=t.y2,e.w=e.x2-e.x1,e.h=e.y2-e.y1},Xt=function(e,t){return!(e.x1>t.x2)&&(!(t.x1>e.x2)&&(!(e.x2t.y2)&&!(t.y1>e.y2)))))))},Wt=function(e,t,n){return e.x1<=t&&t<=e.x2&&e.y1<=n&&n<=e.y2},Ht=function(e,t){return Wt(e,t.x1,t.y1)&&Wt(e,t.x2,t.y2)},Kt=function(e,t,n,r,a,i,o){var s,l,u=arguments.length>7&&void 0!==arguments[7]?arguments[7]:"auto",c="auto"===u?hn(a,i):u,d=a/2,h=i/2,p=(c=Math.min(c,d,h))!==d,f=c!==h;if(p){var g=r-h-o;if((s=on(e,t,n,r,n-d+c-o,g,n+d-c+o,g,!1)).length>0)return s}if(f){var v=n+d+o;if((s=on(e,t,n,r,v,r-h+c-o,v,r+h-c+o,!1)).length>0)return s}if(p){var y=r+h+o;if((s=on(e,t,n,r,n-d+c-o,y,n+d-c+o,y,!1)).length>0)return s}if(f){var m=n-d-o;if((s=on(e,t,n,r,m,r-h+c-o,m,r+h-c+o,!1)).length>0)return s}var b=n-d+c,x=r-h+c;if((l=rn(e,t,n,r,b,x,c+o)).length>0&&l[0]<=b&&l[1]<=x)return[l[0],l[1]];var w=n+d-c,E=r-h+c;if((l=rn(e,t,n,r,w,E,c+o)).length>0&&l[0]>=w&&l[1]<=E)return[l[0],l[1]];var k=n+d-c,C=r+h-c;if((l=rn(e,t,n,r,k,C,c+o)).length>0&&l[0]>=k&&l[1]>=C)return[l[0],l[1]];var S=n-d+c,P=r+h-c;return(l=rn(e,t,n,r,S,P,c+o)).length>0&&l[0]<=S&&l[1]>=P?[l[0],l[1]]:[]},Gt=function(e,t,n,r,a,i,o){var s=o,l=Math.min(n,a),u=Math.max(n,a),c=Math.min(r,i),d=Math.max(r,i);return l-s<=e&&e<=u+s&&c-s<=t&&t<=d+s},Ut=function(e,t,n,r,a,i,o,s,l){var u=Math.min(n,o,a)-l,c=Math.max(n,o,a)+l,d=Math.min(r,s,i)-l,h=Math.max(r,s,i)+l;return!(ec||th)},Zt=function(e,t,n,r,a,i,o,s){var l=[];!function(e,t,n,r,a){var i,o,s,l,u,c,d,h;0===e&&(e=1e-5),s=-27*(r/=e)+(t/=e)*(9*(n/=e)-t*t*2),i=(o=(3*n-t*t)/9)*o*o+(s/=54)*s,a[1]=0,d=t/3,i>0?(u=(u=s+Math.sqrt(i))<0?-Math.pow(-u,1/3):Math.pow(u,1/3),c=(c=s-Math.sqrt(i))<0?-Math.pow(-c,1/3):Math.pow(c,1/3),a[0]=-d+u+c,d+=(u+c)/2,a[4]=a[2]=-d,d=Math.sqrt(3)*(-c+u)/2,a[3]=d,a[5]=-d):(a[5]=a[3]=0,0===i?(h=s<0?-Math.pow(-s,1/3):Math.pow(s,1/3),a[0]=2*h-d,a[4]=a[2]=-(h+d)):(l=(o=-o)*o*o,l=Math.acos(s/Math.sqrt(l)),h=2*Math.sqrt(o),a[0]=-d+h*Math.cos(l/3),a[2]=-d+h*Math.cos((l+2*Math.PI)/3),a[4]=-d+h*Math.cos((l+4*Math.PI)/3)))}(1*n*n-4*n*a+2*n*o+4*a*a-4*a*o+o*o+r*r-4*r*i+2*r*s+4*i*i-4*i*s+s*s,9*n*a-3*n*n-3*n*o-6*a*a+3*a*o+9*r*i-3*r*r-3*r*s-6*i*i+3*i*s,3*n*n-6*n*a+n*o-n*e+2*a*a+2*a*e-o*e+3*r*r-6*r*i+r*s-r*t+2*i*i+2*i*t-s*t,1*n*a-n*n+n*e-a*e+r*i-r*r+r*t-i*t,l);for(var u=[],c=0;c<6;c+=2)Math.abs(l[c+1])<1e-7&&l[c]>=0&&l[c]<=1&&u.push(l[c]);u.push(1),u.push(0);for(var d,h,p,f=-1,g=0;g=0?pl?(e-a)*(e-a)+(t-i)*(t-i):u-d},Qt=function(e,t,n){for(var r,a,i,o,s=0,l=0;l=e&&e>=i||r<=e&&e<=i))continue;(e-r)/(i-r)*(o-a)+a>t&&s++}return s%2!=0},Jt=function(e,t,n,r,a,i,o,s,l){var u,c=new Array(n.length);null!=s[0]?(u=Math.atan(s[1]/s[0]),s[0]<0?u+=Math.PI/2:u=-u-Math.PI/2):u=s;for(var d,h=Math.cos(-u),p=Math.sin(-u),f=0;f0){var g=tn(c,-l);d=en(g)}else d=c;return Qt(e,t,d)},en=function(e){for(var t,n,r,a,i,o,s,l,u=new Array(e.length/2),c=0;c=0&&f<=1&&v.push(f),g>=0&&g<=1&&v.push(g),0===v.length)return[];var y=v[0]*s[0]+e,m=v[0]*s[1]+t;return v.length>1?v[0]==v[1]?[y,m]:[y,m,v[1]*s[0]+e,v[1]*s[1]+t]:[y,m]},an=function(e,t,n){return t<=e&&e<=n||n<=e&&e<=t?e:e<=t&&t<=n||n<=t&&t<=e?t:n},on=function(e,t,n,r,a,i,o,s,l){var u=e-a,c=n-e,d=o-a,h=t-i,p=r-t,f=s-i,g=d*h-f*u,v=c*h-p*u,y=f*c-d*p;if(0!==y){var m=g/y,b=v/y,x=-.001;return x<=m&&m<=1.001&&x<=b&&b<=1.001||l?[e+m*c,t+m*p]:[]}return 0===g||0===v?an(e,n,o)===o?[o,s]:an(e,n,a)===a?[a,i]:an(a,o,n)===n?[n,r]:[]:[]},sn=function(e,t,n,r,a,i,o,s){var l,u,c,d,h,p,f=[],g=new Array(n.length),v=!0;if(null==i&&(v=!1),v){for(var y=0;y0){var m=tn(g,-s);u=en(m)}else u=g}else u=n;for(var b=0;bu&&(u=t)},d=function(e){return l[e]},h=0;h0?b.edgesTo(m)[0]:m.edgesTo(b)[0];var w=r(x);m=m.id(),h[m]>h[v]+w&&(h[m]=h[v]+w,p.nodes.indexOf(m)<0?p.push(m):p.updateItem(m),u[m]=0,l[m]=[]),h[m]==h[v]+w&&(u[m]=u[m]+u[v],l[m].push(v))}else for(var E=0;E0;){for(var P=n.pop(),D=0;D0&&o.push(n[s]);0!==o.length&&a.push(r.collection(o))}return a}(c,l,t,r);return b=function(e){for(var t=0;t5&&void 0!==arguments[5]?arguments[5]:In,o=r,s=0;s=2?Vn(e,t,n,0,Ln,On):Vn(e,t,n,0,An)},squaredEuclidean:function(e,t,n){return Vn(e,t,n,0,Ln)},manhattan:function(e,t,n){return Vn(e,t,n,0,An)},max:function(e,t,n){return Vn(e,t,n,-1/0,Rn)}};function jn(e,t,n,r,a,i){var o;return o=x(e)?e:Fn[e]||Fn.euclidean,0===t&&x(e)?o(a,i):o(t,n,r,a,i)}Fn["squared-euclidean"]=Fn.squaredEuclidean,Fn.squaredeuclidean=Fn.squaredEuclidean;var qn=et({k:2,m:2,sensitivityThreshold:1e-4,distance:"euclidean",maxIterations:10,attributes:[],testMode:!1,testCentroids:null}),Yn=function(e){return qn(e)},Xn=function(e,t,n,r,a){var i="kMedoids"!==a?function(e){return n[e]}:function(e){return r[e](n)},o=n,s=t;return jn(e,r.length,i,(function(e){return r[e](t)}),o,s)},Wn=function(e,t,n){for(var r=n.length,a=new Array(r),i=new Array(r),o=new Array(t),s=null,l=0;ln)return!1}return!0},Zn=function(e,t,n){for(var r=0;ra&&(a=t[l][u],i=u);o[i].push(e[l])}for(var c=0;c=a.threshold||"dendrogram"===a.mode&&1===e.length)return!1;var p,f=t[o],g=t[r[o]];p="dendrogram"===a.mode?{left:f,right:g,key:f.key}:{value:f.value.concat(g.value),key:f.key},e[f.index]=p,e.splice(g.index,1),t[f.key]=p;for(var v=0;vn[g.key][y.key]&&(i=n[g.key][y.key])):"max"===a.linkage?(i=n[f.key][y.key],n[f.key][y.key]1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length,r=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],a=!(arguments.length>5&&void 0!==arguments[5])||arguments[5];arguments.length>3&&void 0!==arguments[3]&&!arguments[3]?(n0&&e.splice(0,t)):e=e.slice(t,n);for(var i=0,o=e.length-1;o>=0;o--){var s=e[o];a?isFinite(s)||(e[o]=-1/0,i++):e.splice(o,1)}r&&e.sort((function(e,t){return e-t}));var l=e.length,u=Math.floor(l/2);return l%2!=0?e[u+1+i]:(e[u-1+i]+e[u+i])/2}(e):"mean"===t?function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length,r=0,a=0,i=t;i1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length,r=1/0,a=t;a1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length,r=-1/0,a=t;ao&&(i=l,o=t[a*e+l])}i>0&&r.push(i)}for(var u=0;u=D?(T=D,D=M,_=B):M>T&&(T=M);for(var N=0;N0?1:0;C[E%u.minIterations*t+R]=V,O+=V}if(O>0&&(E>=u.minIterations-1||E==u.maxIterations-1)){for(var F=0,j=0;j0&&r.push(a);return r}(t,i,o),X=function(e,t,n){for(var r=fr(e,t,n),a=0;al&&(s=u,l=c)}n[a]=i[s]}return fr(e,t,n)}(t,r,Y),W={},H=0;H1||o>1)&&(u=!0),c[t]=[],e.outgoers().forEach((function(e){e.isEdge()&&c[t].push(e.id())}))}else d[t]=[void 0,e.target().id()]})):l.forEach((function(e){var t=e.id();e.isNode()?(e.degree(!0)%2&&(n?r?u=!0:r=t:n=t),c[t]=[],e.connectedEdges().forEach((function(e){return c[t].push(e.id())}))):d[t]=[e.source().id(),e.target().id()]}));var h={found:!1,trail:void 0};if(u)return h;if(r&&n)if(s){if(a&&r!=a)return h;a=r}else{if(a&&r!=a&&n!=a)return h;a||(a=r)}else a||(a=l[0].id());var p=function(e){for(var t,n,r,a=e,i=[e];c[a].length;)t=c[a].shift(),n=d[t][0],a!=(r=d[t][1])?(c[r]=c[r].filter((function(e){return e!=t})),a=r):s||a==n||(c[n]=c[n].filter((function(e){return e!=t})),a=n),i.unshift(t),i.unshift(a);return i},f=[],g=[];for(g=p(a);1!=g.length;)0==c[g[0]].length?(f.unshift(l.getElementById(g.shift())),f.unshift(l.getElementById(g.shift()))):g=p(g.shift()).concat(g);for(var v in f.unshift(l.getElementById(g.shift())),c)if(c[v].length)return h;return h.found=!0,h.trail=this.spawn(f,!0),h}},br=function(){var e=this,t={},n=0,r=0,a=[],i=[],o={},s=function s(l,u,c){l===c&&(r+=1),t[u]={id:n,low:n++,cutVertex:!1};var d,h,p,f,g=e.getElementById(u).connectedEdges().intersection(e);0===g.size()?a.push(e.spawn(e.getElementById(u))):g.forEach((function(n){d=n.source().id(),h=n.target().id(),(p=d===u?h:d)!==c&&(f=n.id(),o[f]||(o[f]=!0,i.push({x:u,y:p,edge:n})),p in t?t[u].low=Math.min(t[u].low,t[p].id):(s(l,p,u),t[u].low=Math.min(t[u].low,t[p].low),t[u].id<=t[p].low&&(t[u].cutVertex=!0,function(n,r){for(var o=i.length-1,s=[],l=e.spawn();i[o].x!=n||i[o].y!=r;)s.push(i.pop().edge),o--;s.push(i.pop().edge),s.forEach((function(n){var r=n.connectedNodes().intersection(e);l.merge(n),r.forEach((function(n){var r=n.id(),a=n.connectedEdges().intersection(e);l.merge(n),t[r].cutVertex?l.merge(a.filter((function(e){return e.isLoop()}))):l.merge(a)}))})),a.push(l)}(u,p))))}))};e.forEach((function(e){if(e.isNode()){var n=e.id();n in t||(r=0,s(n,n),t[n].cutVertex=r>1)}}));var l=Object.keys(t).filter((function(e){return t[e].cutVertex})).map((function(t){return e.getElementById(t)}));return{cut:e.spawn(l),components:a}},xr=function(){var e=this,t={},n=0,r=[],a=[],i=e.spawn(e),o=function o(s){if(a.push(s),t[s]={index:n,low:n++,explored:!1},e.getElementById(s).connectedEdges().intersection(e).forEach((function(e){var n=e.target().id();n!==s&&(n in t||o(n),t[n].explored||(t[s].low=Math.min(t[s].low,t[n].low)))})),t[s].index===t[s].low){for(var l=e.spawn();;){var u=a.pop();if(l.merge(e.getElementById(u)),t[u].low=t[s].index,t[u].explored=!0,u===s)break}var c=l.edgesWith(l),d=l.merge(c);r.push(d),i=i.difference(d)}};return e.forEach((function(e){if(e.isNode()){var n=e.id();n in t||o(n)}})),{cut:i,components:r}},wr={};[ct,ft,gt,yt,bt,wt,St,vn,mn,xn,En,Nn,nr,cr,vr,mr,{hopcroftTarjanBiconnected:br,htbc:br,htb:br,hopcroftTarjanBiconnectedComponents:br},{tarjanStronglyConnected:xr,tsc:xr,tscc:xr,tarjanStronglyConnectedComponents:xr}].forEach((function(e){Y(wr,e)}));var Er=function e(t){if(!(this instanceof e))return new e(t);this.id="Thenable/1.0.7",this.state=0,this.fulfillValue=void 0,this.rejectReason=void 0,this.onFulfilled=[],this.onRejected=[],this.proxy={then:this.then.bind(this)},"function"==typeof t&&t.call(this,this.fulfill.bind(this),this.reject.bind(this))};Er.prototype={fulfill:function(e){return kr(this,1,"fulfillValue",e)},reject:function(e){return kr(this,2,"rejectReason",e)},then:function(e,t){var n=this,r=new Er;return n.onFulfilled.push(Pr(e,r,"fulfill")),n.onRejected.push(Pr(t,r,"reject")),Cr(n),r.proxy}};var kr=function(e,t,n,r){return 0===e.state&&(e.state=t,e[n]=r,Cr(e)),e},Cr=function(e){1===e.state?Sr(e,"onFulfilled",e.fulfillValue):2===e.state&&Sr(e,"onRejected",e.rejectReason)},Sr=function(e,t,n){if(0!==e[t].length){var r=e[t];e[t]=[];var a=function(){for(var e=0;e0:void 0}},clearQueue:function(){return function(){var e=this,t=void 0!==e.length?e:[e];if(!(this._private.cy||this).styleEnabled())return this;for(var n=0;n-1};var ga=function(e,t){var n=this.__data__,r=ca(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this};function va(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e0&&this.spawn(r).updateStyle().emit("class"),t},addClass:function(e){return this.toggleClass(e,!0)},hasClass:function(e){var t=this[0];return null!=t&&t._private.classes.has(e)},toggleClass:function(e,t){w(e)||(e=e.match(/\S+/g)||[]);for(var n=this,r=void 0===t,a=[],i=0,o=n.length;i0&&this.spawn(a).updateStyle().emit("class"),n},removeClass:function(e){return this.toggleClass(e,!1)},flashClass:function(e,t){var n=this;if(null==t)t=250;else if(0===t)return n;return n.addClass(e),setTimeout((function(){n.removeClass(e)}),t),n}};ai.className=ai.classNames=ai.classes;var ii={metaChar:"[\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]",comparatorOp:"=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=",boolOp:"\\?|\\!|\\^",string:"\"(?:\\\\\"|[^\"])*\"|'(?:\\\\'|[^'])*'",number:O,meta:"degree|indegree|outdegree",separator:"\\s*,\\s*",descendant:"\\s+",child:"\\s+>\\s+",subject:"\\$",group:"node|edge|\\*",directedEdge:"\\s+->\\s+",undirectedEdge:"\\s+<->\\s+"};ii.variable="(?:[\\w-.]|(?:\\\\"+ii.metaChar+"))+",ii.className="(?:[\\w-]|(?:\\\\"+ii.metaChar+"))+",ii.value=ii.string+"|"+ii.number,ii.id=ii.variable,function(){var e,t,n;for(e=ii.comparatorOp.split("|"),n=0;n=0||"="!==t&&(ii.comparatorOp+="|\\!"+t)}();var oi=0,si=1,li=2,ui=3,ci=4,di=5,hi=6,pi=7,fi=8,gi=9,vi=10,yi=11,mi=12,bi=13,xi=14,wi=15,Ei=16,ki=17,Ci=18,Si=19,Pi=20,Di=[{selector:":selected",matches:function(e){return e.selected()}},{selector:":unselected",matches:function(e){return!e.selected()}},{selector:":selectable",matches:function(e){return e.selectable()}},{selector:":unselectable",matches:function(e){return!e.selectable()}},{selector:":locked",matches:function(e){return e.locked()}},{selector:":unlocked",matches:function(e){return!e.locked()}},{selector:":visible",matches:function(e){return e.visible()}},{selector:":hidden",matches:function(e){return!e.visible()}},{selector:":transparent",matches:function(e){return e.transparent()}},{selector:":grabbed",matches:function(e){return e.grabbed()}},{selector:":free",matches:function(e){return!e.grabbed()}},{selector:":removed",matches:function(e){return e.removed()}},{selector:":inside",matches:function(e){return!e.removed()}},{selector:":grabbable",matches:function(e){return e.grabbable()}},{selector:":ungrabbable",matches:function(e){return!e.grabbable()}},{selector:":animated",matches:function(e){return e.animated()}},{selector:":unanimated",matches:function(e){return!e.animated()}},{selector:":parent",matches:function(e){return e.isParent()}},{selector:":childless",matches:function(e){return e.isChildless()}},{selector:":child",matches:function(e){return e.isChild()}},{selector:":orphan",matches:function(e){return e.isOrphan()}},{selector:":nonorphan",matches:function(e){return e.isChild()}},{selector:":compound",matches:function(e){return e.isNode()?e.isParent():e.source().isParent()||e.target().isParent()}},{selector:":loop",matches:function(e){return e.isLoop()}},{selector:":simple",matches:function(e){return e.isSimple()}},{selector:":active",matches:function(e){return e.active()}},{selector:":inactive",matches:function(e){return!e.active()}},{selector:":backgrounding",matches:function(e){return e.backgrounding()}},{selector:":nonbackgrounding",matches:function(e){return!e.backgrounding()}}].sort((function(e,t){return function(e,t){return-1*q(e,t)}(e.selector,t.selector)})),Ti=function(){for(var e,t={},n=0;n0&&u.edgeCount>0)return Ue("The selector `"+e+"` is invalid because it uses both a compound selector and an edge selector"),!1;if(u.edgeCount>1)return Ue("The selector `"+e+"` is invalid because it uses multiple edge selectors"),!1;1===u.edgeCount&&Ue("The selector `"+e+"` is deprecated. Edge selectors do not take effect on changes to source and target nodes after an edge is added, for performance reasons. Use a class or data selector on edges instead, updating the class or data of an edge when your app detects a change in source or target nodes.")}return!0},toString:function(){if(null!=this.toStringCache)return this.toStringCache;for(var e=function(e){return null==e?"":e},t=function(t){return b(t)?'"'+t+'"':e(t)},n=function(e){return" "+e+" "},r=function(r,i){var o=r.type,s=r.value;switch(o){case oi:var l=e(s);return l.substring(0,l.length-1);case ui:var u=r.field,c=r.operator;return"["+u+n(e(c))+t(s)+"]";case di:var d=r.operator,h=r.field;return"["+e(d)+h+"]";case ci:return"["+r.field+"]";case hi:var p=r.operator;return"[["+r.field+n(e(p))+t(s)+"]]";case pi:return s;case fi:return"#"+s;case gi:return"."+s;case ki:case wi:return a(r.parent,i)+n(">")+a(r.child,i);case Ci:case Ei:return a(r.ancestor,i)+" "+a(r.descendant,i);case Si:var f=a(r.left,i),g=a(r.subject,i),v=a(r.right,i);return f+(f.length>0?" ":"")+g+v;case Pi:return""}},a=function(e,t){return e.checks.reduce((function(n,a,i){return n+(t===e&&0===i?"$":"")+r(a,t)}),"")},i="",o=0;o1&&o=0&&(t=t.replace("!",""),c=!0),t.indexOf("@")>=0&&(t=t.replace("@",""),u=!0),(o||l||u)&&(a=o||s?""+e:"",i=""+n),u&&(e=a=a.toLowerCase(),n=i=i.toLowerCase()),t){case"*=":r=a.indexOf(i)>=0;break;case"$=":r=a.indexOf(i,a.length-i.length)>=0;break;case"^=":r=0===a.indexOf(i);break;case"=":r=e===n;break;case">":d=!0,r=e>n;break;case">=":d=!0,r=e>=n;break;case"<":d=!0,r=e0;){var u=a.shift();t(u),i.add(u.id()),o&&r(a,i,u)}return e}function Gi(e,t,n){if(n.isParent())for(var r=n._private.children,a=0;a1&&void 0!==arguments[1])||arguments[1],Gi)},Hi.forEachUp=function(e){return Ki(this,e,!(arguments.length>1&&void 0!==arguments[1])||arguments[1],Ui)},Hi.forEachUpAndDown=function(e){return Ki(this,e,!(arguments.length>1&&void 0!==arguments[1])||arguments[1],Zi)},Hi.ancestors=Hi.parents,(Yi=Xi={data:ni.data({field:"data",bindingEvent:"data",allowBinding:!0,allowSetting:!0,settingEvent:"data",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),removeData:ni.removeData({field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),scratch:ni.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeScratch:ni.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0}),rscratch:ni.data({field:"rscratch",allowBinding:!1,allowSetting:!0,settingTriggersEvent:!1,allowGetting:!0}),removeRscratch:ni.removeData({field:"rscratch",triggerEvent:!1}),id:function(){var e=this[0];if(e)return e._private.data.id}}).attr=Yi.data,Yi.removeAttr=Yi.removeData;var $i,Qi,Ji=Xi,eo={};function to(e){return function(t){var n=this;if(void 0===t&&(t=!0),0!==n.length&&n.isNode()&&!n.removed()){for(var r=0,a=n[0],i=a._private.edges,o=0;ot})),minIndegree:no("indegree",(function(e,t){return et})),minOutdegree:no("outdegree",(function(e,t){return et}))}),Y(eo,{totalDegree:function(e){for(var t=0,n=this.nodes(),r=0;r0,c=u;u&&(l=l[0]);var d=c?l.position():{x:0,y:0};return a={x:s.x-d.x,y:s.y-d.y},void 0===e?a:a[e]}for(var h=0;h0,v=g;g&&(f=f[0]);var y=v?f.position():{x:0,y:0};void 0!==t?p.position(e,t+y[e]):void 0!==a&&p.position({x:a.x+y.x,y:a.y+y.y})}}else if(!i)return;return this}},$i.modelPosition=$i.point=$i.position,$i.modelPositions=$i.points=$i.positions,$i.renderedPoint=$i.renderedPosition,$i.relativePoint=$i.relativePosition;var io,oo,so=Qi;io=oo={},oo.renderedBoundingBox=function(e){var t=this.boundingBox(e),n=this.cy(),r=n.zoom(),a=n.pan(),i=t.x1*r+a.x,o=t.x2*r+a.x,s=t.y1*r+a.y,l=t.y2*r+a.y;return{x1:i,x2:o,y1:s,y2:l,w:o-i,h:l-s}},oo.dirtyCompoundBoundsCache=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=this.cy();return t.styleEnabled()&&t.hasCompoundNodes()?(this.forEachUp((function(t){if(t.isParent()){var n=t._private;n.compoundBoundsClean=!1,n.bbCache=null,e||t.emitAndNotify("bounds")}})),this):this},oo.updateCompoundBounds=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=this.cy();if(!t.styleEnabled()||!t.hasCompoundNodes())return this;if(!e&&t.batching())return this;function n(e){if(e.isParent()){var t=e._private,n=e.children(),r="include"===e.pstyle("compound-sizing-wrt-labels").value,a={width:{val:e.pstyle("min-width").pfValue,left:e.pstyle("min-width-bias-left"),right:e.pstyle("min-width-bias-right")},height:{val:e.pstyle("min-height").pfValue,top:e.pstyle("min-height-bias-top"),bottom:e.pstyle("min-height-bias-bottom")}},i=n.boundingBox({includeLabels:r,includeOverlays:!1,useCache:!1}),o=t.position;0!==i.w&&0!==i.h||((i={w:e.pstyle("width").pfValue,h:e.pstyle("height").pfValue}).x1=o.x-i.w/2,i.x2=o.x+i.w/2,i.y1=o.y-i.h/2,i.y2=o.y+i.h/2);var s=a.width.left.value;"px"===a.width.left.units&&a.width.val>0&&(s=100*s/a.width.val);var l=a.width.right.value;"px"===a.width.right.units&&a.width.val>0&&(l=100*l/a.width.val);var u=a.height.top.value;"px"===a.height.top.units&&a.height.val>0&&(u=100*u/a.height.val);var c=a.height.bottom.value;"px"===a.height.bottom.units&&a.height.val>0&&(c=100*c/a.height.val);var d=y(a.width.val-i.w,s,l),h=d.biasDiff,p=d.biasComplementDiff,f=y(a.height.val-i.h,u,c),g=f.biasDiff,v=f.biasComplementDiff;t.autoPadding=function(e,t,n,r){if("%"!==n.units)return"px"===n.units?n.pfValue:0;switch(r){case"width":return e>0?n.pfValue*e:0;case"height":return t>0?n.pfValue*t:0;case"average":return e>0&&t>0?n.pfValue*(e+t)/2:0;case"min":return e>0&&t>0?e>t?n.pfValue*t:n.pfValue*e:0;case"max":return e>0&&t>0?e>t?n.pfValue*e:n.pfValue*t:0;default:return 0}}(i.w,i.h,e.pstyle("padding"),e.pstyle("padding-relative-to").value),t.autoWidth=Math.max(i.w,a.width.val),o.x=(-h+i.x1+i.x2+p)/2,t.autoHeight=Math.max(i.h,a.height.val),o.y=(-g+i.y1+i.y2+v)/2}function y(e,t,n){var r=0,a=0,i=t+n;return e>0&&i>0&&(r=t/i*e,a=n/i*e),{biasDiff:r,biasComplementDiff:a}}}for(var r=0;re.x2?r:e.x2,e.y1=ne.y2?a:e.y2,e.w=e.x2-e.x1,e.h=e.y2-e.y1)},co=function(e,t){return null==t?e:uo(e,t.x1,t.y1,t.x2,t.y2)},ho=function(e,t,n){return rt(e,t,n)},po=function(e,t,n){if(!t.cy().headless()){var r,a,i=t._private,o=i.rstyle,s=o.arrowWidth/2;if("none"!==t.pstyle(n+"-arrow-shape").value){"source"===n?(r=o.srcX,a=o.srcY):"target"===n?(r=o.tgtX,a=o.tgtY):(r=o.midX,a=o.midY);var l=i.arrowBounds=i.arrowBounds||{},u=l[n]=l[n]||{};u.x1=r-s,u.y1=a-s,u.x2=r+s,u.y2=a+s,u.w=u.x2-u.x1,u.h=u.y2-u.y1,jt(u,1),uo(e,u.x1,u.y1,u.x2,u.y2)}}},fo=function(e,t,n){if(!t.cy().headless()){var r;r=n?n+"-":"";var a=t._private,i=a.rstyle;if(t.pstyle(r+"label").strValue){var o,s,l,u,c=t.pstyle("text-halign"),d=t.pstyle("text-valign"),h=ho(i,"labelWidth",n),p=ho(i,"labelHeight",n),f=ho(i,"labelX",n),g=ho(i,"labelY",n),v=t.pstyle(r+"text-margin-x").pfValue,y=t.pstyle(r+"text-margin-y").pfValue,m=t.isEdge(),b=t.pstyle(r+"text-rotation"),x=t.pstyle("text-outline-width").pfValue,w=t.pstyle("text-border-width").pfValue/2,E=t.pstyle("text-background-padding").pfValue,k=p,C=h,S=C/2,P=k/2;if(m)o=f-S,s=f+S,l=g-P,u=g+P;else{switch(c.value){case"left":o=f-C,s=f;break;case"center":o=f-S,s=f+S;break;case"right":o=f,s=f+C}switch(d.value){case"top":l=g-k,u=g;break;case"center":l=g-P,u=g+P;break;case"bottom":l=g,u=g+k}}var D=v-Math.max(x,w)-E-2,T=v+Math.max(x,w)+E+2,_=y-Math.max(x,w)-E-2,M=y+Math.max(x,w)+E+2;o+=D,s+=T,l+=_,u+=M;var B=n||"main",N=a.labelBounds,I=N[B]=N[B]||{};I.x1=o,I.y1=l,I.x2=s,I.y2=u,I.w=s-o,I.h=u-l,I.leftPad=D,I.rightPad=T,I.topPad=_,I.botPad=M;var z=m&&"autorotate"===b.strValue,A=null!=b.pfValue&&0!==b.pfValue;if(z||A){var L=z?ho(a.rstyle,"labelAngle",n):b.pfValue,O=Math.cos(L),R=Math.sin(L),V=(o+s)/2,F=(l+u)/2;if(!m){switch(c.value){case"left":V=s;break;case"right":V=o}switch(d.value){case"top":F=u;break;case"bottom":F=l}}var j=function(e,t){return{x:(e-=V)*O-(t-=F)*R+V,y:e*R+t*O+F}},q=j(o,l),Y=j(o,u),X=j(s,l),W=j(s,u);o=Math.min(q.x,Y.x,X.x,W.x),s=Math.max(q.x,Y.x,X.x,W.x),l=Math.min(q.y,Y.y,X.y,W.y),u=Math.max(q.y,Y.y,X.y,W.y)}var H=B+"Rot",K=N[H]=N[H]||{};K.x1=o,K.y1=l,K.x2=s,K.y2=u,K.w=s-o,K.h=u-l,uo(e,o,l,s,u),uo(a.labelBounds.all,o,l,s,u)}return e}},go=function(e,t){var n,r,a,i,o,s,l,u=e._private.cy,c=u.styleEnabled(),d=u.headless(),h=Rt(),p=e._private,f=e.isNode(),g=e.isEdge(),v=p.rstyle,y=f&&c?e.pstyle("bounds-expansion").pfValue:[0],m=function(e){return"none"!==e.pstyle("display").value},b=!c||m(e)&&(!g||m(e.source())&&m(e.target()));if(b){var x=0;c&&t.includeOverlays&&0!==e.pstyle("overlay-opacity").value&&(x=e.pstyle("overlay-padding").value);var w=0;c&&t.includeUnderlays&&0!==e.pstyle("underlay-opacity").value&&(w=e.pstyle("underlay-padding").value);var E=Math.max(x,w),k=0;if(c&&(k=e.pstyle("width").pfValue/2),f&&t.includeNodes){var C=e.position();o=C.x,s=C.y;var S=e.outerWidth()/2,P=e.outerHeight()/2;uo(h,n=o-S,a=s-P,r=o+S,i=s+P),c&&t.includeOutlines&&function(e,t){if(!t.cy().headless()){var n,r,a,i=t.pstyle("outline-opacity").value,o=t.pstyle("outline-width").value;if(i>0&&o>0){var s=t.pstyle("outline-offset").value,l=t.pstyle("shape").value,u=o+s,c=(e.w+2*u)/e.w,d=(e.h+2*u)/e.h,h=0;["diamond","pentagon","round-triangle"].includes(l)?(c=(e.w+2.4*u)/e.w,h=-u/3.6):["concave-hexagon","rhomboid","right-rhomboid"].includes(l)?c=(e.w+2.4*u)/e.w:"star"===l?(c=(e.w+2.8*u)/e.w,d=(e.h+2.6*u)/e.h,h=-u/3.8):"triangle"===l?(c=(e.w+2.8*u)/e.w,d=(e.h+2.4*u)/e.h,h=-u/1.4):"vee"===l&&(c=(e.w+4.4*u)/e.w,d=(e.h+3.8*u)/e.h,h=.5*-u);var p=e.h*d-e.h,f=e.w*c-e.w;if(qt(e,[Math.ceil(p/2),Math.ceil(f/2)]),0!==h){var g=(r=0,a=h,{x1:(n=e).x1+r,x2:n.x2+r,y1:n.y1+a,y2:n.y2+a,w:n.w,h:n.h});Vt(e,g)}}}}(h,e)}else if(g&&t.includeEdges)if(c&&!d){var D=e.pstyle("curve-style").strValue;if(n=Math.min(v.srcX,v.midX,v.tgtX),r=Math.max(v.srcX,v.midX,v.tgtX),a=Math.min(v.srcY,v.midY,v.tgtY),i=Math.max(v.srcY,v.midY,v.tgtY),uo(h,n-=k,a-=k,r+=k,i+=k),"haystack"===D){var T=v.haystackPts;if(T&&2===T.length){if(n=T[0].x,a=T[0].y,n>(r=T[1].x)){var _=n;n=r,r=_}if(a>(i=T[1].y)){var M=a;a=i,i=M}uo(h,n-k,a-k,r+k,i+k)}}else if("bezier"===D||"unbundled-bezier"===D||D.endsWith("segments")||D.endsWith("taxi")){var B;switch(D){case"bezier":case"unbundled-bezier":B=v.bezierPts;break;case"segments":case"taxi":case"round-segments":case"round-taxi":B=v.linePts}if(null!=B)for(var N=0;N(r=A.x)){var L=n;n=r,r=L}if((a=z.y)>(i=A.y)){var O=a;a=i,i=O}uo(h,n-=k,a-=k,r+=k,i+=k)}if(c&&t.includeEdges&&g&&(po(h,e,"mid-source"),po(h,e,"mid-target"),po(h,e,"source"),po(h,e,"target")),c)if("yes"===e.pstyle("ghost").value){var R=e.pstyle("ghost-offset-x").pfValue,V=e.pstyle("ghost-offset-y").pfValue;uo(h,h.x1+R,h.y1+V,h.x2+R,h.y2+V)}var F=p.bodyBounds=p.bodyBounds||{};Yt(F,h),qt(F,y),jt(F,1),c&&(n=h.x1,r=h.x2,a=h.y1,i=h.y2,uo(h,n-E,a-E,r+E,i+E));var j=p.overlayBounds=p.overlayBounds||{};Yt(j,h),qt(j,y),jt(j,1);var q=p.labelBounds=p.labelBounds||{};null!=q.all?((l=q.all).x1=1/0,l.y1=1/0,l.x2=-1/0,l.y2=-1/0,l.w=0,l.h=0):q.all=Rt(),c&&t.includeLabels&&(t.includeMainLabels&&fo(h,e,null),g&&(t.includeSourceLabels&&fo(h,e,"source"),t.includeTargetLabels&&fo(h,e,"target")))}return h.x1=lo(h.x1),h.y1=lo(h.y1),h.x2=lo(h.x2),h.y2=lo(h.y2),h.w=lo(h.x2-h.x1),h.h=lo(h.y2-h.y1),h.w>0&&h.h>0&&b&&(qt(h,y),jt(h,1)),h},vo=function(e){var t=0,n=function(e){return(e?1:0)<0&&void 0!==arguments[0]?arguments[0]:Lo,t=arguments.length>1?arguments[1]:void 0,n=0;n=0;s--)o(s);return this},Ro.removeAllListeners=function(){return this.removeListener("*")},Ro.emit=Ro.trigger=function(e,t,n){var r=this.listeners,a=r.length;return this.emitting++,w(t)||(t=[t]),jo(this,(function(e,i){null!=n&&(r=[{event:i.event,type:i.type,namespace:i.namespace,callback:n}],a=r.length);for(var o=function(n){var a=r[n];if(a.type===i.type&&(!a.namespace||a.namespace===i.namespace||".*"===a.namespace)&&e.eventMatches(e.context,a,i)){var o=[i];null!=t&&function(e,t){for(var n=0;n1&&!r){var a=this.length-1,i=this[a],o=i._private.data.id;this[a]=void 0,this[e]=i,n.set(o,{ele:i,index:e})}return this.length--,this},unmergeOne:function(e){e=e[0];var t=this._private,n=e._private.data.id,r=t.map.get(n);if(!r)return this;var a=r.index;return this.unmergeAt(a),this},unmerge:function(e){var t=this._private.cy;if(!e)return this;if(e&&b(e)){var n=e;e=t.mutableElements().filter(n)}for(var r=0;r=0;t--){e(this[t])&&this.unmergeAt(t)}return this},map:function(e,t){for(var n=[],r=this,a=0;ar&&(r=s,n=o)}return{value:r,ele:n}},min:function(e,t){for(var n,r=1/0,a=this,i=0;i=0&&a1&&void 0!==arguments[1])||arguments[1],n=this[0],r=n.cy();if(r.styleEnabled()&&n){this.cleanStyle();var a=n._private.style[e];return null!=a?a:t?r.style().getDefaultProperty(e):null}},numericStyle:function(e){var t=this[0];if(t.cy().styleEnabled()&&t){var n=t.pstyle(e);return void 0!==n.pfValue?n.pfValue:n.value}},numericStyleUnits:function(e){var t=this[0];if(t.cy().styleEnabled())return t?t.pstyle(e).units:void 0},renderedStyle:function(e){var t=this.cy();if(!t.styleEnabled())return this;var n=this[0];return n?t.style().getRenderedStyle(n,e):void 0},style:function(e,t){var n=this.cy();if(!n.styleEnabled())return this;var r=!1,a=n.style();if(E(e)){var i=e;a.applyBypass(this,i,r),this.emitAndNotify("style")}else if(b(e)){if(void 0===t){var o=this[0];return o?a.getStylePropertyValue(o,e):void 0}a.applyBypass(this,e,t,r),this.emitAndNotify("style")}else if(void 0===e){var s=this[0];return s?a.getRawStyle(s):void 0}return this},removeStyle:function(e){var t=this.cy();if(!t.styleEnabled())return this;var n=!1,r=t.style(),a=this;if(void 0===e)for(var i=0;i0&&t.push(c[0]),t.push(s[0])}return this.spawn(t,!0).filter(e)}),"neighborhood"),closedNeighborhood:function(e){return this.neighborhood().add(this).filter(e)},openNeighborhood:function(e){return this.neighborhood(e)}}),hs.neighbourhood=hs.neighborhood,hs.closedNeighbourhood=hs.closedNeighborhood,hs.openNeighbourhood=hs.openNeighborhood,Y(hs,{source:Wi((function(e){var t,n=this[0];return n&&(t=n._private.source||n.cy().collection()),t&&e?t.filter(e):t}),"source"),target:Wi((function(e){var t,n=this[0];return n&&(t=n._private.target||n.cy().collection()),t&&e?t.filter(e):t}),"target"),sources:vs({attr:"source"}),targets:vs({attr:"target"})}),Y(hs,{edgesWith:Wi(ys(),"edgesWith"),edgesTo:Wi(ys({thisIsSrc:!0}),"edgesTo")}),Y(hs,{connectedEdges:Wi((function(e){for(var t=[],n=0;n0);return i},component:function(){var e=this[0];return e.cy().mutableElements().components(e)[0]}}),hs.componentsOf=hs.components;var bs=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(void 0!==e){var a=new it,i=!1;if(t){if(t.length>0&&E(t[0])&&!P(t[0])){i=!0;for(var o=[],s=new st,l=0,u=t.length;l0&&void 0!==arguments[0])||arguments[0],r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],a=this,i=a.cy(),o=i._private,s=[],l=[],u=0,c=a.length;u0){for(var O=e.length===a.length?a:new bs(i,e),R=0;R0&&void 0!==arguments[0])||arguments[0],t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=this,r=[],a={},i=n._private.cy;function o(e){var n=a[e.id()];t&&e.removed()||n||(a[e.id()]=!0,e.isNode()?(r.push(e),function(e){for(var t=e._private.edges,n=0;n0&&(e?k.emitAndNotify("remove"):t&&k.emit("remove"));for(var C=0;C=.001?function(t,r){for(var a=0;a<4;++a){var i=h(r,e,n);if(0===i)return r;r-=(d(r,e,n)-t)/i}return r}(t,o):0===l?o:function(t,r,a){var i,o,s=0;do{(i=d(o=r+(a-r)/2,e,n)-t)>0?a=o:r=o}while(Math.abs(i)>1e-7&&++s<10);return o}(t,r,r+a)}var f=!1;function g(){f=!0,e===t&&n===r||function(){for(var t=0;t<11;++t)s[t]=d(t*a,e,n)}()}var v=function(a){return f||g(),e===t&&n===r?a:0===a?0:1===a?1:d(p(a),t,r)};v.getControlPoints=function(){return[{x:e,y:t},{x:n,y:r}]};var y="generateBezier("+[e,t,n,r]+")";return v.toString=function(){return y},v}var ks=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,n,r){var a={x:t.x+r.dx*n,v:t.v+r.dv*n,tension:t.tension,friction:t.friction};return{dx:a.v,dv:e(a)}}function n(n,r){var a={dx:n.v,dv:e(n)},i=t(n,.5*r,a),o=t(n,.5*r,i),s=t(n,r,o),l=1/6*(a.dx+2*(i.dx+o.dx)+s.dx),u=1/6*(a.dv+2*(i.dv+o.dv)+s.dv);return n.x=n.x+l*r,n.v=n.v+u*r,n}return function e(t,r,a){var i,o,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,d=1e-4;for(t=parseFloat(t)||500,r=parseFloat(r)||20,a=a||null,l.tension=t,l.friction=r,o=(i=null!==a)?(c=e(t,r))/a*.016:.016;s=n(s||l,o),u.push(1+s.x),c+=16,Math.abs(s.x)>d&&Math.abs(s.v)>d;);return i?function(e){return u[e*(u.length-1)|0]}:c}}(),Cs=function(e,t,n,r){var a=Es(e,t,n,r);return function(e,t,n){return e+(t-e)*a(n)}},Ss={linear:function(e,t,n){return e+(t-e)*n},ease:Cs(.25,.1,.25,1),"ease-in":Cs(.42,0,1,1),"ease-out":Cs(0,0,.58,1),"ease-in-out":Cs(.42,0,.58,1),"ease-in-sine":Cs(.47,0,.745,.715),"ease-out-sine":Cs(.39,.575,.565,1),"ease-in-out-sine":Cs(.445,.05,.55,.95),"ease-in-quad":Cs(.55,.085,.68,.53),"ease-out-quad":Cs(.25,.46,.45,.94),"ease-in-out-quad":Cs(.455,.03,.515,.955),"ease-in-cubic":Cs(.55,.055,.675,.19),"ease-out-cubic":Cs(.215,.61,.355,1),"ease-in-out-cubic":Cs(.645,.045,.355,1),"ease-in-quart":Cs(.895,.03,.685,.22),"ease-out-quart":Cs(.165,.84,.44,1),"ease-in-out-quart":Cs(.77,0,.175,1),"ease-in-quint":Cs(.755,.05,.855,.06),"ease-out-quint":Cs(.23,1,.32,1),"ease-in-out-quint":Cs(.86,0,.07,1),"ease-in-expo":Cs(.95,.05,.795,.035),"ease-out-expo":Cs(.19,1,.22,1),"ease-in-out-expo":Cs(1,0,0,1),"ease-in-circ":Cs(.6,.04,.98,.335),"ease-out-circ":Cs(.075,.82,.165,1),"ease-in-out-circ":Cs(.785,.135,.15,.86),spring:function(e,t,n){if(0===n)return Ss.linear;var r=ks(e,t,n);return function(e,t,n){return e+(t-e)*r(n)}},"cubic-bezier":Cs};function Ps(e,t,n,r,a){if(1===r)return n;if(t===n)return n;var i=a(t,n,r);return null==e||((e.roundValue||e.color)&&(i=Math.round(i)),void 0!==e.min&&(i=Math.max(i,e.min)),void 0!==e.max&&(i=Math.min(i,e.max))),i}function Ds(e,t){return null!=e.pfValue||null!=e.value?null==e.pfValue||null!=t&&"%"===t.type.units?e.value:e.pfValue:e}function Ts(e,t,n,r,a){var i=null!=a?a.type:null;n<0?n=0:n>1&&(n=1);var o=Ds(e,a),s=Ds(t,a);if(k(o)&&k(s))return Ps(i,o,s,n,r);if(w(o)&&w(s)){for(var l=[],u=0;u0?("spring"===d&&h.push(o.duration),o.easingImpl=Ss[d].apply(null,h)):o.easingImpl=Ss[d]}var p,f=o.easingImpl;if(p=0===o.duration?1:(n-l)/o.duration,o.applying&&(p=o.progress),p<0?p=0:p>1&&(p=1),null==o.delay){var g=o.startPosition,v=o.position;if(v&&a&&!e.locked()){var y={};Ms(g.x,v.x)&&(y.x=Ts(g.x,v.x,p,f)),Ms(g.y,v.y)&&(y.y=Ts(g.y,v.y,p,f)),e.position(y)}var m=o.startPan,x=o.pan,w=i.pan,E=null!=x&&r;E&&(Ms(m.x,x.x)&&(w.x=Ts(m.x,x.x,p,f)),Ms(m.y,x.y)&&(w.y=Ts(m.y,x.y,p,f)),e.emit("pan"));var k=o.startZoom,C=o.zoom,S=null!=C&&r;S&&(Ms(k,C)&&(i.zoom=Ot(i.minZoom,Ts(k,C,p,f),i.maxZoom)),e.emit("zoom")),(E||S)&&e.emit("viewport");var P=o.style;if(P&&P.length>0&&a){for(var D=0;D=0;t--){(0,e[t])()}e.splice(0,e.length)},c=i.length-1;c>=0;c--){var d=i[c],h=d._private;h.stopped?(i.splice(c,1),h.hooked=!1,h.playing=!1,h.started=!1,u(h.frames)):(h.playing||h.applying)&&(h.playing&&h.applying&&(h.applying=!1),h.started||Bs(0,d,e),_s(t,d,e,n),h.applying&&(h.applying=!1),u(h.frames),null!=h.step&&h.step(e),d.completed()&&(i.splice(c,1),h.hooked=!1,h.playing=!1,h.started=!1,u(h.completes)),s=!0)}return n||0!==i.length||0!==o.length||r.push(t),s}for(var i=!1,o=0;o0?t.notify("draw",n):t.notify("draw")),n.unmerge(r),t.emit("step")}var Is={animate:ni.animate(),animation:ni.animation(),animated:ni.animated(),clearQueue:ni.clearQueue(),delay:ni.delay(),delayAnimation:ni.delayAnimation(),stop:ni.stop(),addToAnimationPool:function(e){this.styleEnabled()&&this._private.aniEles.merge(e)},stopAnimationLoop:function(){this._private.animationsRunning=!1},startAnimationLoop:function(){var e=this;if(e._private.animationsRunning=!0,e.styleEnabled()){var t=e.renderer();t&&t.beforeRender?t.beforeRender((function(t,n){Ns(n,e)}),t.beforeRenderPriorities.animations):function t(){e._private.animationsRunning&&De((function(n){Ns(n,e),t()}))}()}}},zs={qualifierCompare:function(e,t){return null==e||null==t?null==e&&null==t:e.sameText(t)},eventMatches:function(e,t,n){var r=t.qualifier;return null==r||e!==n.target&&P(n.target)&&r.matches(n.target)},addEventFields:function(e,t){t.cy=e,t.target=e},callbackContext:function(e,t,n){return null!=t.qualifier?n.target:e}},As=function(e){return b(e)?new Fi(e):e},Ls={createEmitter:function(){var e=this._private;return e.emitter||(e.emitter=new Oo(zs,this)),this},emitter:function(){return this._private.emitter},on:function(e,t,n){return this.emitter().on(e,As(t),n),this},removeListener:function(e,t,n){return this.emitter().removeListener(e,As(t),n),this},removeAllListeners:function(){return this.emitter().removeAllListeners(),this},one:function(e,t,n){return this.emitter().one(e,As(t),n),this},once:function(e,t,n){return this.emitter().one(e,As(t),n),this},emit:function(e,t){return this.emitter().emit(e,t),this},emitAndNotify:function(e,t){return this.emit(e),this.notify(e,t),this}};ni.eventAliasesOn(Ls);var Os={png:function(e){return e=e||{},this._private.renderer.png(e)},jpg:function(e){var t=this._private.renderer;return(e=e||{}).bg=e.bg||"#fff",t.jpg(e)}};Os.jpeg=Os.jpg;var Rs={layout:function(e){var t=this;if(null!=e)if(null!=e.name){var n=e.name,r=t.extension("layout",n);if(null!=r){var a;a=b(e.eles)?t.$(e.eles):null!=e.eles?e.eles:t.$();var i=new r(Y({},e,{cy:t,eles:a}));return i}Ke("No such layout `"+n+"` found. Did you forget to import it and `cytoscape.use()` it?")}else Ke("A `name` must be specified to make a layout");else Ke("Layout options must be specified to make a layout")}};Rs.createLayout=Rs.makeLayout=Rs.layout;var Vs={notify:function(e,t){var n=this._private;if(this.batching()){n.batchNotifications=n.batchNotifications||{};var r=n.batchNotifications[e]=n.batchNotifications[e]||this.collection();null!=t&&r.merge(t)}else if(n.notificationsEnabled){var a=this.renderer();!this.destroyed()&&a&&a.notify(e,t)}},notifications:function(e){var t=this._private;return void 0===e?t.notificationsEnabled:(t.notificationsEnabled=!!e,this)},noNotifications:function(e){this.notifications(!1),e(),this.notifications(!0)},batching:function(){return this._private.batchCount>0},startBatch:function(){var e=this._private;return null==e.batchCount&&(e.batchCount=0),0===e.batchCount&&(e.batchStyleEles=this.collection(),e.batchNotifications={}),e.batchCount++,this},endBatch:function(){var e=this._private;if(0===e.batchCount)return this;if(e.batchCount--,0===e.batchCount){e.batchStyleEles.updateStyle();var t=this.renderer();Object.keys(e.batchNotifications).forEach((function(n){var r=e.batchNotifications[n];r.empty()?t.notify(n):t.notify(n,r)}))}return this},batch:function(e){return this.startBatch(),e(),this.endBatch(),this},batchData:function(e){var t=this;return this.batch((function(){for(var n=Object.keys(e),r=0;r0;)t.removeChild(t.childNodes[0]);e._private.renderer=null,e.mutableElements().forEach((function(e){var t=e._private;t.rscratch={},t.rstyle={},t.animation.current=[],t.animation.queue=[]}))},onRender:function(e){return this.on("render",e)},offRender:function(e){return this.off("render",e)}};js.invalidateDimensions=js.resize;var qs={collection:function(e,t){return b(e)?this.$(e):S(e)?e.collection():w(e)?(t||(t={}),new bs(this,e,t.unique,t.removed)):new bs(this)},nodes:function(e){var t=this.$((function(e){return e.isNode()}));return e?t.filter(e):t},edges:function(e){var t=this.$((function(e){return e.isEdge()}));return e?t.filter(e):t},$:function(e){var t=this._private.elements;return e?t.filter(e):t.spawnSelf()},mutableElements:function(){return this._private.elements}};qs.elements=qs.filter=qs.$;var Ys={},Xs="t";Ys.apply=function(e){for(var t=this,n=t._private.cy.collection(),r=0;r0;if(h||d&&p){var f=void 0;h&&p||h?f=u.properties:p&&(f=u.mappedProperties);for(var g=0;g1&&(v=1),s.color){var w=a.valueMin[0],E=a.valueMax[0],C=a.valueMin[1],S=a.valueMax[1],P=a.valueMin[2],D=a.valueMax[2],T=null==a.valueMin[3]?1:a.valueMin[3],_=null==a.valueMax[3]?1:a.valueMax[3],M=[Math.round(w+(E-w)*v),Math.round(C+(S-C)*v),Math.round(P+(D-P)*v),Math.round(T+(_-T)*v)];n={bypass:a.bypass,name:a.name,value:M,strValue:"rgb("+M[0]+", "+M[1]+", "+M[2]+")"}}else{if(!s.number)return!1;var B=a.valueMin+(a.valueMax-a.valueMin)*v;n=this.parse(a.name,B,a.bypass,h)}if(!n)return g(),!1;n.mapping=a,a=n;break;case o.data:for(var N=a.field.split("."),I=d.data,z=0;z0&&i>0){for(var s={},l=!1,u=0;u0?e.delayAnimation(o).play().promise().then(t):t()})).then((function(){return e.animation({style:s,duration:i,easing:e.pstyle("transition-timing-function").value,queue:!1}).play().promise()})).then((function(){n.removeBypasses(e,a),e.emitAndNotify("style"),r.transitioning=!1}))}else r.transitioning&&(this.removeBypasses(e,a),e.emitAndNotify("style"),r.transitioning=!1)},Ys.checkTrigger=function(e,t,n,r,a,i){var o=this.properties[t],s=a(o);null!=s&&s(n,r)&&i(o)},Ys.checkZOrderTrigger=function(e,t,n,r){var a=this;this.checkTrigger(e,t,n,r,(function(e){return e.triggersZOrder}),(function(){a._private.cy.notify("zorder",e)}))},Ys.checkBoundsTrigger=function(e,t,n,r){this.checkTrigger(e,t,n,r,(function(e){return e.triggersBounds}),(function(a){e.dirtyCompoundBoundsCache(),e.dirtyBoundingBoxCache(),!a.triggersBoundsOfParallelBeziers||"curve-style"!==t||"bezier"!==n&&"bezier"!==r||e.parallelEdges().forEach((function(e){e.dirtyBoundingBoxCache()})),!a.triggersBoundsOfConnectedEdges||"display"!==t||"none"!==n&&"none"!==r||e.connectedEdges().forEach((function(e){e.dirtyBoundingBoxCache()}))}))},Ys.checkTriggers=function(e,t,n,r){e.dirtyStyleCache(),this.checkZOrderTrigger(e,t,n,r),this.checkBoundsTrigger(e,t,n,r)};var Ws={applyBypass:function(e,t,n,r){var a=[];if("*"===t||"**"===t){if(void 0!==n)for(var i=0;it.length?i.substr(t.length):""}function s(){n=n.length>r.length?n.substr(r.length):""}for(i=i.replace(/[/][*](\s|.)+?[*][/]/g,"");;){if(i.match(/^\s*$/))break;var l=i.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/);if(!l){Ue("Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: "+i);break}t=l[0];var u=l[1];if("core"!==u)if(new Fi(u).invalid){Ue("Skipping parsing of block: Invalid selector found in string stylesheet: "+u),o();continue}var c=l[2],d=!1;n=c;for(var h=[];;){if(n.match(/^\s*$/))break;var p=n.match(/^\s*(.+?)\s*:\s*(.+?)(?:\s*;|\s*$)/);if(!p){Ue("Skipping parsing of block: Invalid formatting of style property and value definitions found in:"+c),d=!0;break}r=p[0];var f=p[1],g=p[2];if(this.properties[f])a.parse(f,g)?(h.push({name:f,val:g}),s()):(Ue("Skipping property: Invalid property definition in: "+r),s());else Ue("Skipping property: Invalid property name in: "+r),s()}if(d){o();break}a.selector(u);for(var v=0;v=7&&"d"===t[0]&&(u=new RegExp(s.data.regex).exec(t))){if(n)return!1;var h=s.data;return{name:e,value:u,strValue:""+t,mapped:h,field:u[1],bypass:n}}if(t.length>=10&&"m"===t[0]&&(c=new RegExp(s.mapData.regex).exec(t))){if(n)return!1;if(d.multiple)return!1;var p=s.mapData;if(!d.color&&!d.number)return!1;var f=this.parse(e,c[4]);if(!f||f.mapped)return!1;var g=this.parse(e,c[5]);if(!g||g.mapped)return!1;if(f.pfValue===g.pfValue||f.strValue===g.strValue)return Ue("`"+e+": "+t+"` is not a valid mapper because the output range is zero; converting to `"+e+": "+f.strValue+"`"),this.parse(e,f.strValue);if(d.color){var v=f.value,y=g.value;if(!(v[0]!==y[0]||v[1]!==y[1]||v[2]!==y[2]||v[3]!==y[3]&&(null!=v[3]&&1!==v[3]||null!=y[3]&&1!==y[3])))return!1}return{name:e,value:c,strValue:""+t,mapped:p,field:c[1],fieldMin:parseFloat(c[2]),fieldMax:parseFloat(c[3]),valueMin:f.value,valueMax:g.value,bypass:n}}}if(d.multiple&&"multiple"!==r){var m;if(m=l?t.split(/\s+/):w(t)?t:[t],d.evenMultiple&&m.length%2!=0)return null;for(var E=[],C=[],S=[],P="",D=!1,T=0;T0?" ":"")+_.strValue}return d.validate&&!d.validate(E,C)?null:d.singleEnum&&D?1===E.length&&b(E[0])?{name:e,value:E[0],strValue:E[0],bypass:n}:null:{name:e,value:E,pfValue:S,strValue:P,bypass:n,units:C}}var M,B,N=function(){for(var r=0;rd.max||d.strictMax&&t===d.max))return null;var V={name:e,value:t,strValue:""+t+(z||""),units:z,bypass:n};return d.unitless||"px"!==z&&"em"!==z?V.pfValue=t:V.pfValue="px"!==z&&z?this.getEmSizeInPixels()*t:t,"ms"!==z&&"s"!==z||(V.pfValue="ms"===z?t:1e3*t),"deg"!==z&&"rad"!==z||(V.pfValue="rad"===z?t:(M=t,Math.PI*M/180)),"%"===z&&(V.pfValue=t/100),V}if(d.propList){var F=[],j=""+t;if("none"===j);else{for(var q=j.split(/\s*,\s*|\s+/),Y=0;Y0&&l>0&&!isNaN(n.w)&&!isNaN(n.h)&&n.w>0&&n.h>0)return{zoom:o=(o=(o=Math.min((s-2*t)/n.w,(l-2*t)/n.h))>this._private.maxZoom?this._private.maxZoom:o)=n.minZoom&&(n.maxZoom=t),this},minZoom:function(e){return void 0===e?this._private.minZoom:this.zoomRange({min:e})},maxZoom:function(e){return void 0===e?this._private.maxZoom:this.zoomRange({max:e})},getZoomedViewport:function(e){var t,n,r=this._private,a=r.pan,i=r.zoom,o=!1;if(r.zoomingEnabled||(o=!0),k(e)?n=e:E(e)&&(n=e.level,null!=e.position?t=Pt(e.position,i,a):null!=e.renderedPosition&&(t=e.renderedPosition),null==t||r.panningEnabled||(o=!0)),n=(n=n>r.maxZoom?r.maxZoom:n)t.maxZoom||!t.zoomingEnabled?i=!0:(t.zoom=s,a.push("zoom"))}if(r&&(!i||!e.cancelOnFailedZoom)&&t.panningEnabled){var l=e.pan;k(l.x)&&(t.pan.x=l.x,o=!1),k(l.y)&&(t.pan.y=l.y,o=!1),o||a.push("pan")}return a.length>0&&(a.push("viewport"),this.emit(a.join(" ")),this.notify("viewport")),this},center:function(e){var t=this.getCenterPan(e);return t&&(this._private.pan=t,this.emit("pan viewport"),this.notify("viewport")),this},getCenterPan:function(e,t){if(this._private.panningEnabled){if(b(e)){var n=e;e=this.mutableElements().filter(n)}else S(e)||(e=this.mutableElements());if(0!==e.length){var r=e.boundingBox(),a=this.width(),i=this.height();return{x:(a-(t=void 0===t?this._private.zoom:t)*(r.x1+r.x2))/2,y:(i-t*(r.y1+r.y2))/2}}}},reset:function(){return this._private.panningEnabled&&this._private.zoomingEnabled?(this.viewport({pan:{x:0,y:0},zoom:1}),this):this},invalidateSize:function(){this._private.sizeCache=null},size:function(){var e,t,n=this._private,r=n.container,a=this;return n.sizeCache=n.sizeCache||(r?(e=a.window().getComputedStyle(r),t=function(t){return parseFloat(e.getPropertyValue(t))},{width:r.clientWidth-t("padding-left")-t("padding-right"),height:r.clientHeight-t("padding-top")-t("padding-bottom")}):{width:1,height:1})},width:function(){return this.size().width},height:function(){return this.size().height},extent:function(){var e=this._private.pan,t=this._private.zoom,n=this.renderedExtent(),r={x1:(n.x1-e.x)/t,x2:(n.x2-e.x)/t,y1:(n.y1-e.y)/t,y2:(n.y2-e.y)/t};return r.w=r.x2-r.x1,r.h=r.y2-r.y1,r},renderedExtent:function(){var e=this.width(),t=this.height();return{x1:0,y1:0,x2:e,y2:t,w:e,h:t}},multiClickDebounceTime:function(e){return e?(this._private.multiClickDebounceTime=e,this):this._private.multiClickDebounceTime}};tl.centre=tl.center,tl.autolockNodes=tl.autolock,tl.autoungrabifyNodes=tl.autoungrabify;var nl={data:ni.data({field:"data",bindingEvent:"data",allowBinding:!0,allowSetting:!0,settingEvent:"data",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeData:ni.removeData({field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0}),scratch:ni.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeScratch:ni.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0})};nl.attr=nl.data,nl.removeAttr=nl.removeData;var rl=function(e){var t=this,n=(e=Y({},e)).container;n&&!C(n)&&C(n[0])&&(n=n[0]);var r=n?n._cyreg:null;(r=r||{})&&r.cy&&(r.cy.destroy(),r={});var a=r.readies=r.readies||[];n&&(n._cyreg=r),r.cy=t;var i=void 0!==h&&void 0!==n&&!e.headless,o=e;o.layout=Y({name:i?"grid":"null"},o.layout),o.renderer=Y({name:i?"canvas":"null"},o.renderer);var s=function(e,t,n){return void 0!==t?t:void 0!==n?n:e},l=this._private={container:n,ready:!1,options:o,elements:new bs(this),listeners:[],aniEles:new bs(this),data:o.data||{},scratch:{},layout:null,renderer:null,destroyed:!1,notificationsEnabled:!0,minZoom:1e-50,maxZoom:1e50,zoomingEnabled:s(!0,o.zoomingEnabled),userZoomingEnabled:s(!0,o.userZoomingEnabled),panningEnabled:s(!0,o.panningEnabled),userPanningEnabled:s(!0,o.userPanningEnabled),boxSelectionEnabled:s(!0,o.boxSelectionEnabled),autolock:s(!1,o.autolock,o.autolockNodes),autoungrabify:s(!1,o.autoungrabify,o.autoungrabifyNodes),autounselectify:s(!1,o.autounselectify),styleEnabled:void 0===o.styleEnabled?i:o.styleEnabled,zoom:k(o.zoom)?o.zoom:1,pan:{x:E(o.pan)&&k(o.pan.x)?o.pan.x:0,y:E(o.pan)&&k(o.pan.y)?o.pan.y:0},animation:{current:[],queue:[]},hasCompoundNodes:!1,multiClickDebounceTime:s(250,o.multiClickDebounceTime)};this.createEmitter(),this.selectionType(o.selectionType),this.zoomRange({min:o.minZoom,max:o.maxZoom});l.styleEnabled&&t.setStyle([]);var u=Y({},o,o.renderer);t.initRenderer(u);!function(e,t){if(e.some(B))return Tr.all(e).then(t);t(e)}([o.style,o.elements],(function(e){var n=e[0],i=e[1];l.styleEnabled&&t.style().append(n),function(e,n,r){t.notifications(!1);var a=t.mutableElements();a.length>0&&a.remove(),null!=e&&(E(e)||w(e))&&t.add(e),t.one("layoutready",(function(e){t.notifications(!0),t.emit(e),t.one("load",n),t.emitAndNotify("load")})).one("layoutstop",(function(){t.one("done",r),t.emit("done")}));var i=Y({},t._private.options.layout);i.eles=t.elements(),t.layout(i).run()}(i,(function(){t.startAnimationLoop(),l.ready=!0,x(o.ready)&&t.on("ready",o.ready);for(var e=0;e0,u=Rt(n.boundingBox?n.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()});if(S(n.roots))e=n.roots;else if(w(n.roots)){for(var c=[],d=0;d0;){var N=_.shift(),I=T(N,M);if(I)N.outgoers().filter((function(e){return e.isNode()&&a.has(e)})).forEach(B);else if(null===I){Ue("Detected double maximal shift for node `"+N.id()+"`. Bailing maximal adjustment due to cycle. Use `options.maximal: true` only on DAGs.");break}}}D();var z=0;if(n.avoidOverlap)for(var A=0;A0&&y[0].length<=3?l/2:0),d=2*Math.PI/y[r].length*a;return 0===r&&1===y[0].length&&(c=1),{x:G+c*Math.cos(d),y:U+c*Math.sin(d)}}return{x:G+(a+1-(i+1)/2)*o,y:(r+1)*s}})),this};var cl={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,nodeDimensionsIncludeLabels:!1,spacingFactor:void 0,radius:void 0,startAngle:1.5*Math.PI,sweep:void 0,clockwise:!0,sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:function(e,t){return!0},ready:void 0,stop:void 0,transform:function(e,t){return t}};function dl(e){this.options=Y({},cl,e)}dl.prototype.run=function(){var e=this.options,t=e,n=e.cy,r=t.eles,a=void 0!==t.counterclockwise?!t.counterclockwise:t.clockwise,i=r.nodes().not(":parent");t.sort&&(i=i.sort(t.sort));for(var o,s=Rt(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:n.width(),h:n.height()}),l=s.x1+s.w/2,u=s.y1+s.h/2,c=(void 0===t.sweep?2*Math.PI-2*Math.PI/i.length:t.sweep)/Math.max(1,i.length-1),d=0,h=0;h1&&t.avoidOverlap){d*=1.75;var v=Math.cos(c)-Math.cos(0),y=Math.sin(c)-Math.sin(0),m=Math.sqrt(d*d/(v*v+y*y));o=Math.max(m,o)}return r.nodes().layoutPositions(this,t,(function(e,n){var r=t.startAngle+n*c*(a?1:-1),i=o*Math.cos(r),s=o*Math.sin(r);return{x:l+i,y:u+s}})),this};var hl,pl={fit:!0,padding:30,startAngle:1.5*Math.PI,sweep:void 0,clockwise:!0,equidistant:!1,minNodeSpacing:10,boundingBox:void 0,avoidOverlap:!0,nodeDimensionsIncludeLabels:!1,height:void 0,width:void 0,spacingFactor:void 0,concentric:function(e){return e.degree()},levelWidth:function(e){return e.maxDegree()/4},animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:function(e,t){return!0},ready:void 0,stop:void 0,transform:function(e,t){return t}};function fl(e){this.options=Y({},pl,e)}fl.prototype.run=function(){for(var e=this.options,t=e,n=void 0!==t.counterclockwise?!t.counterclockwise:t.clockwise,r=e.cy,a=t.eles,i=a.nodes().not(":parent"),o=Rt(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()}),s=o.x1+o.w/2,l=o.y1+o.h/2,u=[],c=0,d=0;d0)Math.abs(m[0].value-x.value)>=v&&(m=[],y.push(m));m.push(x)}var w=c+t.minNodeSpacing;if(!t.avoidOverlap){var E=y.length>0&&y[0].length>1,k=(Math.min(o.w,o.h)/2-w)/(y.length+E?1:0);w=Math.min(w,k)}for(var C=0,S=0;S1&&t.avoidOverlap){var _=Math.cos(T)-Math.cos(0),M=Math.sin(T)-Math.sin(0),B=Math.sqrt(w*w/(_*_+M*M));C=Math.max(B,C)}P.r=C,C+=w}if(t.equidistant){for(var N=0,I=0,z=0;z=e.numIter)&&(kl(r,e),r.temperature=r.temperature*e.coolingFactor,!(r.temperature=e.animationThreshold&&i(),De(t)):(Al(r,e),s())}()}else{for(;u;)u=o(l),l++;Al(r,e),s()}return this},vl.prototype.stop=function(){return this.stopped=!0,this.thread&&this.thread.stop(),this.emit("layoutstop"),this},vl.prototype.destroy=function(){return this.thread&&this.thread.stop(),this};var yl=function(e,t,n){for(var r=n.eles.edges(),a=n.eles.nodes(),i=Rt(n.boundingBox?n.boundingBox:{x1:0,y1:0,w:e.width(),h:e.height()}),o={isCompound:e.hasCompoundNodes(),layoutNodes:[],idToIndex:{},nodeSize:a.size(),graphSet:[],indexToGraph:[],layoutEdges:[],edgeSize:r.size(),temperature:n.initialTemp,clientWidth:i.w,clientHeight:i.h,boundingBox:i},s=n.eles.components(),l={},u=0;u0){o.graphSet.push(E);for(u=0;ur.count?0:r.graph},bl=function e(t,n,r,a){var i=a.graphSet[r];if(-10)var s=(u=r.nodeOverlap*o)*a/(g=Math.sqrt(a*a+i*i)),l=u*i/g;else{var u,c=Tl(e,a,i),d=Tl(t,-1*a,-1*i),h=d.x-c.x,p=d.y-c.y,f=h*h+p*p,g=Math.sqrt(f);s=(u=(e.nodeRepulsion+t.nodeRepulsion)/f)*h/g,l=u*p/g}e.isLocked||(e.offsetX-=s,e.offsetY-=l),t.isLocked||(t.offsetX+=s,t.offsetY+=l)}},Dl=function(e,t,n,r){if(n>0)var a=e.maxX-t.minX;else a=t.maxX-e.minX;if(r>0)var i=e.maxY-t.minY;else i=t.maxY-e.minY;return a>=0&&i>=0?Math.sqrt(a*a+i*i):0},Tl=function(e,t,n){var r=e.positionX,a=e.positionY,i=e.height||1,o=e.width||1,s=n/t,l=i/o,u={};return 0===t&&0n?(u.x=r,u.y=a+i/2,u):0t&&-1*l<=s&&s<=l?(u.x=r-o/2,u.y=a-o*n/2/t,u):0=l)?(u.x=r+i*t/2/n,u.y=a+i/2,u):0>n&&(s<=-1*l||s>=l)?(u.x=r-i*t/2/n,u.y=a-i/2,u):u},_l=function(e,t){for(var n=0;n1){var f=t.gravity*d/p,g=t.gravity*h/p;c.offsetX+=f,c.offsetY+=g}}}}},Bl=function(e,t){var n=[],r=0,a=-1;for(n.push.apply(n,e.graphSet[0]),a+=e.graphSet[0].length;r<=a;){var i=n[r++],o=e.idToIndex[i],s=e.layoutNodes[o],l=s.children;if(0n)var a={x:n*e/r,y:n*t/r};else a={x:e,y:t};return a},zl=function e(t,n){var r=t.parentId;if(null!=r){var a=n.layoutNodes[n.idToIndex[r]],i=!1;return(null==a.maxX||t.maxX+a.padRight>a.maxX)&&(a.maxX=t.maxX+a.padRight,i=!0),(null==a.minX||t.minX-a.padLefta.maxY)&&(a.maxY=t.maxY+a.padBottom,i=!0),(null==a.minY||t.minY-a.padTopf&&(d+=p+t.componentSpacing,c=0,h=0,p=0)}}},Ll={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,avoidOverlapPadding:10,nodeDimensionsIncludeLabels:!1,spacingFactor:void 0,condense:!1,rows:void 0,cols:void 0,position:function(e){},sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:function(e,t){return!0},ready:void 0,stop:void 0,transform:function(e,t){return t}};function Ol(e){this.options=Y({},Ll,e)}Ol.prototype.run=function(){var e=this.options,t=e,n=e.cy,r=t.eles,a=r.nodes().not(":parent");t.sort&&(a=a.sort(t.sort));var i=Rt(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:n.width(),h:n.height()});if(0===i.h||0===i.w)r.nodes().layoutPositions(this,t,(function(e){return{x:i.x1,y:i.y1}}));else{var o=a.size(),s=Math.sqrt(o*i.h/i.w),l=Math.round(s),u=Math.round(i.w/i.h*s),c=function(e){if(null==e)return Math.min(l,u);Math.min(l,u)==l?l=e:u=e},d=function(e){if(null==e)return Math.max(l,u);Math.max(l,u)==l?l=e:u=e},h=t.rows,p=null!=t.cols?t.cols:t.columns;if(null!=h&&null!=p)l=h,u=p;else if(null!=h&&null==p)l=h,u=Math.ceil(o/l);else if(null==h&&null!=p)u=p,l=Math.ceil(o/u);else if(u*l>o){var f=c(),g=d();(f-1)*g>=o?c(f-1):(g-1)*f>=o&&d(g-1)}else for(;u*l=o?d(y+1):c(v+1)}var m=i.w/u,b=i.h/l;if(t.condense&&(m=0,b=0),t.avoidOverlap)for(var x=0;x=u&&(B=0,M++)},I={},z=0;z(r=$t(e,t,x[w],x[w+1],x[w+2],x[w+3])))return v(n,r),!0}else if("bezier"===i.edgeType||"multibezier"===i.edgeType||"self"===i.edgeType||"compound"===i.edgeType)for(x=i.allpts,w=0;w+5(r=Zt(e,t,x[w],x[w+1],x[w+2],x[w+3],x[w+4],x[w+5])))return v(n,r),!0;m=m||a.source,b=b||a.target;var E=o.getArrowWidth(l,c),k=[{name:"source",x:i.arrowStartX,y:i.arrowStartY,angle:i.srcArrowAngle},{name:"target",x:i.arrowEndX,y:i.arrowEndY,angle:i.tgtArrowAngle},{name:"mid-source",x:i.midX,y:i.midY,angle:i.midsrcArrowAngle},{name:"mid-target",x:i.midX,y:i.midY,angle:i.midtgtArrowAngle}];for(w=0;w0&&(y(m),y(b))}function b(e,t,n){return rt(e,t,n)}function x(n,r){var a,i=n._private,o=f;a=r?r+"-":"",n.boundingBox();var s=i.labelBounds[r||"main"],l=n.pstyle(a+"label").value;if("yes"===n.pstyle("text-events").strValue&&l){var u=b(i.rscratch,"labelX",r),c=b(i.rscratch,"labelY",r),d=b(i.rscratch,"labelAngle",r),h=n.pstyle(a+"text-margin-x").pfValue,p=n.pstyle(a+"text-margin-y").pfValue,g=s.x1-o-h,y=s.x2+o-h,m=s.y1-o-p,x=s.y2+o-p;if(d){var w=Math.cos(d),E=Math.sin(d),k=function(e,t){return{x:(e-=u)*w-(t-=c)*E+u,y:e*E+t*w+c}},C=k(g,m),S=k(g,x),P=k(y,m),D=k(y,x),T=[C.x+h,C.y+p,P.x+h,P.y+p,D.x+h,D.y+p,S.x+h,S.y+p];if(Qt(e,t,T))return v(n),!0}else if(Wt(s,e,t))return v(n),!0}}n&&(l=l.interactive);for(var w=l.length-1;w>=0;w--){var E=l[w];E.isNode()?y(E)||x(E):m(E)||x(E)||x(E,"source")||x(E,"target")}return u},getAllInBox:function(e,t,n,r){for(var a,i,o=this.getCachedZSortedEles().interactive,s=[],l=Math.min(e,n),u=Math.max(e,n),c=Math.min(t,r),d=Math.max(t,r),h=Rt({x1:e=l,y1:t=c,x2:n=u,y2:r=d}),p=0;p0?-(Math.PI-i.ang):Math.PI+i.ang),vu(t,n,gu),Jl=fu.nx*gu.ny-fu.ny*gu.nx,eu=fu.nx*gu.nx-fu.ny*-gu.ny,ru=Math.asin(Math.max(-1,Math.min(1,Jl))),Math.abs(ru)<1e-6)return $l=t.x,Ql=t.y,void(iu=su=0);tu=1,nu=!1,eu<0?ru<0?ru=Math.PI+ru:(ru=Math.PI-ru,tu=-1,nu=!0):ru>0&&(tu=-1,nu=!0),su=void 0!==t.radius?t.radius:r,au=ru/2,lu=Math.min(fu.len/2,gu.len/2),a?(ou=Math.abs(Math.cos(au)*su/Math.sin(au)))>lu?(ou=lu,iu=Math.abs(ou*Math.sin(au)/Math.cos(au))):iu=su:(ou=Math.min(lu,su),iu=Math.abs(ou*Math.sin(au)/Math.cos(au))),du=t.x+gu.nx*ou,hu=t.y+gu.ny*ou,$l=du-gu.ny*iu*tu,Ql=hu+gu.nx*iu*tu,uu=t.x+fu.nx*ou,cu=t.y+fu.ny*ou,pu=t};function mu(e,t){0===t.radius?e.lineTo(t.cx,t.cy):e.arc(t.cx,t.cy,t.radius,t.startAngle,t.endAngle,t.counterClockwise)}function bu(e,t,n,r){var a=!(arguments.length>4&&void 0!==arguments[4])||arguments[4];return 0===r||0===t.radius?{cx:t.x,cy:t.y,radius:0,startX:t.x,startY:t.y,stopX:t.x,stopY:t.y,startAngle:void 0,endAngle:void 0,counterClockwise:void 0}:(yu(e,t,n,r,a),{cx:$l,cy:Ql,radius:iu,startX:uu,startY:cu,stopX:du,stopY:hu,startAngle:fu.ang+Math.PI/2*tu,endAngle:gu.ang-Math.PI/2*tu,counterClockwise:nu})}var xu={};function wu(e){var t=[];if(null!=e){for(var n=0;n0?Math.max(e-t,0):Math.min(e+t,0)},D=P(C,E),T=P(S,k),_=!1;"auto"===v?g=Math.abs(D)>Math.abs(T)?a:r:v===l||v===s?(g=r,_=!0):v!==i&&v!==o||(g=a,_=!0);var M,B=g===r,N=B?T:D,I=B?S:C,z=Bt(I),A=!1;(_&&(m||x)||!(v===s&&I<0||v===l&&I>0||v===i&&I>0||v===o&&I<0)||(N=(z*=-1)*Math.abs(N),A=!0),m)?M=(b<0?1+b:b)*N:M=(b<0?N:0)+b*z;var L=function(e){return Math.abs(e)=Math.abs(N)},O=L(M),R=L(Math.abs(N)-Math.abs(M));if((O||R)&&!A)if(B){var V=Math.abs(I)<=d/2,F=Math.abs(C)<=h/2;if(V){var j=(u.x1+u.x2)/2,q=u.y1,Y=u.y2;n.segpts=[j,q,j,Y]}else if(F){var X=(u.y1+u.y2)/2,W=u.x1,H=u.x2;n.segpts=[W,X,H,X]}else n.segpts=[u.x1,u.y2]}else{var K=Math.abs(I)<=c/2,G=Math.abs(S)<=p/2;if(K){var U=(u.y1+u.y2)/2,Z=u.x1,$=u.x2;n.segpts=[Z,U,$,U]}else if(G){var Q=(u.x1+u.x2)/2,J=u.y1,ee=u.y2;n.segpts=[Q,J,Q,ee]}else n.segpts=[u.x2,u.y1]}else if(B){var te=u.y1+M+(f?d/2*z:0),ne=u.x1,re=u.x2;n.segpts=[ne,te,re,te]}else{var ae=u.x1+M+(f?c/2*z:0),ie=u.y1,oe=u.y2;n.segpts=[ae,ie,ae,oe]}if(n.isRound){var se=e.pstyle("taxi-radius").value,le="arc-radius"===e.pstyle("radius-type").value[0];n.radii=new Array(n.segpts.length/2).fill(se),n.isArcRadius=new Array(n.segpts.length/2).fill(le)}},xu.tryToCorrectInvalidPoints=function(e,t){var n=e._private.rscratch;if("bezier"===n.edgeType){var r=t.srcPos,a=t.tgtPos,i=t.srcW,o=t.srcH,s=t.tgtW,l=t.tgtH,u=t.srcShape,c=t.tgtShape,d=t.srcCornerRadius,h=t.tgtCornerRadius,p=t.srcRs,f=t.tgtRs,g=!k(n.startX)||!k(n.startY),v=!k(n.arrowStartX)||!k(n.arrowStartY),y=!k(n.endX)||!k(n.endY),m=!k(n.arrowEndX)||!k(n.arrowEndY),b=3*(this.getArrowWidth(e.pstyle("width").pfValue,e.pstyle("arrow-scale").value)*this.arrowShapeWidth),x=Nt({x:n.ctrlpts[0],y:n.ctrlpts[1]},{x:n.startX,y:n.startY}),w=xh.poolIndex()){var p=d;d=h,h=p}var f=s.srcPos=d.position(),g=s.tgtPos=h.position(),v=s.srcW=d.outerWidth(),y=s.srcH=d.outerHeight(),m=s.tgtW=h.outerWidth(),b=s.tgtH=h.outerHeight(),x=s.srcShape=n.nodeShapes[t.getNodeShape(d)],w=s.tgtShape=n.nodeShapes[t.getNodeShape(h)],E=s.srcCornerRadius="auto"===d.pstyle("corner-radius").value?"auto":d.pstyle("corner-radius").pfValue,C=s.tgtCornerRadius="auto"===h.pstyle("corner-radius").value?"auto":h.pstyle("corner-radius").pfValue,S=s.tgtRs=h._private.rscratch,P=s.srcRs=d._private.rscratch;s.dirCounts={north:0,west:0,south:0,east:0,northwest:0,southwest:0,northeast:0,southeast:0};for(var D=0;D0){var H=u,K=It(H,Tt(t)),G=It(H,Tt(W)),U=K;if(G2)It(H,{x:W[2],y:W[3]})0){var le=c,ue=It(le,Tt(t)),ce=It(le,Tt(se)),de=ue;if(ce2)It(le,{x:se[2],y:se[3]})=u||m){c={cp:g,segment:y};break}}if(c)break}var b=c.cp,x=c.segment,w=(u-h)/x.length,E=x.t1-x.t0,k=s?x.t0+E*w:x.t1-E*w;k=Ot(0,k,1),t=Lt(b.p0,b.p1,b.p2,k),a=function(e,t,n,r){var a=Ot(0,r-.001,1),i=Ot(0,r+.001,1),o=Lt(e,t,n,a),s=Lt(e,t,n,i);return Du(o,s)}(b.p0,b.p1,b.p2,k);break;case"straight":case"segments":case"haystack":for(var C,S,P,D,T=0,_=r.allpts.length,M=0;M+3<_&&(s?(P={x:r.allpts[M],y:r.allpts[M+1]},D={x:r.allpts[M+2],y:r.allpts[M+3]}):(P={x:r.allpts[_-2-M],y:r.allpts[_-1-M]},D={x:r.allpts[_-4-M],y:r.allpts[_-3-M]}),S=T,!((T+=C=Nt(P,D))>=u));M+=2);var B=(u-S)/C;B=Ot(0,B,1),t=function(e,t,n,r){var a=t.x-e.x,i=t.y-e.y,o=Nt(e,t),s=a/o,l=i/o;return n=null==n?0:n,r=null!=r?r:n*o,{x:e.x+s*r,y:e.y+l*r}}(P,D,B),a=Du(P,D)}o("labelX",n,t.x),o("labelY",n,t.y),o("labelAutoAngle",n,a)}};u("source"),u("target"),this.applyLabelDimensions(e)}},Su.applyLabelDimensions=function(e){this.applyPrefixedLabelDimensions(e),e.isEdge()&&(this.applyPrefixedLabelDimensions(e,"source"),this.applyPrefixedLabelDimensions(e,"target"))},Su.applyPrefixedLabelDimensions=function(e,t){var n=e._private,r=this.getLabelText(e,t),a=this.calculateLabelDimensions(e,r),i=e.pstyle("line-height").pfValue,o=e.pstyle("text-wrap").strValue,s=rt(n.rscratch,"labelWrapCachedLines",t)||[],l="wrap"!==o?1:Math.max(s.length,1),u=a.height/l,c=u*i,d=a.width,h=a.height+(l-1)*(i-1)*u;at(n.rstyle,"labelWidth",t,d),at(n.rscratch,"labelWidth",t,d),at(n.rstyle,"labelHeight",t,h),at(n.rscratch,"labelHeight",t,h),at(n.rscratch,"labelLineHeight",t,c)},Su.getLabelText=function(e,t){var n=e._private,r=t?t+"-":"",a=e.pstyle(r+"label").strValue,i=e.pstyle("text-transform").value,o=function(e,r){return r?(at(n.rscratch,e,t,r),r):rt(n.rscratch,e,t)};if(!a)return"";"none"==i||("uppercase"==i?a=a.toUpperCase():"lowercase"==i&&(a=a.toLowerCase()));var s=e.pstyle("text-wrap").value;if("wrap"===s){var l=o("labelKey");if(null!=l&&o("labelWrapKey")===l)return o("labelWrapCachedText");for(var u=a.split("\n"),c=e.pstyle("text-max-width").pfValue,h="anywhere"===e.pstyle("text-overflow-wrap").value,p=[],f=/[\s\u200b]+|$/g,g=0;gc){var b,x="",w=0,E=d(v.matchAll(f));try{for(E.s();!(b=E.n()).done;){var k=b.value,C=k[0],S=v.substring(w,k.index);w=k.index+C.length;var P=0===x.length?S:x+S+C;this.calculateLabelDimensions(e,P).width<=c?x+=S+C:(x&&p.push(x),x=S+C)}}catch(B){E.e(B)}finally{E.f()}x.match(/^[\s\u200b]+$/)||p.push(x)}else p.push(v)}o("labelWrapCachedLines",p),a=o("labelWrapCachedText",p.join("\n")),o("labelWrapKey",l)}else if("ellipsis"===s){var D=e.pstyle("text-max-width").pfValue,T="",_=!1;if(this.calculateLabelDimensions(e,a).widthD)break;T+=a[M],M===a.length-1&&(_=!0)}return _||(T+="\u2026"),T}return a},Su.getLabelJustification=function(e){var t=e.pstyle("text-justification").strValue,n=e.pstyle("text-halign").strValue;if("auto"!==t)return t;if(!e.isNode())return"center";switch(n){case"left":return"right";case"right":return"left";default:return"center"}},Su.calculateLabelDimensions=function(e,t){var n=this,r=n.cy.window().document,a=Le(t,e._private.labelDimsKey),i=n.labelDimCache||(n.labelDimCache=[]),o=i[a];if(null!=o)return o;var s=e.pstyle("font-style").strValue,l=e.pstyle("font-size").pfValue,u=e.pstyle("font-family").strValue,c=e.pstyle("font-weight").strValue,d=this.labelCalcCanvas,h=this.labelCalcCanvasContext;if(!d){d=this.labelCalcCanvas=r.createElement("canvas"),h=this.labelCalcCanvasContext=d.getContext("2d");var p=d.style;p.position="absolute",p.left="-9999px",p.top="-9999px",p.zIndex="-1",p.visibility="hidden",p.pointerEvents="none"}h.font="".concat(s," ").concat(c," ").concat(l,"px ").concat(u);for(var f=0,g=0,v=t.split("\n"),y=0;y1&&void 0!==arguments[1])||arguments[1];if(t.merge(e),n)for(var r=0;r=e.desktopTapThreshold2}var D=a(t);v&&(e.hoverData.tapholdCancelled=!0);n=!0,r(g,["mousemove","vmousemove","tapdrag"],t,{x:c[0],y:c[1]});var T=function(){e.data.bgActivePosistion=void 0,e.hoverData.selecting||o.emit({originalEvent:t,type:"boxstart",position:{x:c[0],y:c[1]}}),f[4]=1,e.hoverData.selecting=!0,e.redrawHint("select",!0),e.redraw()};if(3===e.hoverData.which){if(v){var _={originalEvent:t,type:"cxtdrag",position:{x:c[0],y:c[1]}};b?b.emit(_):o.emit(_),e.hoverData.cxtDragged=!0,e.hoverData.cxtOver&&g===e.hoverData.cxtOver||(e.hoverData.cxtOver&&e.hoverData.cxtOver.emit({originalEvent:t,type:"cxtdragout",position:{x:c[0],y:c[1]}}),e.hoverData.cxtOver=g,g&&g.emit({originalEvent:t,type:"cxtdragover",position:{x:c[0],y:c[1]}}))}}else if(e.hoverData.dragging){if(n=!0,o.panningEnabled()&&o.userPanningEnabled()){var M;if(e.hoverData.justStartedPan){var B=e.hoverData.mdownPos;M={x:(c[0]-B[0])*s,y:(c[1]-B[1])*s},e.hoverData.justStartedPan=!1}else M={x:x[0]*s,y:x[1]*s};o.panBy(M),o.emit("dragpan"),e.hoverData.dragged=!0}c=e.projectIntoViewport(t.clientX,t.clientY)}else if(1!=f[4]||null!=b&&!b.pannable()){if(b&&b.pannable()&&b.active()&&b.unactivate(),b&&b.grabbed()||g==y||(y&&r(y,["mouseout","tapdragout"],t,{x:c[0],y:c[1]}),g&&r(g,["mouseover","tapdragover"],t,{x:c[0],y:c[1]}),e.hoverData.last=g),b)if(v){if(o.boxSelectionEnabled()&&D)b&&b.grabbed()&&(d(w),b.emit("freeon"),w.emit("free"),e.dragData.didDrag&&(b.emit("dragfreeon"),w.emit("dragfree"))),T();else if(b&&b.grabbed()&&e.nodeIsDraggable(b)){var N=!e.dragData.didDrag;N&&e.redrawHint("eles",!0),e.dragData.didDrag=!0,e.hoverData.draggingEles||u(w,{inDragLayer:!0});var I={x:0,y:0};if(k(x[0])&&k(x[1])&&(I.x+=x[0],I.y+=x[1],N)){var z=e.hoverData.dragDelta;z&&k(z[0])&&k(z[1])&&(I.x+=z[0],I.y+=z[1])}e.hoverData.draggingEles=!0,w.silentShift(I).emit("position drag"),e.redrawHint("drag",!0),e.redraw()}}else!function(){var t=e.hoverData.dragDelta=e.hoverData.dragDelta||[];0===t.length?(t.push(x[0]),t.push(x[1])):(t[0]+=x[0],t[1]+=x[1])}();n=!0}else if(v){if(e.hoverData.dragging||!o.boxSelectionEnabled()||!D&&o.panningEnabled()&&o.userPanningEnabled()){if(!e.hoverData.selecting&&o.panningEnabled()&&o.userPanningEnabled()){i(b,e.hoverData.downs)&&(e.hoverData.dragging=!0,e.hoverData.justStartedPan=!0,f[4]=0,e.data.bgActivePosistion=Tt(h),e.redrawHint("select",!0),e.redraw())}}else T();b&&b.pannable()&&b.active()&&b.unactivate()}return f[2]=c[0],f[3]=c[1],n?(t.stopPropagation&&t.stopPropagation(),t.preventDefault&&t.preventDefault(),!1):void 0}}),!1),e.registerBinding(t,"mouseup",(function(t){if((1!==e.hoverData.which||1===t.which||!e.hoverData.capture)&&e.hoverData.capture){e.hoverData.capture=!1;var i=e.cy,o=e.projectIntoViewport(t.clientX,t.clientY),s=e.selection,l=e.findNearestElement(o[0],o[1],!0,!1),u=e.dragData.possibleDragElements,c=e.hoverData.down,h=a(t);if(e.data.bgActivePosistion&&(e.redrawHint("select",!0),e.redraw()),e.hoverData.tapholdCancelled=!0,e.data.bgActivePosistion=void 0,c&&c.unactivate(),3===e.hoverData.which){var p={originalEvent:t,type:"cxttapend",position:{x:o[0],y:o[1]}};if(c?c.emit(p):i.emit(p),!e.hoverData.cxtDragged){var f={originalEvent:t,type:"cxttap",position:{x:o[0],y:o[1]}};c?c.emit(f):i.emit(f)}e.hoverData.cxtDragged=!1,e.hoverData.which=null}else if(1===e.hoverData.which){if(r(l,["mouseup","tapend","vmouseup"],t,{x:o[0],y:o[1]}),e.dragData.didDrag||e.hoverData.dragged||e.hoverData.selecting||e.hoverData.isOverThresholdDrag||(r(c,["click","tap","vclick"],t,{x:o[0],y:o[1]}),x=!1,t.timeStamp-w<=i.multiClickDebounceTime()?(b&&clearTimeout(b),x=!0,w=null,r(c,["dblclick","dbltap","vdblclick"],t,{x:o[0],y:o[1]})):(b=setTimeout((function(){x||r(c,["oneclick","onetap","voneclick"],t,{x:o[0],y:o[1]})}),i.multiClickDebounceTime()),w=t.timeStamp)),null!=c||e.dragData.didDrag||e.hoverData.selecting||e.hoverData.dragged||a(t)||(i.$(n).unselect(["tapunselect"]),u.length>0&&e.redrawHint("eles",!0),e.dragData.possibleDragElements=u=i.collection()),l!=c||e.dragData.didDrag||e.hoverData.selecting||null!=l&&l._private.selectable&&(e.hoverData.dragging||("additive"===i.selectionType()||h?l.selected()?l.unselect(["tapunselect"]):l.select(["tapselect"]):h||(i.$(n).unmerge(l).unselect(["tapunselect"]),l.select(["tapselect"]))),e.redrawHint("eles",!0)),e.hoverData.selecting){var g=i.collection(e.getAllInBox(s[0],s[1],s[2],s[3]));e.redrawHint("select",!0),g.length>0&&e.redrawHint("eles",!0),i.emit({type:"boxend",originalEvent:t,position:{x:o[0],y:o[1]}});var v=function(e){return e.selectable()&&!e.selected()};"additive"===i.selectionType()||h||i.$(n).unmerge(g).unselect(),g.emit("box").stdFilter(v).select().emit("boxselect"),e.redraw()}if(e.hoverData.dragging&&(e.hoverData.dragging=!1,e.redrawHint("select",!0),e.redrawHint("eles",!0),e.redraw()),!s[4]){e.redrawHint("drag",!0),e.redrawHint("eles",!0);var y=c&&c.grabbed();d(u),y&&(c.emit("freeon"),u.emit("free"),e.dragData.didDrag&&(c.emit("dragfreeon"),u.emit("dragfree")))}}s[4]=0,e.hoverData.down=null,e.hoverData.cxtStarted=!1,e.hoverData.draggingEles=!1,e.hoverData.selecting=!1,e.hoverData.isOverThresholdDrag=!1,e.dragData.didDrag=!1,e.hoverData.dragged=!1,e.hoverData.dragDelta=[],e.hoverData.mdownPos=null,e.hoverData.mdownGPos=null,e.hoverData.which=null}}),!1);var C,S,P,D,T,_,M,B,N,I,z,A,L,O=function(t){if(!e.scrollingPage){var n=e.cy,r=n.zoom(),a=n.pan(),i=e.projectIntoViewport(t.clientX,t.clientY),o=[i[0]*r+a.x,i[1]*r+a.y];if(e.hoverData.draggingEles||e.hoverData.dragging||e.hoverData.cxtStarted||0!==e.selection[4])t.preventDefault();else if(n.panningEnabled()&&n.userPanningEnabled()&&n.zoomingEnabled()&&n.userZoomingEnabled()){var s;t.preventDefault(),e.data.wheelZooming=!0,clearTimeout(e.data.wheelTimeout),e.data.wheelTimeout=setTimeout((function(){e.data.wheelZooming=!1,e.redrawHint("eles",!0),e.redraw()}),150),s=null!=t.deltaY?t.deltaY/-250:null!=t.wheelDeltaY?t.wheelDeltaY/1e3:t.wheelDelta/1e3,s*=e.wheelSensitivity,1===t.deltaMode&&(s*=33);var l=n.zoom()*Math.pow(10,s);"gesturechange"===t.type&&(l=e.gestureStartZoom*t.scale),n.zoom({level:l,renderedPosition:{x:o[0],y:o[1]}}),n.emit("gesturechange"===t.type?"pinchzoom":"scrollzoom")}}};e.registerBinding(e.container,"wheel",O,!0),e.registerBinding(t,"scroll",(function(t){e.scrollingPage=!0,clearTimeout(e.scrollingPageTimeout),e.scrollingPageTimeout=setTimeout((function(){e.scrollingPage=!1}),250)}),!0),e.registerBinding(e.container,"gesturestart",(function(t){e.gestureStartZoom=e.cy.zoom(),e.hasTouchStarted||t.preventDefault()}),!0),e.registerBinding(e.container,"gesturechange",(function(t){e.hasTouchStarted||O(t)}),!0),e.registerBinding(e.container,"mouseout",(function(t){var n=e.projectIntoViewport(t.clientX,t.clientY);e.cy.emit({originalEvent:t,type:"mouseout",position:{x:n[0],y:n[1]}})}),!1),e.registerBinding(e.container,"mouseover",(function(t){var n=e.projectIntoViewport(t.clientX,t.clientY);e.cy.emit({originalEvent:t,type:"mouseover",position:{x:n[0],y:n[1]}})}),!1);var R,V,F,j,q,Y,X,W=function(e,t,n,r){return Math.sqrt((n-e)*(n-e)+(r-t)*(r-t))},H=function(e,t,n,r){return(n-e)*(n-e)+(r-t)*(r-t)};if(e.registerBinding(e.container,"touchstart",R=function(t){if(e.hasTouchStarted=!0,m(t)){p(),e.touchData.capture=!0,e.data.bgActivePosistion=void 0;var n=e.cy,a=e.touchData.now,i=e.touchData.earlier;if(t.touches[0]){var o=e.projectIntoViewport(t.touches[0].clientX,t.touches[0].clientY);a[0]=o[0],a[1]=o[1]}if(t.touches[1]){o=e.projectIntoViewport(t.touches[1].clientX,t.touches[1].clientY);a[2]=o[0],a[3]=o[1]}if(t.touches[2]){o=e.projectIntoViewport(t.touches[2].clientX,t.touches[2].clientY);a[4]=o[0],a[5]=o[1]}if(t.touches[1]){e.touchData.singleTouchMoved=!0,d(e.dragData.touchDragEles);var l=e.findContainerClientCoords();N=l[0],I=l[1],z=l[2],A=l[3],C=t.touches[0].clientX-N,S=t.touches[0].clientY-I,P=t.touches[1].clientX-N,D=t.touches[1].clientY-I,L=0<=C&&C<=z&&0<=P&&P<=z&&0<=S&&S<=A&&0<=D&&D<=A;var h=n.pan(),f=n.zoom();T=W(C,S,P,D),_=H(C,S,P,D),B=[((M=[(C+P)/2,(S+D)/2])[0]-h.x)/f,(M[1]-h.y)/f];if(_<4e4&&!t.touches[2]){var g=e.findNearestElement(a[0],a[1],!0,!0),v=e.findNearestElement(a[2],a[3],!0,!0);return g&&g.isNode()?(g.activate().emit({originalEvent:t,type:"cxttapstart",position:{x:a[0],y:a[1]}}),e.touchData.start=g):v&&v.isNode()?(v.activate().emit({originalEvent:t,type:"cxttapstart",position:{x:a[0],y:a[1]}}),e.touchData.start=v):n.emit({originalEvent:t,type:"cxttapstart",position:{x:a[0],y:a[1]}}),e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxt=!0,e.touchData.cxtDragged=!1,e.data.bgActivePosistion=void 0,void e.redraw()}}if(t.touches[2])n.boxSelectionEnabled()&&t.preventDefault();else if(t.touches[1]);else if(t.touches[0]){var y=e.findNearestElements(a[0],a[1],!0,!0),b=y[0];if(null!=b&&(b.activate(),e.touchData.start=b,e.touchData.starts=y,e.nodeIsGrabbable(b))){var x=e.dragData.touchDragEles=n.collection(),w=null;e.redrawHint("eles",!0),e.redrawHint("drag",!0),b.selected()?(w=n.$((function(t){return t.selected()&&e.nodeIsGrabbable(t)})),u(w,{addToList:x})):c(b,{addToList:x}),s(b);var E=function(e){return{originalEvent:t,type:e,position:{x:a[0],y:a[1]}}};b.emit(E("grabon")),w?w.forEach((function(e){e.emit(E("grab"))})):b.emit(E("grab"))}r(b,["touchstart","tapstart","vmousedown"],t,{x:a[0],y:a[1]}),null==b&&(e.data.bgActivePosistion={x:o[0],y:o[1]},e.redrawHint("select",!0),e.redraw()),e.touchData.singleTouchMoved=!1,e.touchData.singleTouchStartTime=+new Date,clearTimeout(e.touchData.tapholdTimeout),e.touchData.tapholdTimeout=setTimeout((function(){!1!==e.touchData.singleTouchMoved||e.pinching||e.touchData.selecting||r(e.touchData.start,["taphold"],t,{x:a[0],y:a[1]})}),e.tapholdDuration)}if(t.touches.length>=1){for(var k=e.touchData.startPosition=[null,null,null,null,null,null],O=0;O=e.touchTapThreshold2}if(n&&e.touchData.cxt){t.preventDefault();var w=t.touches[0].clientX-N,E=t.touches[0].clientY-I,M=t.touches[1].clientX-N,z=t.touches[1].clientY-I,A=H(w,E,M,z);if(A/_>=2.25||A>=22500){e.touchData.cxt=!1,e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var O={originalEvent:t,type:"cxttapend",position:{x:s[0],y:s[1]}};e.touchData.start?(e.touchData.start.unactivate().emit(O),e.touchData.start=null):o.emit(O)}}if(n&&e.touchData.cxt){O={originalEvent:t,type:"cxtdrag",position:{x:s[0],y:s[1]}};e.data.bgActivePosistion=void 0,e.redrawHint("select",!0),e.touchData.start?e.touchData.start.emit(O):o.emit(O),e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxtDragged=!0;var R=e.findNearestElement(s[0],s[1],!0,!0);e.touchData.cxtOver&&R===e.touchData.cxtOver||(e.touchData.cxtOver&&e.touchData.cxtOver.emit({originalEvent:t,type:"cxtdragout",position:{x:s[0],y:s[1]}}),e.touchData.cxtOver=R,R&&R.emit({originalEvent:t,type:"cxtdragover",position:{x:s[0],y:s[1]}}))}else if(n&&t.touches[2]&&o.boxSelectionEnabled())t.preventDefault(),e.data.bgActivePosistion=void 0,this.lastThreeTouch=+new Date,e.touchData.selecting||o.emit({originalEvent:t,type:"boxstart",position:{x:s[0],y:s[1]}}),e.touchData.selecting=!0,e.touchData.didSelect=!0,a[4]=1,a&&0!==a.length&&void 0!==a[0]?(a[2]=(s[0]+s[2]+s[4])/3,a[3]=(s[1]+s[3]+s[5])/3):(a[0]=(s[0]+s[2]+s[4])/3,a[1]=(s[1]+s[3]+s[5])/3,a[2]=(s[0]+s[2]+s[4])/3+1,a[3]=(s[1]+s[3]+s[5])/3+1),e.redrawHint("select",!0),e.redraw();else if(n&&t.touches[1]&&!e.touchData.didSelect&&o.zoomingEnabled()&&o.panningEnabled()&&o.userZoomingEnabled()&&o.userPanningEnabled()){if(t.preventDefault(),e.data.bgActivePosistion=void 0,e.redrawHint("select",!0),ee=e.dragData.touchDragEles){e.redrawHint("drag",!0);for(var V=0;V0&&!e.hoverData.draggingEles&&!e.swipePanning&&null!=e.data.bgActivePosistion&&(e.data.bgActivePosistion=void 0,e.redrawHint("select",!0),e.redraw())}},!1),e.registerBinding(t,"touchcancel",F=function(t){var n=e.touchData.start;e.touchData.capture=!1,n&&n.unactivate()}),e.registerBinding(t,"touchend",j=function(t){var a=e.touchData.start;if(e.touchData.capture){0===t.touches.length&&(e.touchData.capture=!1),t.preventDefault();var i=e.selection;e.swipePanning=!1,e.hoverData.draggingEles=!1;var o,s=e.cy,l=s.zoom(),u=e.touchData.now,c=e.touchData.earlier;if(t.touches[0]){var h=e.projectIntoViewport(t.touches[0].clientX,t.touches[0].clientY);u[0]=h[0],u[1]=h[1]}if(t.touches[1]){h=e.projectIntoViewport(t.touches[1].clientX,t.touches[1].clientY);u[2]=h[0],u[3]=h[1]}if(t.touches[2]){h=e.projectIntoViewport(t.touches[2].clientX,t.touches[2].clientY);u[4]=h[0],u[5]=h[1]}if(a&&a.unactivate(),e.touchData.cxt){if(o={originalEvent:t,type:"cxttapend",position:{x:u[0],y:u[1]}},a?a.emit(o):s.emit(o),!e.touchData.cxtDragged){var p={originalEvent:t,type:"cxttap",position:{x:u[0],y:u[1]}};a?a.emit(p):s.emit(p)}return e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxt=!1,e.touchData.start=null,void e.redraw()}if(!t.touches[2]&&s.boxSelectionEnabled()&&e.touchData.selecting){e.touchData.selecting=!1;var f=s.collection(e.getAllInBox(i[0],i[1],i[2],i[3]));i[0]=void 0,i[1]=void 0,i[2]=void 0,i[3]=void 0,i[4]=0,e.redrawHint("select",!0),s.emit({type:"boxend",originalEvent:t,position:{x:u[0],y:u[1]}});f.emit("box").stdFilter((function(e){return e.selectable()&&!e.selected()})).select().emit("boxselect"),f.nonempty()&&e.redrawHint("eles",!0),e.redraw()}if(null!=a&&a.unactivate(),t.touches[2])e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);else if(t.touches[1]);else if(t.touches[0]);else if(!t.touches[0]){e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var g=e.dragData.touchDragEles;if(null!=a){var v=a._private.grabbed;d(g),e.redrawHint("drag",!0),e.redrawHint("eles",!0),v&&(a.emit("freeon"),g.emit("free"),e.dragData.didDrag&&(a.emit("dragfreeon"),g.emit("dragfree"))),r(a,["touchend","tapend","vmouseup","tapdragout"],t,{x:u[0],y:u[1]}),a.unactivate(),e.touchData.start=null}else{var y=e.findNearestElement(u[0],u[1],!0,!0);r(y,["touchend","tapend","vmouseup","tapdragout"],t,{x:u[0],y:u[1]})}var m=e.touchData.startPosition[0]-u[0],b=m*m,x=e.touchData.startPosition[1]-u[1],w=(b+x*x)*l*l;e.touchData.singleTouchMoved||(a||s.$(":selected").unselect(["tapunselect"]),r(a,["tap","vclick"],t,{x:u[0],y:u[1]}),q=!1,t.timeStamp-X<=s.multiClickDebounceTime()?(Y&&clearTimeout(Y),q=!0,X=null,r(a,["dbltap","vdblclick"],t,{x:u[0],y:u[1]})):(Y=setTimeout((function(){q||r(a,["onetap","voneclick"],t,{x:u[0],y:u[1]})}),s.multiClickDebounceTime()),X=t.timeStamp)),null!=a&&!e.dragData.didDrag&&a._private.selectable&&w2){for(var p=[c[0],c[1]],f=Math.pow(p[0]-e,2)+Math.pow(p[1]-t,2),g=1;g0)return g[0]}return null},p=Object.keys(d),f=0;f0?u:Kt(a,i,e,t,n,r,o,s)},checkPoint:function(e,t,n,r,a,i,o,s){var l=2*(s="auto"===s?hn(r,a):s);if(Jt(e,t,this.points,i,o,r,a-l,[0,-1],n))return!0;if(Jt(e,t,this.points,i,o,r-l,a,[0,-1],n))return!0;var u=r/2+2*n,c=a/2+2*n;return!!Qt(e,t,[i-u,o-c,i-u,o,i+u,o,i+u,o-c])||(!!nn(e,t,l,l,i+r/2-s,o+a/2-s,n)||!!nn(e,t,l,l,i-r/2+s,o+a/2-s,n))}}},Au.registerNodeShapes=function(){var e=this.nodeShapes={},t=this;this.generateEllipse(),this.generatePolygon("triangle",un(3,0)),this.generateRoundPolygon("round-triangle",un(3,0)),this.generatePolygon("rectangle",un(4,0)),e.square=e.rectangle,this.generateRoundRectangle(),this.generateCutRectangle(),this.generateBarrel(),this.generateBottomRoundrectangle();var n=[0,1,1,0,0,-1,-1,0];this.generatePolygon("diamond",n),this.generateRoundPolygon("round-diamond",n),this.generatePolygon("pentagon",un(5,0)),this.generateRoundPolygon("round-pentagon",un(5,0)),this.generatePolygon("hexagon",un(6,0)),this.generateRoundPolygon("round-hexagon",un(6,0)),this.generatePolygon("heptagon",un(7,0)),this.generateRoundPolygon("round-heptagon",un(7,0)),this.generatePolygon("octagon",un(8,0)),this.generateRoundPolygon("round-octagon",un(8,0));var r=new Array(20),a=dn(5,0),i=dn(5,Math.PI/5),o=.5*(3-Math.sqrt(5));o*=1.57;for(var s=0;s=e.deqFastCost*g)break}else if(a){if(p>=e.deqCost*l||p>=e.deqAvgCost*s)break}else if(f>=e.deqNoDrawCost*Fu)break;var v=e.deq(t,d,c);if(!(v.length>0))break;for(var y=0;y0&&(e.onDeqd(t,u),!a&&e.shouldRedraw(t,u,d,c)&&r())}),a(t))}}},qu=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Xe;a(this,e),this.idsByKey=new it,this.keyForId=new it,this.cachesByLvl=new it,this.lvls=[],this.getKey=t,this.doesEleInvalidateKey=n}return o(e,[{key:"getIdsFor",value:function(e){null==e&&Ke("Can not get id list for null key");var t=this.idsByKey,n=this.idsByKey.get(e);return n||(n=new st,t.set(e,n)),n}},{key:"addIdForKey",value:function(e,t){null!=e&&this.getIdsFor(e).add(t)}},{key:"deleteIdForKey",value:function(e,t){null!=e&&this.getIdsFor(e).delete(t)}},{key:"getNumberOfIdsForKey",value:function(e){return null==e?0:this.getIdsFor(e).size}},{key:"updateKeyMappingFor",value:function(e){var t=e.id(),n=this.keyForId.get(t),r=this.getKey(e);this.deleteIdForKey(n,t),this.addIdForKey(r,t),this.keyForId.set(t,r)}},{key:"deleteKeyMappingFor",value:function(e){var t=e.id(),n=this.keyForId.get(t);this.deleteIdForKey(n,t),this.keyForId.delete(t)}},{key:"keyHasChangedFor",value:function(e){var t=e.id();return this.keyForId.get(t)!==this.getKey(e)}},{key:"isInvalid",value:function(e){return this.keyHasChangedFor(e)||this.doesEleInvalidateKey(e)}},{key:"getCachesAt",value:function(e){var t=this.cachesByLvl,n=this.lvls,r=t.get(e);return r||(r=new it,t.set(e,r),n.push(e)),r}},{key:"getCache",value:function(e,t){return this.getCachesAt(t).get(e)}},{key:"get",value:function(e,t){var n=this.getKey(e),r=this.getCache(n,t);return null!=r&&this.updateKeyMappingFor(e),r}},{key:"getForCachedKey",value:function(e,t){var n=this.keyForId.get(e.id());return this.getCache(n,t)}},{key:"hasCache",value:function(e,t){return this.getCachesAt(t).has(e)}},{key:"has",value:function(e,t){var n=this.getKey(e);return this.hasCache(n,t)}},{key:"setCache",value:function(e,t,n){n.key=e,this.getCachesAt(t).set(e,n)}},{key:"set",value:function(e,t,n){var r=this.getKey(e);this.setCache(r,t,n),this.updateKeyMappingFor(e)}},{key:"deleteCache",value:function(e,t){this.getCachesAt(t).delete(e)}},{key:"delete",value:function(e,t){var n=this.getKey(e);this.deleteCache(n,t)}},{key:"invalidateKey",value:function(e){var t=this;this.lvls.forEach((function(n){return t.deleteCache(e,n)}))}},{key:"invalidate",value:function(e){var t=e.id(),n=this.keyForId.get(t);this.deleteKeyMappingFor(e);var r=this.doesEleInvalidateKey(e);return r&&this.invalidateKey(n),r||0===this.getNumberOfIdsForKey(n)}}]),e}(),Yu={dequeue:"dequeue",downscale:"downscale",highQuality:"highQuality"},Xu=et({getKey:null,doesEleInvalidateKey:Xe,drawElement:null,getBoundingBox:null,getRotationPoint:null,getRotationOffset:null,isVisible:Ye,allowEdgeTxrCaching:!0,allowParentTxrCaching:!0}),Wu=function(e,t){var n=this;n.renderer=e,n.onDequeues=[];var r=Xu(t);Y(n,r),n.lookup=new qu(r.getKey,r.doesEleInvalidateKey),n.setupDequeueing()},Hu=Wu.prototype;Hu.reasons=Yu,Hu.getTextureQueue=function(e){var t=this;return t.eleImgCaches=t.eleImgCaches||{},t.eleImgCaches[e]=t.eleImgCaches[e]||[]},Hu.getRetiredTextureQueue=function(e){var t=this.eleImgCaches.retired=this.eleImgCaches.retired||{};return t[e]=t[e]||[]},Hu.getElementQueue=function(){return this.eleCacheQueue=this.eleCacheQueue||new ht((function(e,t){return t.reqs-e.reqs}))},Hu.getElementKeyToQueue=function(){return this.eleKeyToCacheQueue=this.eleKeyToCacheQueue||{}},Hu.getElement=function(e,t,n,r,a){var i=this,o=this.renderer,s=o.cy.zoom(),l=this.lookup;if(!t||0===t.w||0===t.h||isNaN(t.w)||isNaN(t.h)||!e.visible()||e.removed())return null;if(!i.allowEdgeTxrCaching&&e.isEdge()||!i.allowParentTxrCaching&&e.isParent())return null;if(null==r&&(r=Math.ceil(Mt(s*n))),r<-4)r=-4;else if(s>=7.99||r>3)return null;var u=Math.pow(2,r),c=t.h*u,d=t.w*u,h=o.eleTextBiggerThanMin(e,u);if(!this.isVisible(e,h))return null;var p,f=l.get(e,r);if(f&&f.invalidated&&(f.invalidated=!1,f.texture.invalidatedWidth-=f.width),f)return f;if(p=c<=25?25:c<=50?50:50*Math.ceil(c/50),c>1024||d>1024)return null;var g=i.getTextureQueue(p),v=g[g.length-2],y=function(){return i.recycleTexture(p,d)||i.addTexture(p,d)};v||(v=g[g.length-1]),v||(v=y()),v.width-v.usedWidthr;D--)S=i.getElement(e,t,n,D,Yu.downscale);P()}else{var T;if(!x&&!w&&!E)for(var _=r-1;_>=-4;_--){var M=l.get(e,_);if(M){T=M;break}}if(b(T))return i.queueElement(e,r),T;v.context.translate(v.usedWidth,0),v.context.scale(u,u),this.drawElement(v.context,e,t,h,!1),v.context.scale(1/u,1/u),v.context.translate(-v.usedWidth,0)}return f={x:v.usedWidth,texture:v,level:r,scale:u,width:d,height:c,scaledLabelShown:h},v.usedWidth+=Math.ceil(d+8),v.eleCaches.push(f),l.set(e,r,f),i.checkTextureFullness(v),f},Hu.invalidateElements=function(e){for(var t=0;t=.2*e.width&&this.retireTexture(e)},Hu.checkTextureFullness=function(e){var t=this.getTextureQueue(e.height);e.usedWidth/e.width>.8&&e.fullnessChecks>=10?tt(t,e):e.fullnessChecks++},Hu.retireTexture=function(e){var t=e.height,n=this.getTextureQueue(t),r=this.lookup;tt(n,e),e.retired=!0;for(var a=e.eleCaches,i=0;i=t)return i.retired=!1,i.usedWidth=0,i.invalidatedWidth=0,i.fullnessChecks=0,nt(i.eleCaches),i.context.setTransform(1,0,0,1,0,0),i.context.clearRect(0,0,i.width,i.height),tt(r,i),n.push(i),i}},Hu.queueElement=function(e,t){var n=this.getElementQueue(),r=this.getElementKeyToQueue(),a=this.getKey(e),i=r[a];if(i)i.level=Math.max(i.level,t),i.eles.merge(e),i.reqs++,n.updateItem(i);else{var o={eles:e.spawn().merge(e),level:t,reqs:1,key:a};n.push(o),r[a]=o}},Hu.dequeue=function(e){for(var t=this,n=t.getElementQueue(),r=t.getElementKeyToQueue(),a=[],i=t.lookup,o=0;o<1&&n.size()>0;o++){var s=n.pop(),l=s.key,u=s.eles[0],c=i.hasCache(u,s.level);if(r[l]=null,!c){a.push(s);var d=t.getBoundingBox(u);t.getElement(u,d,e,s.level,Yu.dequeue)}}return a},Hu.removeFromQueue=function(e){var t=this.getElementQueue(),n=this.getElementKeyToQueue(),r=this.getKey(e),a=n[r];null!=a&&(1===a.eles.length?(a.reqs=qe,t.updateItem(a),t.pop(),n[r]=null):a.eles.unmerge(e))},Hu.onDequeue=function(e){this.onDequeues.push(e)},Hu.offDequeue=function(e){tt(this.onDequeues,e)},Hu.setupDequeueing=ju({deqRedrawThreshold:100,deqCost:.15,deqAvgCost:.1,deqNoDrawCost:.9,deqFastCost:.9,deq:function(e,t,n){return e.dequeue(t,n)},onDeqd:function(e,t){for(var n=0;n=3.99||n>2)return null;r.validateLayersElesOrdering(n,e);var o,s,l=r.layersByLevel,u=Math.pow(2,n),c=l[n]=l[n]||[];if(r.levelIsComplete(n,e))return c;!function(){var t=function(t){if(r.validateLayersElesOrdering(t,e),r.levelIsComplete(t,e))return s=l[t],!0},a=function(e){if(!s)for(var r=n+e;-4<=r&&r<=2&&!t(r);r+=e);};a(1),a(-1);for(var i=c.length-1;i>=0;i--){var o=c[i];o.invalid&&tt(c,o)}}();var d=function(t){var a=(t=t||{}).after;!function(){if(!o){o=Rt();for(var t=0;t32767||s>32767)return null;if(i*s>16e6)return null;var l=r.makeLayer(o,n);if(null!=a){var d=c.indexOf(a)+1;c.splice(d,0,l)}else(void 0===t.insert||t.insert)&&c.unshift(l);return l};if(r.skipping&&!i)return null;for(var h=null,p=e.length/1,f=!i,g=0;g=p||!Ht(h.bb,v.boundingBox()))&&!(h=d({insert:!0,after:h})))return null;s||f?r.queueLayer(h,v):r.drawEleInLayer(h,v,n,t),h.eles.push(v),m[n]=h}}return s||(f?null:c)},Gu.getEleLevelForLayerLevel=function(e,t){return e},Gu.drawEleInLayer=function(e,t,n,r){var a=this.renderer,i=e.context,o=t.boundingBox();0!==o.w&&0!==o.h&&t.visible()&&(n=this.getEleLevelForLayerLevel(n,r),a.setImgSmoothing(i,!1),a.drawCachedElement(i,t,null,null,n,true),a.setImgSmoothing(i,!0))},Gu.levelIsComplete=function(e,t){var n=this.layersByLevel[e];if(!n||0===n.length)return!1;for(var r=0,a=0;a0)return!1;if(i.invalid)return!1;r+=i.eles.length}return r===t.length},Gu.validateLayersElesOrdering=function(e,t){var n=this.layersByLevel[e];if(n)for(var r=0;r0){e=!0;break}}return e},Gu.invalidateElements=function(e){var t=this;0!==e.length&&(t.lastInvalidationTime=Te(),0!==e.length&&t.haveLayers()&&t.updateElementsInLayers(e,(function(e,n,r){t.invalidateLayer(e)})))},Gu.invalidateLayer=function(e){if(this.lastInvalidationTime=Te(),!e.invalid){var t=e.level,n=e.eles,r=this.layersByLevel[t];tt(r,e),e.elesQueue=[],e.invalid=!0,e.replacement&&(e.replacement.invalid=!0);for(var a=0;a3&&void 0!==arguments[3])||arguments[3],a=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],i=!(arguments.length>5&&void 0!==arguments[5])||arguments[5],o=this,s=t._private.rscratch;if((!i||t.visible())&&!s.badLine&&null!=s.allpts&&!isNaN(s.allpts[0])){var l;n&&(l=n,e.translate(-l.x1,-l.y1));var u=i?t.pstyle("opacity").value:1,c=i?t.pstyle("line-opacity").value:1,d=t.pstyle("curve-style").value,h=t.pstyle("line-style").value,p=t.pstyle("width").pfValue,f=t.pstyle("line-cap").value,g=t.pstyle("line-outline-width").value,v=t.pstyle("line-outline-color").value,y=u*c,m=u*c,b=function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:y;"straight-triangle"===d?(o.eleStrokeStyle(e,t,n),o.drawEdgeTrianglePath(t,e,s.allpts)):(e.lineWidth=p,e.lineCap=f,o.eleStrokeStyle(e,t,n),o.drawEdgePath(t,e,s.allpts,h),e.lineCap="butt")},x=function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:m;o.drawArrowheads(e,t,n)};if(e.lineJoin="round","yes"===t.pstyle("ghost").value){var w=t.pstyle("ghost-offset-x").pfValue,E=t.pstyle("ghost-offset-y").pfValue,k=t.pstyle("ghost-opacity").value,C=y*k;e.translate(w,E),b(C),x(C),e.translate(-w,-E)}else!function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:y;e.lineWidth=p+g,e.lineCap=f,g>0?(o.colorStrokeStyle(e,v[0],v[1],v[2],n),"straight-triangle"===d?o.drawEdgeTrianglePath(t,e,s.allpts):(o.drawEdgePath(t,e,s.allpts,h),e.lineCap="butt")):e.lineCap="butt"}();a&&o.drawEdgeUnderlay(e,t),b(),x(),a&&o.drawEdgeOverlay(e,t),o.drawElementText(e,t,null,r),n&&e.translate(l.x1,l.y1)}}},hc=function(e){if(!["overlay","underlay"].includes(e))throw new Error("Invalid state");return function(t,n){if(n.visible()){var r=n.pstyle("".concat(e,"-opacity")).value;if(0!==r){var a=this,i=a.usePaths(),o=n._private.rscratch,s=2*n.pstyle("".concat(e,"-padding")).pfValue,l=n.pstyle("".concat(e,"-color")).value;t.lineWidth=s,"self"!==o.edgeType||i?t.lineCap="round":t.lineCap="butt",a.colorStrokeStyle(t,l[0],l[1],l[2],r),a.drawEdgePath(n,t,o.allpts,"solid")}}}};dc.drawEdgeOverlay=hc("overlay"),dc.drawEdgeUnderlay=hc("underlay"),dc.drawEdgePath=function(e,t,n,r){var a,i=e._private.rscratch,o=t,s=!1,l=this.usePaths(),u=e.pstyle("line-dash-pattern").pfValue,c=e.pstyle("line-dash-offset").pfValue;if(l){var h=n.join("$");i.pathCacheKey&&i.pathCacheKey===h?(a=t=i.pathCache,s=!0):(a=t=new Path2D,i.pathCacheKey=h,i.pathCache=a)}if(o.setLineDash)switch(r){case"dotted":o.setLineDash([1,1]);break;case"dashed":o.setLineDash(u),o.lineDashOffset=c;break;case"solid":o.setLineDash([])}if(!s&&!i.badLine)switch(t.beginPath&&t.beginPath(),t.moveTo(n[0],n[1]),i.edgeType){case"bezier":case"self":case"compound":case"multibezier":for(var p=2;p+35&&void 0!==arguments[5]?arguments[5]:5,o=arguments.length>6?arguments[6]:void 0;e.beginPath(),e.moveTo(t+i,n),e.lineTo(t+r-i,n),e.quadraticCurveTo(t+r,n,t+r,n+i),e.lineTo(t+r,n+a-i),e.quadraticCurveTo(t+r,n+a,t+r-i,n+a),e.lineTo(t+i,n+a),e.quadraticCurveTo(t,n+a,t,n+a-i),e.lineTo(t,n+i),e.quadraticCurveTo(t,n,t+i,n),e.closePath(),o?e.stroke():e.fill()}fc.eleTextBiggerThanMin=function(e,t){if(!t){var n=e.cy().zoom(),r=this.getPixelRatio(),a=Math.ceil(Mt(n*r));t=Math.pow(2,a)}return!(e.pstyle("font-size").pfValue*t5&&void 0!==arguments[5])||arguments[5],o=this;if(null==r){if(i&&!o.eleTextBiggerThanMin(t))return}else if(!1===r)return;if(t.isNode()){var s=t.pstyle("label");if(!s||!s.value)return;var l=o.getLabelJustification(t);e.textAlign=l,e.textBaseline="bottom"}else{var u=t.element()._private.rscratch.badLine,c=t.pstyle("label"),d=t.pstyle("source-label"),h=t.pstyle("target-label");if(u||(!c||!c.value)&&(!d||!d.value)&&(!h||!h.value))return;e.textAlign="center",e.textBaseline="bottom"}var p,f=!n;n&&(p=n,e.translate(-p.x1,-p.y1)),null==a?(o.drawText(e,t,null,f,i),t.isEdge()&&(o.drawText(e,t,"source",f,i),o.drawText(e,t,"target",f,i))):o.drawText(e,t,a,f,i),n&&e.translate(p.x1,p.y1)},fc.getFontCache=function(e){var t;this.fontCaches=this.fontCaches||[];for(var n=0;n2&&void 0!==arguments[2])||arguments[2],r=t.pstyle("font-style").strValue,a=t.pstyle("font-size").pfValue+"px",i=t.pstyle("font-family").strValue,o=t.pstyle("font-weight").strValue,s=n?t.effectiveOpacity()*t.pstyle("text-opacity").value:1,l=t.pstyle("text-outline-opacity").value*s,u=t.pstyle("color").value,c=t.pstyle("text-outline-color").value;e.font=r+" "+o+" "+a+" "+i,e.lineJoin="round",this.colorFillStyle(e,u[0],u[1],u[2],s),this.colorStrokeStyle(e,c[0],c[1],c[2],l)},fc.getTextAngle=function(e,t){var n=e._private.rscratch,r=t?t+"-":"",a=e.pstyle(r+"text-rotation"),i=rt(n,"labelAngle",t);return"autorotate"===a.strValue?e.isEdge()?i:0:"none"===a.strValue?0:a.pfValue},fc.drawText=function(e,t,n){var r=!(arguments.length>3&&void 0!==arguments[3])||arguments[3],a=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],i=t._private.rscratch,o=a?t.effectiveOpacity():1;if(!a||0!==o&&0!==t.pstyle("text-opacity").value){"main"===n&&(n=null);var s,l,u=rt(i,"labelX",n),c=rt(i,"labelY",n),d=this.getLabelText(t,n);if(null!=d&&""!==d&&!isNaN(u)&&!isNaN(c)){this.setupTextStyle(e,t,a);var h,p=n?n+"-":"",f=rt(i,"labelWidth",n),g=rt(i,"labelHeight",n),v=t.pstyle(p+"text-margin-x").pfValue,y=t.pstyle(p+"text-margin-y").pfValue,m=t.isEdge(),b=t.pstyle("text-halign").value,x=t.pstyle("text-valign").value;switch(m&&(b="center",x="center"),u+=v,c+=y,0!==(h=r?this.getTextAngle(t,n):0)&&(s=u,l=c,e.translate(s,l),e.rotate(h),u=0,c=0),x){case"top":break;case"center":c+=g/2;break;case"bottom":c+=g}var w=t.pstyle("text-background-opacity").value,E=t.pstyle("text-border-opacity").value,k=t.pstyle("text-border-width").pfValue,C=t.pstyle("text-background-padding").pfValue,S=0===t.pstyle("text-background-shape").strValue.indexOf("round");if(w>0||k>0&&E>0){var P=u-C;switch(b){case"left":P-=f;break;case"center":P-=f/2}var D=c-g-C,T=f+2*C,_=g+2*C;if(w>0){var M=e.fillStyle,B=t.pstyle("text-background-color").value;e.fillStyle="rgba("+B[0]+","+B[1]+","+B[2]+","+w*o+")",S?gc(e,P,D,T,_,2):e.fillRect(P,D,T,_),e.fillStyle=M}if(k>0&&E>0){var N=e.strokeStyle,I=e.lineWidth,z=t.pstyle("text-border-color").value,A=t.pstyle("text-border-style").value;if(e.strokeStyle="rgba("+z[0]+","+z[1]+","+z[2]+","+E*o+")",e.lineWidth=k,e.setLineDash)switch(A){case"dotted":e.setLineDash([1,1]);break;case"dashed":e.setLineDash([4,2]);break;case"double":e.lineWidth=k/4,e.setLineDash([]);break;case"solid":e.setLineDash([])}if(S?gc(e,P,D,T,_,2,"stroke"):e.strokeRect(P,D,T,_),"double"===A){var L=k/2;S?gc(e,P+L,D+L,T-2*L,_-2*L,2,"stroke"):e.strokeRect(P+L,D+L,T-2*L,_-2*L)}e.setLineDash&&e.setLineDash([]),e.lineWidth=I,e.strokeStyle=N}}var O=2*t.pstyle("text-outline-width").pfValue;if(O>0&&(e.lineWidth=O),"wrap"===t.pstyle("text-wrap").value){var R=rt(i,"labelWrapCachedLines",n),V=rt(i,"labelLineHeight",n),F=f/2,j=this.getLabelJustification(t);switch("auto"===j||("left"===b?"left"===j?u+=-f:"center"===j&&(u+=-F):"center"===b?"left"===j?u+=-F:"right"===j&&(u+=F):"right"===b&&("center"===j?u+=F:"right"===j&&(u+=f))),x){case"top":case"center":case"bottom":c-=(R.length-1)*V}for(var q=0;q0&&e.strokeText(R[q],u,c),e.fillText(R[q],u,c),c+=V}else O>0&&e.strokeText(d,u,c),e.fillText(d,u,c);0!==h&&(e.rotate(-h),e.translate(-s,-l))}}};var vc={drawNode:function(e,t,n){var r,a,i=!(arguments.length>3&&void 0!==arguments[3])||arguments[3],o=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],s=!(arguments.length>5&&void 0!==arguments[5])||arguments[5],l=this,u=t._private,c=u.rscratch,d=t.position();if(k(d.x)&&k(d.y)&&(!s||t.visible())){var h,p,f=s?t.effectiveOpacity():1,g=l.usePaths(),v=!1,y=t.padding();r=t.width()+2*y,a=t.height()+2*y,n&&(p=n,e.translate(-p.x1,-p.y1));for(var m=t.pstyle("background-image").value,b=new Array(m.length),x=new Array(m.length),w=0,E=0;E0&&void 0!==arguments[0]?arguments[0]:T;l.eleFillStyle(e,t,n)},X=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:L;l.colorStrokeStyle(e,_[0],_[1],_[2],t)},W=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:F;l.colorStrokeStyle(e,R[0],R[1],R[2],t)},H=function(e,t,n,r){var a,i=l.nodePathCache=l.nodePathCache||[],o=Oe("polygon"===n?n+","+r.join(","):n,""+t,""+e,""+q),s=i[o],u=!1;return null!=s?(a=s,u=!0,c.pathCache=a):(a=new Path2D,i[o]=c.pathCache=a),{path:a,cacheHit:u}},K=t.pstyle("shape").strValue,G=t.pstyle("shape-polygon-points").pfValue;if(g){e.translate(d.x,d.y);var U=H(r,a,K,G);h=U.path,v=U.cacheHit}var Z=function(){if(!v){var n=d;g&&(n={x:0,y:0}),l.nodeShapes[l.getNodeShape(t)].draw(h||e,n.x,n.y,r,a,q,c)}g?e.fill(h):e.fill()},$=function(){for(var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:f,r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],a=u.backgrounding,i=0,o=0;o0&&void 0!==arguments[0]&&arguments[0],i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:f;l.hasPie(t)&&(l.drawPie(e,t,i),n&&(g||l.nodeShapes[l.getNodeShape(t)].draw(e,d.x,d.y,r,a,q,c)))},J=function(){var t=(P>0?P:-P)*(arguments.length>0&&void 0!==arguments[0]?arguments[0]:f),n=P>0?0:255;0!==P&&(l.colorFillStyle(e,n,n,n,t),g?e.fill(h):e.fill())},ee=function(){if(D>0){if(e.lineWidth=D,e.lineCap=N,e.lineJoin=B,e.setLineDash)switch(M){case"dotted":e.setLineDash([1,1]);break;case"dashed":e.setLineDash(z),e.lineDashOffset=A;break;case"solid":case"double":e.setLineDash([])}if("center"!==I){if(e.save(),e.lineWidth*=2,"inside"===I)g?e.clip(h):e.clip();else{var t=new Path2D;t.rect(-r/2-D,-a/2-D,r+2*D,a+2*D),t.addPath(h),e.clip(t,"evenodd")}g?e.stroke(h):e.stroke(),e.restore()}else g?e.stroke(h):e.stroke();if("double"===M){e.lineWidth=D/3;var n=e.globalCompositeOperation;e.globalCompositeOperation="destination-out",g?e.stroke(h):e.stroke(),e.globalCompositeOperation=n}e.setLineDash&&e.setLineDash([])}},te=function(){if(O>0){if(e.lineWidth=O,e.lineCap="butt",e.setLineDash)switch(V){case"dotted":e.setLineDash([1,1]);break;case"dashed":e.setLineDash([4,2]);break;case"solid":case"double":e.setLineDash([])}var n=d;g&&(n={x:0,y:0});var i=l.getNodeShape(t),o=D;"inside"===I&&(o=0),"outside"===I&&(o*=2);var s,u=(r+o+(O+j))/r,c=(a+o+(O+j))/a,h=r*u,p=a*c,f=l.nodeShapes[i].points;if(g)s=H(h,p,i,f).path;if("ellipse"===i)l.drawEllipsePath(s||e,n.x,n.y,h,p);else if(["round-diamond","round-heptagon","round-hexagon","round-octagon","round-pentagon","round-polygon","round-triangle","round-tag"].includes(i)){var v=0,y=0,m=0;"round-diamond"===i?v=1.4*(o+j+O):"round-heptagon"===i?(v=1.075*(o+j+O),m=-(o/2+j+O)/35):"round-hexagon"===i?v=1.12*(o+j+O):"round-pentagon"===i?(v=1.13*(o+j+O),m=-(o/2+j+O)/15):"round-tag"===i?(v=1.12*(o+j+O),y=.07*(o/2+O+j)):"round-triangle"===i&&(v=(o+j+O)*(Math.PI/2),m=-(o+j/2+O)/Math.PI),0!==v&&(h=r*(u=(r+v)/r),["round-hexagon","round-tag"].includes(i)||(p=a*(c=(a+v)/a)));for(var b=h/2,x=p/2,w=(q="auto"===q?pn(h,p):q)+(o+O+j)/2,E=new Array(f.length/2),k=new Array(f.length/2),C=0;C0){if(r=r||n.position(),null==a||null==i){var d=n.padding();a=n.width()+2*d,i=n.height()+2*d}this.colorFillStyle(t,l[0],l[1],l[2],s),this.nodeShapes[u].draw(t,r.x,r.y,a+2*o,i+2*o,c),t.fill()}}}};vc.drawNodeOverlay=yc("overlay"),vc.drawNodeUnderlay=yc("underlay"),vc.hasPie=function(e){return(e=e[0])._private.hasPie},vc.drawPie=function(e,t,n,r){t=t[0],r=r||t.position();var a=t.cy().style(),i=t.pstyle("pie-size"),o=r.x,s=r.y,l=t.width(),u=t.height(),c=Math.min(l,u)/2,d=0;this.usePaths()&&(o=0,s=0),"%"===i.units?c*=i.pfValue:void 0!==i.pfValue&&(c=i.pfValue/2);for(var h=1;h<=a.pieBackgroundN;h++){var p=t.pstyle("pie-"+h+"-background-size").value,f=t.pstyle("pie-"+h+"-background-color").value,g=t.pstyle("pie-"+h+"-background-opacity").value*n,v=p/100;v+d>1&&(v=1-d);var y=1.5*Math.PI+2*Math.PI*d,m=y+2*Math.PI*v;0===p||d>=1||d+v>1||(e.beginPath(),e.moveTo(o,s),e.arc(o,s,c,y,m),e.closePath(),this.colorFillStyle(e,f[0],f[1],f[2],g),e.fill(),d+=v)}};var mc={};mc.getPixelRatio=function(){var e=this.data.contexts[0];if(null!=this.forcedPixelRatio)return this.forcedPixelRatio;var t=this.cy.window(),n=e.backingStorePixelRatio||e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1;return(t.devicePixelRatio||1)/n},mc.paintCache=function(e){for(var t,n=this.paintCaches=this.paintCaches||[],r=!0,a=0;ao.minMbLowQualFrames&&(o.motionBlurPxRatio=o.mbPxRBlurry)),o.clearingMotionBlur&&(o.motionBlurPxRatio=1),o.textureDrawLastFrame&&!d&&(c[o.NODE]=!0,c[o.SELECT_BOX]=!0);var m=l.style(),b=l.zoom(),x=void 0!==a?a:b,w=l.pan(),E={x:w.x,y:w.y},k={zoom:b,pan:{x:w.x,y:w.y}},C=o.prevViewport;void 0===C||k.zoom!==C.zoom||k.pan.x!==C.pan.x||k.pan.y!==C.pan.y||g&&!f||(o.motionBlurPxRatio=1),i&&(E=i),x*=s,E.x*=s,E.y*=s;var S=o.getCachedZSortedEles();function P(e,t,n,r,a){var i=e.globalCompositeOperation;e.globalCompositeOperation="destination-out",o.colorFillStyle(e,255,255,255,o.motionBlurTransparency),e.fillRect(t,n,r,a),e.globalCompositeOperation=i}function D(e,r){var s,l,c,d;o.clearingMotionBlur||e!==u.bufferContexts[o.MOTIONBLUR_BUFFER_NODE]&&e!==u.bufferContexts[o.MOTIONBLUR_BUFFER_DRAG]?(s=E,l=x,c=o.canvasWidth,d=o.canvasHeight):(s={x:w.x*p,y:w.y*p},l=b*p,c=o.canvasWidth*p,d=o.canvasHeight*p),e.setTransform(1,0,0,1,0,0),"motionBlur"===r?P(e,0,0,c,d):t||void 0!==r&&!r||e.clearRect(0,0,c,d),n||(e.translate(s.x,s.y),e.scale(l,l)),i&&e.translate(i.x,i.y),a&&e.scale(a,a)}if(d||(o.textureDrawLastFrame=!1),d){if(o.textureDrawLastFrame=!0,!o.textureCache){o.textureCache={},o.textureCache.bb=l.mutableElements().boundingBox(),o.textureCache.texture=o.data.bufferCanvases[o.TEXTURE_BUFFER];var T=o.data.bufferContexts[o.TEXTURE_BUFFER];T.setTransform(1,0,0,1,0,0),T.clearRect(0,0,o.canvasWidth*o.textureMult,o.canvasHeight*o.textureMult),o.render({forcedContext:T,drawOnlyNodeLayer:!0,forcedPxRatio:s*o.textureMult}),(k=o.textureCache.viewport={zoom:l.zoom(),pan:l.pan(),width:o.canvasWidth,height:o.canvasHeight}).mpan={x:(0-k.pan.x)/k.zoom,y:(0-k.pan.y)/k.zoom}}c[o.DRAG]=!1,c[o.NODE]=!1;var _=u.contexts[o.NODE],M=o.textureCache.texture;k=o.textureCache.viewport;_.setTransform(1,0,0,1,0,0),h?P(_,0,0,k.width,k.height):_.clearRect(0,0,k.width,k.height);var B=m.core("outside-texture-bg-color").value,N=m.core("outside-texture-bg-opacity").value;o.colorFillStyle(_,B[0],B[1],B[2],N),_.fillRect(0,0,k.width,k.height);b=l.zoom();D(_,!1),_.clearRect(k.mpan.x,k.mpan.y,k.width/k.zoom/s,k.height/k.zoom/s),_.drawImage(M,k.mpan.x,k.mpan.y,k.width/k.zoom/s,k.height/k.zoom/s)}else o.textureOnViewport&&!t&&(o.textureCache=null);var I=l.extent(),z=o.pinching||o.hoverData.dragging||o.swipePanning||o.data.wheelZooming||o.hoverData.draggingEles||o.cy.animated(),A=o.hideEdgesOnViewport&&z,L=[];if(L[o.NODE]=!c[o.NODE]&&h&&!o.clearedForMotionBlur[o.NODE]||o.clearingMotionBlur,L[o.NODE]&&(o.clearedForMotionBlur[o.NODE]=!0),L[o.DRAG]=!c[o.DRAG]&&h&&!o.clearedForMotionBlur[o.DRAG]||o.clearingMotionBlur,L[o.DRAG]&&(o.clearedForMotionBlur[o.DRAG]=!0),c[o.NODE]||n||r||L[o.NODE]){var O=h&&!L[o.NODE]&&1!==p;D(_=t||(O?o.data.bufferContexts[o.MOTIONBLUR_BUFFER_NODE]:u.contexts[o.NODE]),h&&!O?"motionBlur":void 0),A?o.drawCachedNodes(_,S.nondrag,s,I):o.drawLayeredElements(_,S.nondrag,s,I),o.debug&&o.drawDebugPoints(_,S.nondrag),n||h||(c[o.NODE]=!1)}if(!r&&(c[o.DRAG]||n||L[o.DRAG])){O=h&&!L[o.DRAG]&&1!==p;D(_=t||(O?o.data.bufferContexts[o.MOTIONBLUR_BUFFER_DRAG]:u.contexts[o.DRAG]),h&&!O?"motionBlur":void 0),A?o.drawCachedNodes(_,S.drag,s,I):o.drawCachedElements(_,S.drag,s,I),o.debug&&o.drawDebugPoints(_,S.drag),n||h||(c[o.DRAG]=!1)}if(o.showFps||!r&&c[o.SELECT_BOX]&&!n){if(D(_=t||u.contexts[o.SELECT_BOX]),1==o.selection[4]&&(o.hoverData.selecting||o.touchData.selecting)){b=o.cy.zoom();var R=m.core("selection-box-border-width").value/b;_.lineWidth=R,_.fillStyle="rgba("+m.core("selection-box-color").value[0]+","+m.core("selection-box-color").value[1]+","+m.core("selection-box-color").value[2]+","+m.core("selection-box-opacity").value+")",_.fillRect(o.selection[0],o.selection[1],o.selection[2]-o.selection[0],o.selection[3]-o.selection[1]),R>0&&(_.strokeStyle="rgba("+m.core("selection-box-border-color").value[0]+","+m.core("selection-box-border-color").value[1]+","+m.core("selection-box-border-color").value[2]+","+m.core("selection-box-opacity").value+")",_.strokeRect(o.selection[0],o.selection[1],o.selection[2]-o.selection[0],o.selection[3]-o.selection[1]))}if(u.bgActivePosistion&&!o.hoverData.selecting){b=o.cy.zoom();var V=u.bgActivePosistion;_.fillStyle="rgba("+m.core("active-bg-color").value[0]+","+m.core("active-bg-color").value[1]+","+m.core("active-bg-color").value[2]+","+m.core("active-bg-opacity").value+")",_.beginPath(),_.arc(V.x,V.y,m.core("active-bg-size").pfValue/b,0,2*Math.PI),_.fill()}var F=o.lastRedrawTime;if(o.showFps&&F){F=Math.round(F);var j=Math.round(1e3/F);_.setTransform(1,0,0,1,0,0),_.fillStyle="rgba(255, 0, 0, 0.75)",_.strokeStyle="rgba(255, 0, 0, 0.75)",_.lineWidth=1,_.fillText("1 frame = "+F+" ms = "+j+" fps",0,20);_.strokeRect(0,30,250,20),_.fillRect(0,30,250*Math.min(j/60,1),20)}n||(c[o.SELECT_BOX]=!1)}if(h&&1!==p){var q=u.contexts[o.NODE],Y=o.data.bufferCanvases[o.MOTIONBLUR_BUFFER_NODE],X=u.contexts[o.DRAG],W=o.data.bufferCanvases[o.MOTIONBLUR_BUFFER_DRAG],H=function(e,t,n){e.setTransform(1,0,0,1,0,0),n||!y?e.clearRect(0,0,o.canvasWidth,o.canvasHeight):P(e,0,0,o.canvasWidth,o.canvasHeight);var r=p;e.drawImage(t,0,0,o.canvasWidth*r,o.canvasHeight*r,0,0,o.canvasWidth,o.canvasHeight)};(c[o.NODE]||L[o.NODE])&&(H(q,Y,L[o.NODE]),c[o.NODE]=!1),(c[o.DRAG]||L[o.DRAG])&&(H(X,W,L[o.DRAG]),c[o.DRAG]=!1)}o.prevViewport=k,o.clearingMotionBlur&&(o.clearingMotionBlur=!1,o.motionBlurCleared=!0,o.motionBlur=!0),h&&(o.motionBlurTimeout=setTimeout((function(){o.motionBlurTimeout=null,o.clearedForMotionBlur[o.NODE]=!1,o.clearedForMotionBlur[o.DRAG]=!1,o.motionBlur=!1,o.clearingMotionBlur=!d,o.mbFrames=0,c[o.NODE]=!0,c[o.DRAG]=!0,o.redraw()}),100)),t||l.emit("render")};for(var bc={drawPolygonPath:function(e,t,n,r,a,i){var o=r/2,s=a/2;e.beginPath&&e.beginPath(),e.moveTo(t+o*i[0],n+s*i[1]);for(var l=1;l0&&i>0){h.clearRect(0,0,a,i),h.globalCompositeOperation="source-over";var p=this.getCachedZSortedEles();if(e.full)h.translate(-n.x1*l,-n.y1*l),h.scale(l,l),this.drawElements(h,p),h.scale(1/l,1/l),h.translate(n.x1*l,n.y1*l);else{var f=t.pan(),g={x:f.x*l,y:f.y*l};l*=t.zoom(),h.translate(g.x,g.y),h.scale(l,l),this.drawElements(h,p),h.scale(1/l,1/l),h.translate(-g.x,-g.y)}e.bg&&(h.globalCompositeOperation="destination-over",h.fillStyle=e.bg,h.rect(0,0,a,i),h.fill())}return d},Pc.png=function(e){return Tc(e,this.bufferCanvasImage(e),"image/png")},Pc.jpg=function(e){return Tc(e,this.bufferCanvasImage(e),"image/jpeg")};var _c={nodeShapeImpl:function(e,t,n,r,a,i,o,s){switch(e){case"ellipse":return this.drawEllipsePath(t,n,r,a,i);case"polygon":return this.drawPolygonPath(t,n,r,a,i,o);case"round-polygon":return this.drawRoundPolygonPath(t,n,r,a,i,o,s);case"roundrectangle":case"round-rectangle":return this.drawRoundRectanglePath(t,n,r,a,i,s);case"cutrectangle":case"cut-rectangle":return this.drawCutRectanglePath(t,n,r,a,i,o,s);case"bottomroundrectangle":case"bottom-round-rectangle":return this.drawBottomRoundRectanglePath(t,n,r,a,i,s);case"barrel":return this.drawBarrelPath(t,n,r,a,i)}}},Mc=Nc,Bc=Nc.prototype;function Nc(e){var t=this,n=t.cy.window().document;t.data={canvases:new Array(Bc.CANVAS_LAYERS),contexts:new Array(Bc.CANVAS_LAYERS),canvasNeedsRedraw:new Array(Bc.CANVAS_LAYERS),bufferCanvases:new Array(Bc.BUFFER_COUNT),bufferContexts:new Array(Bc.CANVAS_LAYERS)};var r="-webkit-tap-highlight-color",a="rgba(0,0,0,0)";t.data.canvasContainer=n.createElement("div");var i=t.data.canvasContainer.style;t.data.canvasContainer.style[r]=a,i.position="relative",i.zIndex="0",i.overflow="hidden";var o=e.cy.container();o.appendChild(t.data.canvasContainer),o.style[r]=a;var s={"-webkit-user-select":"none","-moz-user-select":"-moz-none","user-select":"none","-webkit-tap-highlight-color":"rgba(0,0,0,0)","outline-style":"none"};p&&p.userAgent.match(/msie|trident|edge/i)&&(s["-ms-touch-action"]="none",s["touch-action"]="none");for(var l=0;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-1.2/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/components/policies.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/components/service-mesh"}}');var s=n(74848),r=n(28453);const o={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2},{value:"Platform Differences",id:"platform-differences",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," or TDX ",(0,s.jsx)(t.code,{children:"MRCONFIGID"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," or ",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."}),"\n",(0,s.jsx)(t.h2,{id:"platform-differences",children:"Platform Differences"}),"\n",(0,s.jsx)(t.p,{children:"Contrast uses different rules and data sections for different platforms.\nThis results in different policy hashes for different platforms."}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"generate"})," command automatically derives the correct set of rules and data sections from the ",(0,s.jsx)(t.code,{children:"reference-values"})," flag."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"verify"}),", ",(0,s.jsx)(t.code,{children:"set"}),", and ",(0,s.jsx)(t.code,{children:"recover"})," commands need to know the coordinator's expected policy hash to verify its identity.\nBy default these commands assume that the coordinator is using the policy for the ",(0,s.jsx)(t.code,{children:"AKS-CLH-SNP"})," platform.\nIf the coordinator is running on a different platform, the correct policy hash can be looked up in the ",(0,s.jsx)(t.code,{children:"coordinator-policy.hash"})," file bundled with the ",(0,s.jsx)(t.a,{href:"https://github.com/edgelesssys/contrast/releases",children:"Contrast release"}),".\nThe coordinator policy hash can be overwritten using the ",(0,s.jsx)(t.code,{children:"--coordinator-policy-hash"})," flag."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const s={},r=i.createContext(s);function o(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/173fd1a8.3f03ca9c.js b/pr-preview/pr-1071/assets/js/173fd1a8.3f03ca9c.js deleted file mode 100644 index 1f499d8135..0000000000 --- a/pr-preview/pr-1071/assets/js/173fd1a8.3f03ca9c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1514],{71144:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-0.7/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/basics/features.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits"},"next":{"title":"Getting started","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"../architecture",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/17896441.642e26c0.js b/pr-preview/pr-1071/assets/js/17896441.642e26c0.js deleted file mode 100644 index efaa52a851..0000000000 --- a/pr-preview/pr-1071/assets/js/17896441.642e26c0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8401],{51807:(s,c,t)=>{t.d(c,{A:()=>o});var a=t(13404),e=t(49489),n=t(7227);const o={...a.A,Tabs:e.A,TabItem:n.A}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1825.260fa3c3.js b/pr-preview/pr-1071/assets/js/1825.260fa3c3.js deleted file mode 100644 index 050f1434c0..0000000000 --- a/pr-preview/pr-1071/assets/js/1825.260fa3c3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1825],{63933:(e,t,a)=>{function i(e,t){e.accDescr&&t.setAccDescription?.(e.accDescr),e.accTitle&&t.setAccTitle?.(e.accTitle),e.title&&t.setDiagramTitle?.(e.title)}a.d(t,{S:()=>i}),(0,a(10009).K2)(i,"populateCommonDb")},61825:(e,t,a)=>{a.d(t,{diagram:()=>b});var i=a(63933),n=a(8159),r=a(77286),l=a(10009),s=a(78731),o=a(20007),c=l.UI.pie,p={sections:new Map,showData:!1,config:c},d=p.sections,g=p.showData,u=structuredClone(c),h=(0,l.K2)((()=>structuredClone(u)),"getConfig"),m=(0,l.K2)((()=>{d=new Map,g=p.showData,(0,l.IU)()}),"clear"),f=(0,l.K2)((({label:e,value:t})=>{d.has(e)||(d.set(e,t),l.Rm.debug(`added new section: ${e}, with value: ${t}`))}),"addSection"),S=(0,l.K2)((()=>d),"getSections"),x=(0,l.K2)((e=>{g=e}),"setShowData"),w=(0,l.K2)((()=>g),"getShowData"),D={getConfig:h,clear:m,setDiagramTitle:l.ke,getDiagramTitle:l.ab,setAccTitle:l.SV,getAccTitle:l.iN,setAccDescription:l.EI,getAccDescription:l.m7,addSection:f,getSections:S,setShowData:x,getShowData:w},T=(0,l.K2)(((e,t)=>{(0,i.S)(e,t),t.setShowData(e.showData),e.sections.map(t.addSection)}),"populateDb"),$={parse:(0,l.K2)((async e=>{const t=await(0,s.qg)("pie",e);l.Rm.debug(t),T(t,D)}),"parse")},y=(0,l.K2)((e=>`\n .pieCircle{\n stroke: ${e.pieStrokeColor};\n stroke-width : ${e.pieStrokeWidth};\n opacity : ${e.pieOpacity};\n }\n .pieOuterCircle{\n stroke: ${e.pieOuterStrokeColor};\n stroke-width: ${e.pieOuterStrokeWidth};\n fill: none;\n }\n .pieTitleText {\n text-anchor: middle;\n font-size: ${e.pieTitleTextSize};\n fill: ${e.pieTitleTextColor};\n font-family: ${e.fontFamily};\n }\n .slice {\n font-family: ${e.fontFamily};\n fill: ${e.pieSectionTextColor};\n font-size:${e.pieSectionTextSize};\n // fill: white;\n }\n .legend text {\n fill: ${e.pieLegendTextColor};\n font-family: ${e.fontFamily};\n font-size: ${e.pieLegendTextSize};\n }\n`),"getStyles"),C=(0,l.K2)((e=>{const t=[...e.entries()].map((e=>({label:e[0],value:e[1]}))).sort(((e,t)=>t.value-e.value));return(0,o.rLf)().value((e=>e.value))(t)}),"createPieArcs"),b={parser:$,db:D,renderer:{draw:(0,l.K2)(((e,t,a,i)=>{l.Rm.debug("rendering pie chart\n"+e);const s=i.db,c=(0,l.D7)(),p=(0,n.$t)(s.getConfig(),c.pie),d=18,g=450,u=g,h=(0,r.D)(t),m=h.append("g");m.attr("transform","translate(225,225)");const{themeVariables:f}=c;let[S]=(0,n.I5)(f.pieOuterStrokeWidth);S??=2;const x=p.textPosition,w=Math.min(u,g)/2-40,D=(0,o.JLW)().innerRadius(0).outerRadius(w),T=(0,o.JLW)().innerRadius(w*x).outerRadius(w*x);m.append("circle").attr("cx",0).attr("cy",0).attr("r",w+S/2).attr("class","pieOuterCircle");const $=s.getSections(),y=C($),b=[f.pie1,f.pie2,f.pie3,f.pie4,f.pie5,f.pie6,f.pie7,f.pie8,f.pie9,f.pie10,f.pie11,f.pie12],k=(0,o.UMr)(b);m.selectAll("mySlices").data(y).enter().append("path").attr("d",D).attr("fill",(e=>k(e.data.label))).attr("class","pieCircle");let K=0;$.forEach((e=>{K+=e})),m.selectAll("mySlices").data(y).enter().append("text").text((e=>(e.data.value/K*100).toFixed(0)+"%")).attr("transform",(e=>"translate("+T.centroid(e)+")")).style("text-anchor","middle").attr("class","slice"),m.append("text").text(s.getDiagramTitle()).attr("x",0).attr("y",-200).attr("class","pieTitleText");const v=m.selectAll(".legend").data(k.domain()).enter().append("g").attr("class","legend").attr("transform",((e,t)=>"translate(216,"+(22*t-22*k.domain().length/2)+")"));v.append("rect").attr("width",d).attr("height",d).style("fill",k).style("stroke",k),v.data(y).append("text").attr("x",22).attr("y",14).text((e=>{const{label:t,value:a}=e.data;return s.getShowData()?`${t} [${a}]`:t}));const A=512+Math.max(...v.selectAll("text").nodes().map((e=>e?.getBoundingClientRect().width??0)));h.attr("viewBox",`0 0 ${A} 450`),(0,l.a$)(h,g,A,p.useMaxWidth)}),"draw")},styles:y}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/197c7105.a9227bd1.js b/pr-preview/pr-1071/assets/js/197c7105.a9227bd1.js deleted file mode 100644 index 93b69e2282..0000000000 --- a/pr-preview/pr-1071/assets/js/197c7105.a9227bd1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7742],{82557:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-1.2/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/deployment.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Encrypted volume mount","permalink":"/contrast/pr-preview/pr-1071/examples/mysql"},"next":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/troubleshooting"}}');var r=t(74848),a=t(28453);const i={},o="Workload deployment",l={},c=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"Security review",id:"security-review",level:3},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2},{value:"Recover the Coordinator",id:"recover-the-coordinator",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components},{TabItem:t,Tabs:s}=n;return t||u("TabItem",!0),s||u("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,r.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/getting-started/cluster-setup",children:"setup guide"})," on how to set up a cluster on AKS."]})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/getting-started/bare-metal",children:"setup guide"})," on how to set up a bare-metal cluster."]})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/getting-started/bare-metal",children:"setup guide"})," on how to set up a bare-metal cluster."]})})]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast depends on a ",(0,r.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:["custom Kubernetes ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," (",(0,r.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,r.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-aks-clh-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-aks-clh-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,r.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,r.jsx)(n.h3,{id:"security-review",children:"Security review"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast ensures integrity and confidentiality of the applications, but interactions with untrusted systems require the developers' attention.\nReview the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/architecture/security-considerations",children:"security considerations"})," and the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates",children:"certificates"})," section for writing secure Contrast application."]}),"\n",(0,r.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,r.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,r.jsxs)(s,{groupId:"yaml-source",children:[(0,r.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"helm",label:"helm",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"copy",label:"copy",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,r.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,r.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,r.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,r.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,r.jsxs)(n.p,{children:["In the initialization process, the ",(0,r.jsx)(n.code,{children:"contrast-secrets"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,r.jsxs)(s,{groupId:"tls",children:[(0,r.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,r.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,r.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,r.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,r.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,r.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,r.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,r.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,r.jsxs)(n.p,{children:["During the ",(0,r.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,r.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,r.jsxs)(t,{value:"go",label:"Go integration",children:[(0,r.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,r.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,r.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,r.jsxs)(s,{groupId:"golang-tls-setup",children:[(0,r.jsx)(t,{value:"client",label:"Client",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,r.jsx)(t,{value:"server",label:"Server",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(n.p,{children:["Run the ",(0,r.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,r.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp resources/\n"})})}),(0,r.jsxs)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp resources/\n"})}),(0,r.jsx)(n.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(n.p,{children:["On bare-metal SEV-SNP, ",(0,r.jsx)(n.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(n.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(n.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,r.jsxs)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx resources/\n"})}),(0,r.jsx)(n.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(n.p,{children:["On bare-metal TDX, ",(0,r.jsx)(n.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(n.code,{children:"MinimumTeeTcbSvn"})," and ",(0,r.jsx)(n.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(n.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,r.jsx)(n.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,r.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,r.jsxs)(s,{groupId:"injection",children:[(0,r.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,r.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,r.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,r.jsx)(n.code,{children:"generate"})," command."]}),(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp --skip-initializer resources/\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp --skip-initializer resources/\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx --skip-initializer resources/\n"})})})]})]}),(0,r.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,r.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,r.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,r.jsx)(n.code,{children:"contrast-secrets"})," ",(0,r.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:v1.2.0@sha256:942c019b751762540c45d827c1667e5e9f228ccf72c8cc44f11fc428610d196e"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /contrast\n name: contrast-secrets\n volumes:\n - emptyDir: {}\n name: contrast-secrets\n'})}),"\n",(0,r.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,r.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,r.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,r.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,r.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,r.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,r.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,r.jsx)(n.p,{children:"This will use the reference values from the manifest file to attest the Coordinator.\nAfter this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,r.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,r.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the\nservice mesh root certificate and the history of manifests into the ",(0,r.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies\nreferenced in the active manifest are also written to the directory. The verification will fail if the active\nmanifest at the Coordinator doesn't match the manifest passed to the CLI."]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,r.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,r.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, attempting to connect with curl and the mesh CA certificate will throw the following error:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,r.jsxs)(n.p,{children:["Using ",(0,r.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,r.jsx)(n.h2,{id:"recover-the-coordinator",children:"Recover the Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material.\nFor demonstration purposes, you can simulate this scenario by deleting the Coordinator pod."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl delete pod -l app.kubernetes.io/name=coordinator\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet.\nYou can confirm this by running ",(0,r.jsx)(n.code,{children:"verify"})," again, or you can restart a workload pod, which should stay in the initialization phase.\nHowever, the secret seed in your working directory is sufficient to recover the coordinator."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast recover -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsx)(n.p,{children:"Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state.\nYou can now verify the Coordinator again, which should return the same manifest you set before."}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The recovery process invalidates the mesh CA certificate:\nexisting workloads won't be able to communicate with workloads newly spawned.\nAll workloads should be restarted after the recovery succeeded."})}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function u(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>o});var s=t(96540);const r={},a=s.createContext(r);function i(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1ab97833.c3577891.js b/pr-preview/pr-1071/assets/js/1ab97833.c3577891.js deleted file mode 100644 index 9619bf5e34..0000000000 --- a/pr-preview/pr-1071/assets/js/1ab97833.c3577891.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[985],{29083:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-1.0/components/overview.md","sourceDirName":"components","slug":"/components/overview","permalink":"/contrast/pr-preview/pr-1071/1.0/components/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/components/overview.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/1.0/troubleshooting"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/1.0/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},l=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(45426).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},45426:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1c9b88ee.c2b9b81d.js b/pr-preview/pr-1071/assets/js/1c9b88ee.c2b9b81d.js deleted file mode 100644 index 54609048c5..0000000000 --- a/pr-preview/pr-1071/assets/js/1c9b88ee.c2b9b81d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1560],{62538:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-0.6/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/getting-started/install.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Getting started","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup"}}');var r=n(74848),a=n(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/latest/download/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>i});var s=n(96540);const r={},a=s.createContext(r);function o(t){const e=s.useContext(a);return s.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),s.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1de90583.1ca7e4e9.js b/pr-preview/pr-1071/assets/js/1de90583.1ca7e4e9.js deleted file mode 100644 index 3e29056bbe..0000000000 --- a/pr-preview/pr-1071/assets/js/1de90583.1ca7e4e9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6200],{64920:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.8","label":"0.8","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.8","isLast":false,"docsSidebars":{"docs":[{"type":"link","label":"What is Contrast?","href":"/contrast/pr-preview/pr-1071/0.8/","docId":"intro","unlisted":false},{"type":"category","label":"Basics","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/0.8/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/0.8/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false}],"collapsible":true},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/0.8/deployment","docId":"deployment","unlisted":false},{"type":"link","label":"Troubleshooting","href":"/contrast/pr-preview/pr-1071/0.8/troubleshooting","docId":"troubleshooting","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Overview","href":"/contrast/pr-preview/pr-1071/0.8/components/overview","docId":"components/overview","unlisted":false},{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/0.8/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/0.8/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/0.8/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/0.8/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Secrets & recovery","href":"/contrast/pr-preview/pr-1071/0.8/architecture/secrets","docId":"architecture/secrets","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/0.8/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/0.8/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/0.8/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/0.8/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"architecture/secrets":{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/overview":{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"troubleshooting":{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1e7c9753.62495ac8.js b/pr-preview/pr-1071/assets/js/1e7c9753.62495ac8.js deleted file mode 100644 index 96147c2d48..0000000000 --- a/pr-preview/pr-1071/assets/js/1e7c9753.62495ac8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3391],{99028:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-1.1/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/basics/features.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/install"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/1fefe6de.55a1a00a.js b/pr-preview/pr-1071/assets/js/1fefe6de.55a1a00a.js deleted file mode 100644 index d74ca90c46..0000000000 --- a/pr-preview/pr-1071/assets/js/1fefe6de.55a1a00a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6463],{71758:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","source":"@site/versioned_docs/version-1.2/troubleshooting.md","sourceDirName":".","slug":"/troubleshooting","permalink":"/contrast/pr-preview/pr-1071/troubleshooting","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/troubleshooting.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/deployment"},"next":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/components/overview"}}');var i=t(74848),s=t(28453);const a={},r="Troubleshooting",c={},l=[{value:"Logging",id:"logging",level:2},{value:"CLI",id:"cli",level:3},{value:"Coordinator and Initializer",id:"coordinator-and-initializer",level:3},{value:"Pod fails to start",id:"pod-fails-to-start",level:2},{value:"Regenerating the policies",id:"regenerating-the-policies",level:3},{value:"Pin container images",id:"pin-container-images",level:3},{value:"Validate Contrast components match",id:"validate-contrast-components-match",level:3}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"troubleshooting",children:"Troubleshooting"})}),"\n",(0,i.jsx)(n.p,{children:"This section contains information on how to debug your Contrast deployment."}),"\n",(0,i.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,i.jsx)(n.p,{children:"Collecting logs can be a good first step to identify problems in your\ndeployment. Both the CLI and the Contrast Coordinator as well as the Initializer\ncan be configured to emit additional logs."}),"\n",(0,i.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,i.jsxs)(n.p,{children:["The CLI logs can be configured with the ",(0,i.jsx)(n.code,{children:"--log-level"})," command-line flag, which\ncan be set to either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"})," or ",(0,i.jsx)(n.code,{children:"error"}),". The default is ",(0,i.jsx)(n.code,{children:"info"}),".\nSetting this to ",(0,i.jsx)(n.code,{children:"debug"})," can get more fine-grained information as to where the\nproblem lies."]}),"\n",(0,i.jsx)(n.h3,{id:"coordinator-and-initializer",children:"Coordinator and Initializer"}),"\n",(0,i.jsxs)(n.p,{children:["The logs from the Coordinator and the Initializer can be configured via the\nenvironment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"}),", ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," and\n",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"})," can be set to one of either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"}),", or\n",(0,i.jsx)(n.code,{children:"error"}),", similar to the CLI (defaults to ",(0,i.jsx)(n.code,{children:"info"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," can be set to ",(0,i.jsx)(n.code,{children:"text"})," or ",(0,i.jsx)(n.code,{children:"json"}),", determining the output\nformat (defaults to ",(0,i.jsx)(n.code,{children:"text"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," is a comma-separated list of subsystems that should\nbe enabled for logging, which are disabled by default. Subsystems include:\n",(0,i.jsx)(n.code,{children:"kds-getter"}),", ",(0,i.jsx)(n.code,{children:"issuer"})," and ",(0,i.jsx)(n.code,{children:"validator"}),".\nTo enable all subsystems, use ",(0,i.jsx)(n.code,{children:"*"})," as the value for this environment variable.\nWarnings and error messages from subsystems get printed regardless of whether\nthe subsystem is listed in the ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," environment variable."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"To configure debug logging with all subsystems for your Coordinator, add the\nfollowing variables to your container definition."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n containers:\n image: "ghcr.io/edgelesssys/contrast/coordinator:v1.2.0@sha256:458e408cd8f390b258b84a1236464febf63bda08f0be91a585c5a14500564cc8"\n name: coordinator\n env:\n - name: CONTRAST_LOG_LEVEL\n value: debug\n - name: CONTRAST_LOG_SUBSYSTEMS\n value: "*"\n # ...\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["While the Contrast Coordinator has a policy that allows certain configurations,\nthe Initializer and service mesh don't. When changing environment variables of other\nparts than the Coordinator, ensure to rerun ",(0,i.jsx)(n.code,{children:"contrast generate"})," to update the policy."]})}),"\n",(0,i.jsxs)(n.p,{children:["To access the logs generated by the Coordinator, you can use ",(0,i.jsx)(n.code,{children:"kubectl"})," with the\nfollowing command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl logs \n"})}),"\n",(0,i.jsx)(n.h2,{id:"pod-fails-to-start",children:"Pod fails to start"}),"\n",(0,i.jsxs)(n.p,{children:["If the Coordinator or a workload pod fails to even start, it can be helpful to\nlook at the events of the pod during the startup process using the ",(0,i.jsx)(n.code,{children:"describe"}),"\ncommand."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n events --for pod/\n"})}),"\n",(0,i.jsx)(n.p,{children:"Example output:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'LAST SEEN TYPE REASON OBJECT MESSAGE\n32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...\n'})}),"\n",(0,i.jsx)(n.p,{children:"A common error, as in this example, is that the container creation was blocked by the\npolicy. Potential reasons are a modification of the deployment YAML without updating\nthe policies afterward, or a version mismatch between Contrast components."}),"\n",(0,i.jsx)(n.h3,{id:"regenerating-the-policies",children:"Regenerating the policies"}),"\n",(0,i.jsx)(n.p,{children:"To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated\npolicies, rerun"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast generate\n"})}),"\n",(0,i.jsx)(n.p,{children:"on your deployment. If any of the policy annotations change, re-deploy with the updated policies."}),"\n",(0,i.jsx)(n.h3,{id:"pin-container-images",children:"Pin container images"}),"\n",(0,i.jsx)(n.p,{children:"When generating the policies, Contrast will download the images specified in your deployment\nYAML and include their cryptographic identity. If the image tag is moved to another\ncontainer image after the policy has been generated, the image downloaded at deploy time\nwill differ from the one at generation time, and the policy enforcement won't allow the\ncontainer to be started in the pod VM."}),"\n",(0,i.jsxs)(n.p,{children:["To ensure the correct image is always used, pin the container image to a fixed ",(0,i.jsx)(n.code,{children:"sha256"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This way, the same image will still be pulled when the container tag (",(0,i.jsx)(n.code,{children:"22.04"}),") is moved\nto another image."]}),"\n",(0,i.jsx)(n.h3,{id:"validate-contrast-components-match",children:"Validate Contrast components match"}),"\n",(0,i.jsx)(n.p,{children:"A version mismatch between Contrast components can cause policy validation or attestation\nto fail. Each Contrast runtime is identifiable based on its (shortened) measurement value\nused to name the runtime class version."}),"\n",(0,i.jsx)(n.p,{children:"First, analyze which runtime class is currently installed in your cluster by running"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl get runtimeclasses\n"})}),"\n",(0,i.jsx)(n.p,{children:"This should give you output similar to the following one."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"NAME HANDLER AGE\ncontrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h\nkata-cc-isolation kata-cc 45d\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided\nby the AKS CoCo preview, which isn't used by Contrast)."}),"\n",(0,i.jsx)(n.p,{children:"Next, check if the pod that won't start has the correct runtime class configured, and the\nCoordinator uses the exact same runtime:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n get -o=jsonpath='{.spec.runtimeClassName}' pod/\nkubectl -n get -o=jsonpath='{.spec.runtimeClassName}' pod/\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output should list the runtime class the pod is using:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast-cc-aks-clh-snp-7173acb5\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Version information about the currently used CLI can be obtained via the ",(0,i.jsx)(n.code,{children:"version"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast --version\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast version v0.X.0\n\n runtime handler: contrast-cc-aks-clh-snp-7173acb5\n launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35\n genpolicy version: 3.2.0.azl1.genpolicy0\n image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...\n ghcr.io/edgelesssys/contrast/initializer@sha256:...\n"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(96540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/200ecf61.42b16ee7.js b/pr-preview/pr-1071/assets/js/200ecf61.42b16ee7.js deleted file mode 100644 index 5c7a3e5fc8..0000000000 --- a/pr-preview/pr-1071/assets/js/200ecf61.42b16ee7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8904],{79880:e=>{e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Network Encryption","slug":"/category/network-encryption","permalink":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption","sidebar":"docs","navigation":{"previous":{"title":"PKI","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki"},"next":{"title":"Sidecar","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/20382dd7.24536267.js b/pr-preview/pr-1071/assets/js/20382dd7.24536267.js deleted file mode 100644 index e04c2fa522..0000000000 --- a/pr-preview/pr-1071/assets/js/20382dd7.24536267.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3357],{33961:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"architecture/attestation/runtime-policies","title":"runtime-policies","description":"","source":"@site/versioned_docs/version-0.5/architecture/attestation/runtime-policies.md","sourceDirName":"architecture/attestation","slug":"/architecture/attestation/runtime-policies","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/attestation/runtime-policies.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Pod VM","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm"},"next":{"title":"Manifest","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest"}}');var i=n(74848),s=n(28453);const o={},c=void 0,a={},u=[];function p(t){return(0,i.jsx)(i.Fragment,{})}function d(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(p,{...t})}):p()}},28453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>c});var r=n(96540);const i={},s=r.createContext(i);function o(t){const e=r.useContext(s);return r.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function c(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(i):t.components||i:o(t.components),r.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/207bb774.937e3159.js b/pr-preview/pr-1071/assets/js/207bb774.937e3159.js deleted file mode 100644 index 1a09c99f9c..0000000000 --- a/pr-preview/pr-1071/assets/js/207bb774.937e3159.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[430],{50880:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"about/index","title":"About","description":"","source":"@site/versioned_docs/version-0.6/about/index.md","sourceDirName":"about","slug":"/about/","permalink":"/contrast/pr-preview/pr-1071/0.6/about/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/about/index.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Known limitations","permalink":"/contrast/pr-preview/pr-1071/0.6/known-limitations"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/0.6/about/telemetry"}}');var o=n(74848),s=n(28453),c=n(44074);const i={},a="About",l={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"about",children:"About"})}),"\n","\n",(0,o.jsx)(c.A,{})]})}function m(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>k});var r=n(96540),o=n(34164),s=n(45357),c=n(14783),i=n(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function m(){const e=d();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const o=n.select(t),s=n.pluralForms.indexOf(o);return r[Math.min(s,r.length-1)]}(n,t,e)}}var p=n(40877),h=n(23230),f=n(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=n(74848);function b(e){let{href:t,children:n}=e;return(0,g.jsx)(c.A,{href:t,className:(0,o.A)("card padding--lg",x.cardContainer),children:n})}function j(e){let{href:t,icon:n,title:r,description:s}=e;return(0,g.jsxs)(b,{href:t,children:[(0,g.jsxs)(f.A,{as:"h2",className:(0,o.A)("text--truncate",x.cardTitle),title:r,children:[n," ",r]}),s&&(0,g.jsx)("p",{className:(0,o.A)("text--truncate",x.cardDescription),title:s,children:s})]})}function v(e){let{item:t}=e;const n=(0,s.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,h.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,g.jsx)(j,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function w(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,s.cC)(t.docId??void 0);return(0,g.jsx)(j,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function y(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(w,{item:t});case"category":return(0,g.jsx)(v,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function A(e){let{className:t}=e;const n=(0,s.$S)();return(0,g.jsx)(k,{items:n.items,className:t})}function k(e){const{items:t,className:n}=e;if(!t)return(0,g.jsx)(A,{...e});const r=(0,s.d1)(t);return(0,g.jsx)("section",{className:(0,o.A)("row",n),children:r.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(y,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>i});var r=n(96540);const o={},s=r.createContext(o);function c(e){const t=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:c(e.components),r.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/20e0cfa9.efdde374.js b/pr-preview/pr-1071/assets/js/20e0cfa9.efdde374.js deleted file mode 100644 index b013ab8cea..0000000000 --- a/pr-preview/pr-1071/assets/js/20e0cfa9.efdde374.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8403],{69107:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-0.7/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/basics/confidential-containers.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Contrast","permalink":"/contrast/pr-preview/pr-1071/0.7/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2130.a7c31b12.js b/pr-preview/pr-1071/assets/js/2130.a7c31b12.js deleted file mode 100644 index edb87e73cd..0000000000 --- a/pr-preview/pr-1071/assets/js/2130.a7c31b12.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2130],{22130:(e,t,r)=>{r.d(t,{default:()=>Ja});class a{constructor(e,t,r){this.lexer=void 0,this.start=void 0,this.end=void 0,this.lexer=e,this.start=t,this.end=r}static range(e,t){return t?e&&e.loc&&t.loc&&e.loc.lexer===t.loc.lexer?new a(e.loc.lexer,e.loc.start,t.loc.end):null:e&&e.loc}}class n{constructor(e,t){this.text=void 0,this.loc=void 0,this.noexpand=void 0,this.treatAsRelax=void 0,this.text=e,this.loc=t}range(e,t){return new n(t,a.range(this,e))}}class i{constructor(e,t){this.name=void 0,this.position=void 0,this.length=void 0,this.rawMessage=void 0;var r,a,n="KaTeX parse error: "+e,o=t&&t.loc;if(o&&o.start<=o.end){var s=o.lexer.input;r=o.start,a=o.end,r===s.length?n+=" at end of input: ":n+=" at position "+(r+1)+": ";var l=s.slice(r,a).replace(/[^]/g,"$&\u0332");n+=(r>15?"\u2026"+s.slice(r-15,r):s.slice(0,r))+l+(a+15":">","<":"<",'"':""","'":"'"},l=/[&><"']/g;var h=function e(t){return"ordgroup"===t.type||"color"===t.type?1===t.body.length?e(t.body[0]):t:"font"===t.type?e(t.body):t},m={contains:function(e,t){return-1!==e.indexOf(t)},deflt:function(e,t){return void 0===e?t:e},escape:function(e){return String(e).replace(l,(e=>s[e]))},hyphenate:function(e){return e.replace(o,"-$1").toLowerCase()},getBaseElem:h,isCharacterBox:function(e){var t=h(e);return"mathord"===t.type||"textord"===t.type||"atom"===t.type},protocolFromUrl:function(e){var t=/^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(e);return t?":"!==t[2]?null:/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(t[1])?t[1].toLowerCase():null:"_relative"}},c={displayMode:{type:"boolean",description:"Render math in display mode, which puts the math in display style (so \\int and \\sum are large, for example), and centers the math on the page on its own line.",cli:"-d, --display-mode"},output:{type:{enum:["htmlAndMathml","html","mathml"]},description:"Determines the markup language of the output.",cli:"-F, --format "},leqno:{type:"boolean",description:"Render display math in leqno style (left-justified tags)."},fleqn:{type:"boolean",description:"Render display math flush left."},throwOnError:{type:"boolean",default:!0,cli:"-t, --no-throw-on-error",cliDescription:"Render errors (in the color given by --error-color) instead of throwing a ParseError exception when encountering an error."},errorColor:{type:"string",default:"#cc0000",cli:"-c, --error-color ",cliDescription:"A color string given in the format 'rgb' or 'rrggbb' (no #). This option determines the color of errors rendered by the -t option.",cliProcessor:e=>"#"+e},macros:{type:"object",cli:"-m, --macro ",cliDescription:"Define custom macro of the form '\\foo:expansion' (use multiple -m arguments for multiple macros).",cliDefault:[],cliProcessor:(e,t)=>(t.push(e),t)},minRuleThickness:{type:"number",description:"Specifies a minimum thickness, in ems, for fraction lines, `\\sqrt` top lines, `{array}` vertical lines, `\\hline`, `\\hdashline`, `\\underline`, `\\overline`, and the borders of `\\fbox`, `\\boxed`, and `\\fcolorbox`.",processor:e=>Math.max(0,e),cli:"--min-rule-thickness ",cliProcessor:parseFloat},colorIsTextColor:{type:"boolean",description:"Makes \\color behave like LaTeX's 2-argument \\textcolor, instead of LaTeX's one-argument \\color mode change.",cli:"-b, --color-is-text-color"},strict:{type:[{enum:["warn","ignore","error"]},"boolean","function"],description:"Turn on strict / LaTeX faithfulness mode, which throws an error if the input uses features that are not supported by LaTeX.",cli:"-S, --strict",cliDefault:!1},trust:{type:["boolean","function"],description:"Trust the input, enabling all HTML features such as \\url.",cli:"-T, --trust"},maxSize:{type:"number",default:1/0,description:"If non-zero, all user-specified sizes, e.g. in \\rule{500em}{500em}, will be capped to maxSize ems. Otherwise, elements and spaces can be arbitrarily large",processor:e=>Math.max(0,e),cli:"-s, --max-size ",cliProcessor:parseInt},maxExpand:{type:"number",default:1e3,description:"Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to Infinity, the macro expander will try to fully expand as in LaTeX.",processor:e=>Math.max(0,e),cli:"-e, --max-expand ",cliProcessor:e=>"Infinity"===e?1/0:parseInt(e)},globalGroup:{type:"boolean",cli:!1}};function p(e){if(e.default)return e.default;var t=e.type,r=Array.isArray(t)?t[0]:t;if("string"!=typeof r)return r.enum[0];switch(r){case"boolean":return!1;case"string":return"";case"number":return 0;case"object":return{}}}class u{constructor(e){for(var t in this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,this.globalGroup=void 0,e=e||{},c)if(c.hasOwnProperty(t)){var r=c[t];this[t]=void 0!==e[t]?r.processor?r.processor(e[t]):e[t]:p(r)}}reportNonstrict(e,t,r){var a=this.strict;if("function"==typeof a&&(a=a(e,t,r)),a&&"ignore"!==a){if(!0===a||"error"===a)throw new i("LaTeX-incompatible input and strict mode is set to 'error': "+t+" ["+e+"]",r);"warn"===a?"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+t+" ["+e+"]"):"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+t+" ["+e+"]")}}useStrictBehavior(e,t,r){var a=this.strict;if("function"==typeof a)try{a=a(e,t,r)}catch(n){a="error"}return!(!a||"ignore"===a)&&(!0===a||"error"===a||("warn"===a?("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+t+" ["+e+"]"),!1):("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+t+" ["+e+"]"),!1)))}isTrusted(e){if(e.url&&!e.protocol){var t=m.protocolFromUrl(e.url);if(null==t)return!1;e.protocol=t}var r="function"==typeof this.trust?this.trust(e):this.trust;return Boolean(r)}}class d{constructor(e,t,r){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=e,this.size=t,this.cramped=r}sup(){return g[f[this.id]]}sub(){return g[v[this.id]]}fracNum(){return g[b[this.id]]}fracDen(){return g[y[this.id]]}cramp(){return g[x[this.id]]}text(){return g[w[this.id]]}isTight(){return this.size>=2}}var g=[new d(0,0,!1),new d(1,0,!0),new d(2,1,!1),new d(3,1,!0),new d(4,2,!1),new d(5,2,!0),new d(6,3,!1),new d(7,3,!0)],f=[4,5,4,5,6,7,6,7],v=[5,5,5,5,7,7,7,7],b=[2,3,4,5,6,7,6,7],y=[3,3,5,5,7,7,7,7],x=[1,1,3,3,5,5,7,7],w=[0,1,2,3,2,3,2,3],k={DISPLAY:g[0],TEXT:g[2],SCRIPT:g[4],SCRIPTSCRIPT:g[6]},S=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"armenian",blocks:[[1328,1423]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}];var M=[];function z(e){for(var t=0;t=M[t]&&e<=M[t+1])return!0;return!1}S.forEach((e=>e.blocks.forEach((e=>M.push(...e)))));var A=80,T={doubleleftarrow:"M262 157\nl10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3\n 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28\n 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5\nc2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5\n 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87\n-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7\n-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z\nm8 0v40h399730v-40zm0 194v40h399730v-40z",doublerightarrow:"M399738 392l\n-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5\n 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88\n-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68\n-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18\n-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782\nc-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3\n-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z",leftarrow:"M400000 241H110l3-3c68.7-52.7 113.7-120\n 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8\n-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247\nc-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208\n 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3\n 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202\n l-3-3h399890zM100 241v40h399900v-40z",leftbrace:"M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117\n-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7\n 5-6 9-10 13-.7 1-7.3 1-20 1H6z",leftbraceunder:"M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13\n 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688\n 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7\n-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z",leftgroup:"M400000 80\nH435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0\n 435 0h399565z",leftgroupunder:"M400000 262\nH435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219\n 435 219h399565z",leftharpoon:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3\n-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5\n-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7\n-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z",leftharpoonplus:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5\n 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3\n-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7\n-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z\nm0 0v40h400000v-40z",leftharpoondown:"M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333\n 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5\n 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667\n-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z",leftharpoondownplus:"M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12\n 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7\n-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0\nv40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z",lefthook:"M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5\n-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3\n-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21\n 71.5 23h399859zM103 281v-40h399897v40z",leftlinesegment:"M40 281 V428 H0 V94 H40 V241 H400000 v40z\nM40 281 V428 H0 V94 H40 V241 H400000 v40z",leftmapsto:"M40 281 V448H0V74H40V241H400000v40z\nM40 281 V448H0V74H40V241H400000v40z",leftToFrom:"M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23\n-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8\nc28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3\n 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z",longequal:"M0 50 h400000 v40H0z m0 194h40000v40H0z\nM0 50 h400000 v40H0z m0 194h40000v40H0z",midbrace:"M200428 334\nc-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14\n-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7\n 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11\n 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z",midbraceunder:"M199572 214\nc100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14\n 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3\n 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0\n-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z",oiintSize1:"M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6\n-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z\nm368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8\n60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z",oiintSize2:"M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8\n-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z\nm502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2\nc0 110 84 276 504 276s502.4-166 502.4-276z",oiiintSize1:"M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6\n-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z\nm525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0\n85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z",oiiintSize2:"M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8\n-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z\nm770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1\nc0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z",rightarrow:"M0 241v40h399891c-47.3 35.3-84 78-110 128\n-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20\n 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7\n 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85\n-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n 151.7 139 205zm0 0v40h399900v-40z",rightbrace:"M400000 542l\n-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5\ns-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1\nc124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z",rightbraceunder:"M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3\n 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237\n-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z",rightgroup:"M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0\n 3-1 3-3v-38c-76-158-257-219-435-219H0z",rightgroupunder:"M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18\n 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z",rightharpoon:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3\n-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2\n-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58\n 69.2 92 94.5zm0 0v40h399900v-40z",rightharpoonplus:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11\n-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7\n 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z\nm0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z",rightharpoondown:"M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8\n 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5\n-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95\n-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z",rightharpoondownplus:"M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8\n 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3\n 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3\n-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z\nm0-194v40h400000v-40zm0 0v40h400000v-40z",righthook:"M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3\n 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0\n-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21\n 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z",rightlinesegment:"M399960 241 V94 h40 V428 h-40 V281 H0 v-40z\nM399960 241 V94 h40 V428 h-40 V281 H0 v-40z",rightToFrom:"M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23\n 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32\n-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142\n-167z M100 147v40h399900v-40zM0 341v40h399900v-40z",twoheadleftarrow:"M0 167c68 40\n 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69\n-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3\n-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19\n-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101\n 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z",twoheadrightarrow:"M400000 167\nc-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3\n 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42\n 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333\n-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70\n 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z",tilde1:"M200 55.538c-77 0-168 73.953-177 73.953-3 0-7\n-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0\n 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0\n 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128\n-68.267.847-113-73.952-191-73.952z",tilde2:"M344 55.266c-142 0-300.638 81.316-311.5 86.418\n-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9\n 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114\nc1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751\n 181.476 676 181.476c-149 0-189-126.21-332-126.21z",tilde3:"M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457\n-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0\n 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697\n 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696\n -338 0-409-156.573-744-156.573z",tilde4:"M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345\n-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409\n 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9\n 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409\n -175.236-744-175.236z",vec:"M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5\n3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11\n10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63\n-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1\n-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59\nH213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359\nc-16-25.333-24-45-24-59z",widehat1:"M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22\nc-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z",widehat2:"M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat3:"M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat4:"M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widecheck1:"M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1,\n-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z",widecheck2:"M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck3:"M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck4:"M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",baraboveleftarrow:"M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202\nc4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5\nc-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130\ns-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47\n121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6\ns2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11\nc0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z\nM100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z",rightarrowabovebar:"M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32\n-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0\n13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39\n-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5\n-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z",baraboveshortleftharpoon:"M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17\nc2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21\nc-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40\nc-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z\nM0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z",rightharpoonaboveshortbar:"M0,241 l0,40c399126,0,399993,0,399993,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z",shortbaraboveleftharpoon:"M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9,\n1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7,\n-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z\nM93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z",shortrightharpoonabovebar:"M53,241l0,40c398570,0,399437,0,399437,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z"};class B{constructor(e){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=e,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}hasClass(e){return m.contains(this.classes,e)}toNode(){for(var e=document.createDocumentFragment(),t=0;te.toText())).join("")}}var C={"AMS-Regular":{32:[0,0,0,0,.25],65:[0,.68889,0,0,.72222],66:[0,.68889,0,0,.66667],67:[0,.68889,0,0,.72222],68:[0,.68889,0,0,.72222],69:[0,.68889,0,0,.66667],70:[0,.68889,0,0,.61111],71:[0,.68889,0,0,.77778],72:[0,.68889,0,0,.77778],73:[0,.68889,0,0,.38889],74:[.16667,.68889,0,0,.5],75:[0,.68889,0,0,.77778],76:[0,.68889,0,0,.66667],77:[0,.68889,0,0,.94445],78:[0,.68889,0,0,.72222],79:[.16667,.68889,0,0,.77778],80:[0,.68889,0,0,.61111],81:[.16667,.68889,0,0,.77778],82:[0,.68889,0,0,.72222],83:[0,.68889,0,0,.55556],84:[0,.68889,0,0,.66667],85:[0,.68889,0,0,.72222],86:[0,.68889,0,0,.72222],87:[0,.68889,0,0,1],88:[0,.68889,0,0,.72222],89:[0,.68889,0,0,.72222],90:[0,.68889,0,0,.66667],107:[0,.68889,0,0,.55556],160:[0,0,0,0,.25],165:[0,.675,.025,0,.75],174:[.15559,.69224,0,0,.94666],240:[0,.68889,0,0,.55556],295:[0,.68889,0,0,.54028],710:[0,.825,0,0,2.33334],732:[0,.9,0,0,2.33334],770:[0,.825,0,0,2.33334],771:[0,.9,0,0,2.33334],989:[.08167,.58167,0,0,.77778],1008:[0,.43056,.04028,0,.66667],8245:[0,.54986,0,0,.275],8463:[0,.68889,0,0,.54028],8487:[0,.68889,0,0,.72222],8498:[0,.68889,0,0,.55556],8502:[0,.68889,0,0,.66667],8503:[0,.68889,0,0,.44445],8504:[0,.68889,0,0,.66667],8513:[0,.68889,0,0,.63889],8592:[-.03598,.46402,0,0,.5],8594:[-.03598,.46402,0,0,.5],8602:[-.13313,.36687,0,0,1],8603:[-.13313,.36687,0,0,1],8606:[.01354,.52239,0,0,1],8608:[.01354,.52239,0,0,1],8610:[.01354,.52239,0,0,1.11111],8611:[.01354,.52239,0,0,1.11111],8619:[0,.54986,0,0,1],8620:[0,.54986,0,0,1],8621:[-.13313,.37788,0,0,1.38889],8622:[-.13313,.36687,0,0,1],8624:[0,.69224,0,0,.5],8625:[0,.69224,0,0,.5],8630:[0,.43056,0,0,1],8631:[0,.43056,0,0,1],8634:[.08198,.58198,0,0,.77778],8635:[.08198,.58198,0,0,.77778],8638:[.19444,.69224,0,0,.41667],8639:[.19444,.69224,0,0,.41667],8642:[.19444,.69224,0,0,.41667],8643:[.19444,.69224,0,0,.41667],8644:[.1808,.675,0,0,1],8646:[.1808,.675,0,0,1],8647:[.1808,.675,0,0,1],8648:[.19444,.69224,0,0,.83334],8649:[.1808,.675,0,0,1],8650:[.19444,.69224,0,0,.83334],8651:[.01354,.52239,0,0,1],8652:[.01354,.52239,0,0,1],8653:[-.13313,.36687,0,0,1],8654:[-.13313,.36687,0,0,1],8655:[-.13313,.36687,0,0,1],8666:[.13667,.63667,0,0,1],8667:[.13667,.63667,0,0,1],8669:[-.13313,.37788,0,0,1],8672:[-.064,.437,0,0,1.334],8674:[-.064,.437,0,0,1.334],8705:[0,.825,0,0,.5],8708:[0,.68889,0,0,.55556],8709:[.08167,.58167,0,0,.77778],8717:[0,.43056,0,0,.42917],8722:[-.03598,.46402,0,0,.5],8724:[.08198,.69224,0,0,.77778],8726:[.08167,.58167,0,0,.77778],8733:[0,.69224,0,0,.77778],8736:[0,.69224,0,0,.72222],8737:[0,.69224,0,0,.72222],8738:[.03517,.52239,0,0,.72222],8739:[.08167,.58167,0,0,.22222],8740:[.25142,.74111,0,0,.27778],8741:[.08167,.58167,0,0,.38889],8742:[.25142,.74111,0,0,.5],8756:[0,.69224,0,0,.66667],8757:[0,.69224,0,0,.66667],8764:[-.13313,.36687,0,0,.77778],8765:[-.13313,.37788,0,0,.77778],8769:[-.13313,.36687,0,0,.77778],8770:[-.03625,.46375,0,0,.77778],8774:[.30274,.79383,0,0,.77778],8776:[-.01688,.48312,0,0,.77778],8778:[.08167,.58167,0,0,.77778],8782:[.06062,.54986,0,0,.77778],8783:[.06062,.54986,0,0,.77778],8785:[.08198,.58198,0,0,.77778],8786:[.08198,.58198,0,0,.77778],8787:[.08198,.58198,0,0,.77778],8790:[0,.69224,0,0,.77778],8791:[.22958,.72958,0,0,.77778],8796:[.08198,.91667,0,0,.77778],8806:[.25583,.75583,0,0,.77778],8807:[.25583,.75583,0,0,.77778],8808:[.25142,.75726,0,0,.77778],8809:[.25142,.75726,0,0,.77778],8812:[.25583,.75583,0,0,.5],8814:[.20576,.70576,0,0,.77778],8815:[.20576,.70576,0,0,.77778],8816:[.30274,.79383,0,0,.77778],8817:[.30274,.79383,0,0,.77778],8818:[.22958,.72958,0,0,.77778],8819:[.22958,.72958,0,0,.77778],8822:[.1808,.675,0,0,.77778],8823:[.1808,.675,0,0,.77778],8828:[.13667,.63667,0,0,.77778],8829:[.13667,.63667,0,0,.77778],8830:[.22958,.72958,0,0,.77778],8831:[.22958,.72958,0,0,.77778],8832:[.20576,.70576,0,0,.77778],8833:[.20576,.70576,0,0,.77778],8840:[.30274,.79383,0,0,.77778],8841:[.30274,.79383,0,0,.77778],8842:[.13597,.63597,0,0,.77778],8843:[.13597,.63597,0,0,.77778],8847:[.03517,.54986,0,0,.77778],8848:[.03517,.54986,0,0,.77778],8858:[.08198,.58198,0,0,.77778],8859:[.08198,.58198,0,0,.77778],8861:[.08198,.58198,0,0,.77778],8862:[0,.675,0,0,.77778],8863:[0,.675,0,0,.77778],8864:[0,.675,0,0,.77778],8865:[0,.675,0,0,.77778],8872:[0,.69224,0,0,.61111],8873:[0,.69224,0,0,.72222],8874:[0,.69224,0,0,.88889],8876:[0,.68889,0,0,.61111],8877:[0,.68889,0,0,.61111],8878:[0,.68889,0,0,.72222],8879:[0,.68889,0,0,.72222],8882:[.03517,.54986,0,0,.77778],8883:[.03517,.54986,0,0,.77778],8884:[.13667,.63667,0,0,.77778],8885:[.13667,.63667,0,0,.77778],8888:[0,.54986,0,0,1.11111],8890:[.19444,.43056,0,0,.55556],8891:[.19444,.69224,0,0,.61111],8892:[.19444,.69224,0,0,.61111],8901:[0,.54986,0,0,.27778],8903:[.08167,.58167,0,0,.77778],8905:[.08167,.58167,0,0,.77778],8906:[.08167,.58167,0,0,.77778],8907:[0,.69224,0,0,.77778],8908:[0,.69224,0,0,.77778],8909:[-.03598,.46402,0,0,.77778],8910:[0,.54986,0,0,.76042],8911:[0,.54986,0,0,.76042],8912:[.03517,.54986,0,0,.77778],8913:[.03517,.54986,0,0,.77778],8914:[0,.54986,0,0,.66667],8915:[0,.54986,0,0,.66667],8916:[0,.69224,0,0,.66667],8918:[.0391,.5391,0,0,.77778],8919:[.0391,.5391,0,0,.77778],8920:[.03517,.54986,0,0,1.33334],8921:[.03517,.54986,0,0,1.33334],8922:[.38569,.88569,0,0,.77778],8923:[.38569,.88569,0,0,.77778],8926:[.13667,.63667,0,0,.77778],8927:[.13667,.63667,0,0,.77778],8928:[.30274,.79383,0,0,.77778],8929:[.30274,.79383,0,0,.77778],8934:[.23222,.74111,0,0,.77778],8935:[.23222,.74111,0,0,.77778],8936:[.23222,.74111,0,0,.77778],8937:[.23222,.74111,0,0,.77778],8938:[.20576,.70576,0,0,.77778],8939:[.20576,.70576,0,0,.77778],8940:[.30274,.79383,0,0,.77778],8941:[.30274,.79383,0,0,.77778],8994:[.19444,.69224,0,0,.77778],8995:[.19444,.69224,0,0,.77778],9416:[.15559,.69224,0,0,.90222],9484:[0,.69224,0,0,.5],9488:[0,.69224,0,0,.5],9492:[0,.37788,0,0,.5],9496:[0,.37788,0,0,.5],9585:[.19444,.68889,0,0,.88889],9586:[.19444,.74111,0,0,.88889],9632:[0,.675,0,0,.77778],9633:[0,.675,0,0,.77778],9650:[0,.54986,0,0,.72222],9651:[0,.54986,0,0,.72222],9654:[.03517,.54986,0,0,.77778],9660:[0,.54986,0,0,.72222],9661:[0,.54986,0,0,.72222],9664:[.03517,.54986,0,0,.77778],9674:[.11111,.69224,0,0,.66667],9733:[.19444,.69224,0,0,.94445],10003:[0,.69224,0,0,.83334],10016:[0,.69224,0,0,.83334],10731:[.11111,.69224,0,0,.66667],10846:[.19444,.75583,0,0,.61111],10877:[.13667,.63667,0,0,.77778],10878:[.13667,.63667,0,0,.77778],10885:[.25583,.75583,0,0,.77778],10886:[.25583,.75583,0,0,.77778],10887:[.13597,.63597,0,0,.77778],10888:[.13597,.63597,0,0,.77778],10889:[.26167,.75726,0,0,.77778],10890:[.26167,.75726,0,0,.77778],10891:[.48256,.98256,0,0,.77778],10892:[.48256,.98256,0,0,.77778],10901:[.13667,.63667,0,0,.77778],10902:[.13667,.63667,0,0,.77778],10933:[.25142,.75726,0,0,.77778],10934:[.25142,.75726,0,0,.77778],10935:[.26167,.75726,0,0,.77778],10936:[.26167,.75726,0,0,.77778],10937:[.26167,.75726,0,0,.77778],10938:[.26167,.75726,0,0,.77778],10949:[.25583,.75583,0,0,.77778],10950:[.25583,.75583,0,0,.77778],10955:[.28481,.79383,0,0,.77778],10956:[.28481,.79383,0,0,.77778],57350:[.08167,.58167,0,0,.22222],57351:[.08167,.58167,0,0,.38889],57352:[.08167,.58167,0,0,.77778],57353:[0,.43056,.04028,0,.66667],57356:[.25142,.75726,0,0,.77778],57357:[.25142,.75726,0,0,.77778],57358:[.41951,.91951,0,0,.77778],57359:[.30274,.79383,0,0,.77778],57360:[.30274,.79383,0,0,.77778],57361:[.41951,.91951,0,0,.77778],57366:[.25142,.75726,0,0,.77778],57367:[.25142,.75726,0,0,.77778],57368:[.25142,.75726,0,0,.77778],57369:[.25142,.75726,0,0,.77778],57370:[.13597,.63597,0,0,.77778],57371:[.13597,.63597,0,0,.77778]},"Caligraphic-Regular":{32:[0,0,0,0,.25],65:[0,.68333,0,.19445,.79847],66:[0,.68333,.03041,.13889,.65681],67:[0,.68333,.05834,.13889,.52653],68:[0,.68333,.02778,.08334,.77139],69:[0,.68333,.08944,.11111,.52778],70:[0,.68333,.09931,.11111,.71875],71:[.09722,.68333,.0593,.11111,.59487],72:[0,.68333,.00965,.11111,.84452],73:[0,.68333,.07382,0,.54452],74:[.09722,.68333,.18472,.16667,.67778],75:[0,.68333,.01445,.05556,.76195],76:[0,.68333,0,.13889,.68972],77:[0,.68333,0,.13889,1.2009],78:[0,.68333,.14736,.08334,.82049],79:[0,.68333,.02778,.11111,.79611],80:[0,.68333,.08222,.08334,.69556],81:[.09722,.68333,0,.11111,.81667],82:[0,.68333,0,.08334,.8475],83:[0,.68333,.075,.13889,.60556],84:[0,.68333,.25417,0,.54464],85:[0,.68333,.09931,.08334,.62583],86:[0,.68333,.08222,0,.61278],87:[0,.68333,.08222,.08334,.98778],88:[0,.68333,.14643,.13889,.7133],89:[.09722,.68333,.08222,.08334,.66834],90:[0,.68333,.07944,.13889,.72473],160:[0,0,0,0,.25]},"Fraktur-Regular":{32:[0,0,0,0,.25],33:[0,.69141,0,0,.29574],34:[0,.69141,0,0,.21471],38:[0,.69141,0,0,.73786],39:[0,.69141,0,0,.21201],40:[.24982,.74947,0,0,.38865],41:[.24982,.74947,0,0,.38865],42:[0,.62119,0,0,.27764],43:[.08319,.58283,0,0,.75623],44:[0,.10803,0,0,.27764],45:[.08319,.58283,0,0,.75623],46:[0,.10803,0,0,.27764],47:[.24982,.74947,0,0,.50181],48:[0,.47534,0,0,.50181],49:[0,.47534,0,0,.50181],50:[0,.47534,0,0,.50181],51:[.18906,.47534,0,0,.50181],52:[.18906,.47534,0,0,.50181],53:[.18906,.47534,0,0,.50181],54:[0,.69141,0,0,.50181],55:[.18906,.47534,0,0,.50181],56:[0,.69141,0,0,.50181],57:[.18906,.47534,0,0,.50181],58:[0,.47534,0,0,.21606],59:[.12604,.47534,0,0,.21606],61:[-.13099,.36866,0,0,.75623],63:[0,.69141,0,0,.36245],65:[0,.69141,0,0,.7176],66:[0,.69141,0,0,.88397],67:[0,.69141,0,0,.61254],68:[0,.69141,0,0,.83158],69:[0,.69141,0,0,.66278],70:[.12604,.69141,0,0,.61119],71:[0,.69141,0,0,.78539],72:[.06302,.69141,0,0,.7203],73:[0,.69141,0,0,.55448],74:[.12604,.69141,0,0,.55231],75:[0,.69141,0,0,.66845],76:[0,.69141,0,0,.66602],77:[0,.69141,0,0,1.04953],78:[0,.69141,0,0,.83212],79:[0,.69141,0,0,.82699],80:[.18906,.69141,0,0,.82753],81:[.03781,.69141,0,0,.82699],82:[0,.69141,0,0,.82807],83:[0,.69141,0,0,.82861],84:[0,.69141,0,0,.66899],85:[0,.69141,0,0,.64576],86:[0,.69141,0,0,.83131],87:[0,.69141,0,0,1.04602],88:[0,.69141,0,0,.71922],89:[.18906,.69141,0,0,.83293],90:[.12604,.69141,0,0,.60201],91:[.24982,.74947,0,0,.27764],93:[.24982,.74947,0,0,.27764],94:[0,.69141,0,0,.49965],97:[0,.47534,0,0,.50046],98:[0,.69141,0,0,.51315],99:[0,.47534,0,0,.38946],100:[0,.62119,0,0,.49857],101:[0,.47534,0,0,.40053],102:[.18906,.69141,0,0,.32626],103:[.18906,.47534,0,0,.5037],104:[.18906,.69141,0,0,.52126],105:[0,.69141,0,0,.27899],106:[0,.69141,0,0,.28088],107:[0,.69141,0,0,.38946],108:[0,.69141,0,0,.27953],109:[0,.47534,0,0,.76676],110:[0,.47534,0,0,.52666],111:[0,.47534,0,0,.48885],112:[.18906,.52396,0,0,.50046],113:[.18906,.47534,0,0,.48912],114:[0,.47534,0,0,.38919],115:[0,.47534,0,0,.44266],116:[0,.62119,0,0,.33301],117:[0,.47534,0,0,.5172],118:[0,.52396,0,0,.5118],119:[0,.52396,0,0,.77351],120:[.18906,.47534,0,0,.38865],121:[.18906,.47534,0,0,.49884],122:[.18906,.47534,0,0,.39054],160:[0,0,0,0,.25],8216:[0,.69141,0,0,.21471],8217:[0,.69141,0,0,.21471],58112:[0,.62119,0,0,.49749],58113:[0,.62119,0,0,.4983],58114:[.18906,.69141,0,0,.33328],58115:[.18906,.69141,0,0,.32923],58116:[.18906,.47534,0,0,.50343],58117:[0,.69141,0,0,.33301],58118:[0,.62119,0,0,.33409],58119:[0,.47534,0,0,.50073]},"Main-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.35],34:[0,.69444,0,0,.60278],35:[.19444,.69444,0,0,.95833],36:[.05556,.75,0,0,.575],37:[.05556,.75,0,0,.95833],38:[0,.69444,0,0,.89444],39:[0,.69444,0,0,.31944],40:[.25,.75,0,0,.44722],41:[.25,.75,0,0,.44722],42:[0,.75,0,0,.575],43:[.13333,.63333,0,0,.89444],44:[.19444,.15556,0,0,.31944],45:[0,.44444,0,0,.38333],46:[0,.15556,0,0,.31944],47:[.25,.75,0,0,.575],48:[0,.64444,0,0,.575],49:[0,.64444,0,0,.575],50:[0,.64444,0,0,.575],51:[0,.64444,0,0,.575],52:[0,.64444,0,0,.575],53:[0,.64444,0,0,.575],54:[0,.64444,0,0,.575],55:[0,.64444,0,0,.575],56:[0,.64444,0,0,.575],57:[0,.64444,0,0,.575],58:[0,.44444,0,0,.31944],59:[.19444,.44444,0,0,.31944],60:[.08556,.58556,0,0,.89444],61:[-.10889,.39111,0,0,.89444],62:[.08556,.58556,0,0,.89444],63:[0,.69444,0,0,.54305],64:[0,.69444,0,0,.89444],65:[0,.68611,0,0,.86944],66:[0,.68611,0,0,.81805],67:[0,.68611,0,0,.83055],68:[0,.68611,0,0,.88194],69:[0,.68611,0,0,.75555],70:[0,.68611,0,0,.72361],71:[0,.68611,0,0,.90416],72:[0,.68611,0,0,.9],73:[0,.68611,0,0,.43611],74:[0,.68611,0,0,.59444],75:[0,.68611,0,0,.90138],76:[0,.68611,0,0,.69166],77:[0,.68611,0,0,1.09166],78:[0,.68611,0,0,.9],79:[0,.68611,0,0,.86388],80:[0,.68611,0,0,.78611],81:[.19444,.68611,0,0,.86388],82:[0,.68611,0,0,.8625],83:[0,.68611,0,0,.63889],84:[0,.68611,0,0,.8],85:[0,.68611,0,0,.88472],86:[0,.68611,.01597,0,.86944],87:[0,.68611,.01597,0,1.18888],88:[0,.68611,0,0,.86944],89:[0,.68611,.02875,0,.86944],90:[0,.68611,0,0,.70277],91:[.25,.75,0,0,.31944],92:[.25,.75,0,0,.575],93:[.25,.75,0,0,.31944],94:[0,.69444,0,0,.575],95:[.31,.13444,.03194,0,.575],97:[0,.44444,0,0,.55902],98:[0,.69444,0,0,.63889],99:[0,.44444,0,0,.51111],100:[0,.69444,0,0,.63889],101:[0,.44444,0,0,.52708],102:[0,.69444,.10903,0,.35139],103:[.19444,.44444,.01597,0,.575],104:[0,.69444,0,0,.63889],105:[0,.69444,0,0,.31944],106:[.19444,.69444,0,0,.35139],107:[0,.69444,0,0,.60694],108:[0,.69444,0,0,.31944],109:[0,.44444,0,0,.95833],110:[0,.44444,0,0,.63889],111:[0,.44444,0,0,.575],112:[.19444,.44444,0,0,.63889],113:[.19444,.44444,0,0,.60694],114:[0,.44444,0,0,.47361],115:[0,.44444,0,0,.45361],116:[0,.63492,0,0,.44722],117:[0,.44444,0,0,.63889],118:[0,.44444,.01597,0,.60694],119:[0,.44444,.01597,0,.83055],120:[0,.44444,0,0,.60694],121:[.19444,.44444,.01597,0,.60694],122:[0,.44444,0,0,.51111],123:[.25,.75,0,0,.575],124:[.25,.75,0,0,.31944],125:[.25,.75,0,0,.575],126:[.35,.34444,0,0,.575],160:[0,0,0,0,.25],163:[0,.69444,0,0,.86853],168:[0,.69444,0,0,.575],172:[0,.44444,0,0,.76666],176:[0,.69444,0,0,.86944],177:[.13333,.63333,0,0,.89444],184:[.17014,0,0,0,.51111],198:[0,.68611,0,0,1.04166],215:[.13333,.63333,0,0,.89444],216:[.04861,.73472,0,0,.89444],223:[0,.69444,0,0,.59722],230:[0,.44444,0,0,.83055],247:[.13333,.63333,0,0,.89444],248:[.09722,.54167,0,0,.575],305:[0,.44444,0,0,.31944],338:[0,.68611,0,0,1.16944],339:[0,.44444,0,0,.89444],567:[.19444,.44444,0,0,.35139],710:[0,.69444,0,0,.575],711:[0,.63194,0,0,.575],713:[0,.59611,0,0,.575],714:[0,.69444,0,0,.575],715:[0,.69444,0,0,.575],728:[0,.69444,0,0,.575],729:[0,.69444,0,0,.31944],730:[0,.69444,0,0,.86944],732:[0,.69444,0,0,.575],733:[0,.69444,0,0,.575],915:[0,.68611,0,0,.69166],916:[0,.68611,0,0,.95833],920:[0,.68611,0,0,.89444],923:[0,.68611,0,0,.80555],926:[0,.68611,0,0,.76666],928:[0,.68611,0,0,.9],931:[0,.68611,0,0,.83055],933:[0,.68611,0,0,.89444],934:[0,.68611,0,0,.83055],936:[0,.68611,0,0,.89444],937:[0,.68611,0,0,.83055],8211:[0,.44444,.03194,0,.575],8212:[0,.44444,.03194,0,1.14999],8216:[0,.69444,0,0,.31944],8217:[0,.69444,0,0,.31944],8220:[0,.69444,0,0,.60278],8221:[0,.69444,0,0,.60278],8224:[.19444,.69444,0,0,.51111],8225:[.19444,.69444,0,0,.51111],8242:[0,.55556,0,0,.34444],8407:[0,.72444,.15486,0,.575],8463:[0,.69444,0,0,.66759],8465:[0,.69444,0,0,.83055],8467:[0,.69444,0,0,.47361],8472:[.19444,.44444,0,0,.74027],8476:[0,.69444,0,0,.83055],8501:[0,.69444,0,0,.70277],8592:[-.10889,.39111,0,0,1.14999],8593:[.19444,.69444,0,0,.575],8594:[-.10889,.39111,0,0,1.14999],8595:[.19444,.69444,0,0,.575],8596:[-.10889,.39111,0,0,1.14999],8597:[.25,.75,0,0,.575],8598:[.19444,.69444,0,0,1.14999],8599:[.19444,.69444,0,0,1.14999],8600:[.19444,.69444,0,0,1.14999],8601:[.19444,.69444,0,0,1.14999],8636:[-.10889,.39111,0,0,1.14999],8637:[-.10889,.39111,0,0,1.14999],8640:[-.10889,.39111,0,0,1.14999],8641:[-.10889,.39111,0,0,1.14999],8656:[-.10889,.39111,0,0,1.14999],8657:[.19444,.69444,0,0,.70277],8658:[-.10889,.39111,0,0,1.14999],8659:[.19444,.69444,0,0,.70277],8660:[-.10889,.39111,0,0,1.14999],8661:[.25,.75,0,0,.70277],8704:[0,.69444,0,0,.63889],8706:[0,.69444,.06389,0,.62847],8707:[0,.69444,0,0,.63889],8709:[.05556,.75,0,0,.575],8711:[0,.68611,0,0,.95833],8712:[.08556,.58556,0,0,.76666],8715:[.08556,.58556,0,0,.76666],8722:[.13333,.63333,0,0,.89444],8723:[.13333,.63333,0,0,.89444],8725:[.25,.75,0,0,.575],8726:[.25,.75,0,0,.575],8727:[-.02778,.47222,0,0,.575],8728:[-.02639,.47361,0,0,.575],8729:[-.02639,.47361,0,0,.575],8730:[.18,.82,0,0,.95833],8733:[0,.44444,0,0,.89444],8734:[0,.44444,0,0,1.14999],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.31944],8741:[.25,.75,0,0,.575],8743:[0,.55556,0,0,.76666],8744:[0,.55556,0,0,.76666],8745:[0,.55556,0,0,.76666],8746:[0,.55556,0,0,.76666],8747:[.19444,.69444,.12778,0,.56875],8764:[-.10889,.39111,0,0,.89444],8768:[.19444,.69444,0,0,.31944],8771:[.00222,.50222,0,0,.89444],8773:[.027,.638,0,0,.894],8776:[.02444,.52444,0,0,.89444],8781:[.00222,.50222,0,0,.89444],8801:[.00222,.50222,0,0,.89444],8804:[.19667,.69667,0,0,.89444],8805:[.19667,.69667,0,0,.89444],8810:[.08556,.58556,0,0,1.14999],8811:[.08556,.58556,0,0,1.14999],8826:[.08556,.58556,0,0,.89444],8827:[.08556,.58556,0,0,.89444],8834:[.08556,.58556,0,0,.89444],8835:[.08556,.58556,0,0,.89444],8838:[.19667,.69667,0,0,.89444],8839:[.19667,.69667,0,0,.89444],8846:[0,.55556,0,0,.76666],8849:[.19667,.69667,0,0,.89444],8850:[.19667,.69667,0,0,.89444],8851:[0,.55556,0,0,.76666],8852:[0,.55556,0,0,.76666],8853:[.13333,.63333,0,0,.89444],8854:[.13333,.63333,0,0,.89444],8855:[.13333,.63333,0,0,.89444],8856:[.13333,.63333,0,0,.89444],8857:[.13333,.63333,0,0,.89444],8866:[0,.69444,0,0,.70277],8867:[0,.69444,0,0,.70277],8868:[0,.69444,0,0,.89444],8869:[0,.69444,0,0,.89444],8900:[-.02639,.47361,0,0,.575],8901:[-.02639,.47361,0,0,.31944],8902:[-.02778,.47222,0,0,.575],8968:[.25,.75,0,0,.51111],8969:[.25,.75,0,0,.51111],8970:[.25,.75,0,0,.51111],8971:[.25,.75,0,0,.51111],8994:[-.13889,.36111,0,0,1.14999],8995:[-.13889,.36111,0,0,1.14999],9651:[.19444,.69444,0,0,1.02222],9657:[-.02778,.47222,0,0,.575],9661:[.19444,.69444,0,0,1.02222],9667:[-.02778,.47222,0,0,.575],9711:[.19444,.69444,0,0,1.14999],9824:[.12963,.69444,0,0,.89444],9825:[.12963,.69444,0,0,.89444],9826:[.12963,.69444,0,0,.89444],9827:[.12963,.69444,0,0,.89444],9837:[0,.75,0,0,.44722],9838:[.19444,.69444,0,0,.44722],9839:[.19444,.69444,0,0,.44722],10216:[.25,.75,0,0,.44722],10217:[.25,.75,0,0,.44722],10815:[0,.68611,0,0,.9],10927:[.19667,.69667,0,0,.89444],10928:[.19667,.69667,0,0,.89444],57376:[.19444,.69444,0,0,0]},"Main-BoldItalic":{32:[0,0,0,0,.25],33:[0,.69444,.11417,0,.38611],34:[0,.69444,.07939,0,.62055],35:[.19444,.69444,.06833,0,.94444],37:[.05556,.75,.12861,0,.94444],38:[0,.69444,.08528,0,.88555],39:[0,.69444,.12945,0,.35555],40:[.25,.75,.15806,0,.47333],41:[.25,.75,.03306,0,.47333],42:[0,.75,.14333,0,.59111],43:[.10333,.60333,.03306,0,.88555],44:[.19444,.14722,0,0,.35555],45:[0,.44444,.02611,0,.41444],46:[0,.14722,0,0,.35555],47:[.25,.75,.15806,0,.59111],48:[0,.64444,.13167,0,.59111],49:[0,.64444,.13167,0,.59111],50:[0,.64444,.13167,0,.59111],51:[0,.64444,.13167,0,.59111],52:[.19444,.64444,.13167,0,.59111],53:[0,.64444,.13167,0,.59111],54:[0,.64444,.13167,0,.59111],55:[.19444,.64444,.13167,0,.59111],56:[0,.64444,.13167,0,.59111],57:[0,.64444,.13167,0,.59111],58:[0,.44444,.06695,0,.35555],59:[.19444,.44444,.06695,0,.35555],61:[-.10889,.39111,.06833,0,.88555],63:[0,.69444,.11472,0,.59111],64:[0,.69444,.09208,0,.88555],65:[0,.68611,0,0,.86555],66:[0,.68611,.0992,0,.81666],67:[0,.68611,.14208,0,.82666],68:[0,.68611,.09062,0,.87555],69:[0,.68611,.11431,0,.75666],70:[0,.68611,.12903,0,.72722],71:[0,.68611,.07347,0,.89527],72:[0,.68611,.17208,0,.8961],73:[0,.68611,.15681,0,.47166],74:[0,.68611,.145,0,.61055],75:[0,.68611,.14208,0,.89499],76:[0,.68611,0,0,.69777],77:[0,.68611,.17208,0,1.07277],78:[0,.68611,.17208,0,.8961],79:[0,.68611,.09062,0,.85499],80:[0,.68611,.0992,0,.78721],81:[.19444,.68611,.09062,0,.85499],82:[0,.68611,.02559,0,.85944],83:[0,.68611,.11264,0,.64999],84:[0,.68611,.12903,0,.7961],85:[0,.68611,.17208,0,.88083],86:[0,.68611,.18625,0,.86555],87:[0,.68611,.18625,0,1.15999],88:[0,.68611,.15681,0,.86555],89:[0,.68611,.19803,0,.86555],90:[0,.68611,.14208,0,.70888],91:[.25,.75,.1875,0,.35611],93:[.25,.75,.09972,0,.35611],94:[0,.69444,.06709,0,.59111],95:[.31,.13444,.09811,0,.59111],97:[0,.44444,.09426,0,.59111],98:[0,.69444,.07861,0,.53222],99:[0,.44444,.05222,0,.53222],100:[0,.69444,.10861,0,.59111],101:[0,.44444,.085,0,.53222],102:[.19444,.69444,.21778,0,.4],103:[.19444,.44444,.105,0,.53222],104:[0,.69444,.09426,0,.59111],105:[0,.69326,.11387,0,.35555],106:[.19444,.69326,.1672,0,.35555],107:[0,.69444,.11111,0,.53222],108:[0,.69444,.10861,0,.29666],109:[0,.44444,.09426,0,.94444],110:[0,.44444,.09426,0,.64999],111:[0,.44444,.07861,0,.59111],112:[.19444,.44444,.07861,0,.59111],113:[.19444,.44444,.105,0,.53222],114:[0,.44444,.11111,0,.50167],115:[0,.44444,.08167,0,.48694],116:[0,.63492,.09639,0,.385],117:[0,.44444,.09426,0,.62055],118:[0,.44444,.11111,0,.53222],119:[0,.44444,.11111,0,.76777],120:[0,.44444,.12583,0,.56055],121:[.19444,.44444,.105,0,.56166],122:[0,.44444,.13889,0,.49055],126:[.35,.34444,.11472,0,.59111],160:[0,0,0,0,.25],168:[0,.69444,.11473,0,.59111],176:[0,.69444,0,0,.94888],184:[.17014,0,0,0,.53222],198:[0,.68611,.11431,0,1.02277],216:[.04861,.73472,.09062,0,.88555],223:[.19444,.69444,.09736,0,.665],230:[0,.44444,.085,0,.82666],248:[.09722,.54167,.09458,0,.59111],305:[0,.44444,.09426,0,.35555],338:[0,.68611,.11431,0,1.14054],339:[0,.44444,.085,0,.82666],567:[.19444,.44444,.04611,0,.385],710:[0,.69444,.06709,0,.59111],711:[0,.63194,.08271,0,.59111],713:[0,.59444,.10444,0,.59111],714:[0,.69444,.08528,0,.59111],715:[0,.69444,0,0,.59111],728:[0,.69444,.10333,0,.59111],729:[0,.69444,.12945,0,.35555],730:[0,.69444,0,0,.94888],732:[0,.69444,.11472,0,.59111],733:[0,.69444,.11472,0,.59111],915:[0,.68611,.12903,0,.69777],916:[0,.68611,0,0,.94444],920:[0,.68611,.09062,0,.88555],923:[0,.68611,0,0,.80666],926:[0,.68611,.15092,0,.76777],928:[0,.68611,.17208,0,.8961],931:[0,.68611,.11431,0,.82666],933:[0,.68611,.10778,0,.88555],934:[0,.68611,.05632,0,.82666],936:[0,.68611,.10778,0,.88555],937:[0,.68611,.0992,0,.82666],8211:[0,.44444,.09811,0,.59111],8212:[0,.44444,.09811,0,1.18221],8216:[0,.69444,.12945,0,.35555],8217:[0,.69444,.12945,0,.35555],8220:[0,.69444,.16772,0,.62055],8221:[0,.69444,.07939,0,.62055]},"Main-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.12417,0,.30667],34:[0,.69444,.06961,0,.51444],35:[.19444,.69444,.06616,0,.81777],37:[.05556,.75,.13639,0,.81777],38:[0,.69444,.09694,0,.76666],39:[0,.69444,.12417,0,.30667],40:[.25,.75,.16194,0,.40889],41:[.25,.75,.03694,0,.40889],42:[0,.75,.14917,0,.51111],43:[.05667,.56167,.03694,0,.76666],44:[.19444,.10556,0,0,.30667],45:[0,.43056,.02826,0,.35778],46:[0,.10556,0,0,.30667],47:[.25,.75,.16194,0,.51111],48:[0,.64444,.13556,0,.51111],49:[0,.64444,.13556,0,.51111],50:[0,.64444,.13556,0,.51111],51:[0,.64444,.13556,0,.51111],52:[.19444,.64444,.13556,0,.51111],53:[0,.64444,.13556,0,.51111],54:[0,.64444,.13556,0,.51111],55:[.19444,.64444,.13556,0,.51111],56:[0,.64444,.13556,0,.51111],57:[0,.64444,.13556,0,.51111],58:[0,.43056,.0582,0,.30667],59:[.19444,.43056,.0582,0,.30667],61:[-.13313,.36687,.06616,0,.76666],63:[0,.69444,.1225,0,.51111],64:[0,.69444,.09597,0,.76666],65:[0,.68333,0,0,.74333],66:[0,.68333,.10257,0,.70389],67:[0,.68333,.14528,0,.71555],68:[0,.68333,.09403,0,.755],69:[0,.68333,.12028,0,.67833],70:[0,.68333,.13305,0,.65277],71:[0,.68333,.08722,0,.77361],72:[0,.68333,.16389,0,.74333],73:[0,.68333,.15806,0,.38555],74:[0,.68333,.14028,0,.525],75:[0,.68333,.14528,0,.76888],76:[0,.68333,0,0,.62722],77:[0,.68333,.16389,0,.89666],78:[0,.68333,.16389,0,.74333],79:[0,.68333,.09403,0,.76666],80:[0,.68333,.10257,0,.67833],81:[.19444,.68333,.09403,0,.76666],82:[0,.68333,.03868,0,.72944],83:[0,.68333,.11972,0,.56222],84:[0,.68333,.13305,0,.71555],85:[0,.68333,.16389,0,.74333],86:[0,.68333,.18361,0,.74333],87:[0,.68333,.18361,0,.99888],88:[0,.68333,.15806,0,.74333],89:[0,.68333,.19383,0,.74333],90:[0,.68333,.14528,0,.61333],91:[.25,.75,.1875,0,.30667],93:[.25,.75,.10528,0,.30667],94:[0,.69444,.06646,0,.51111],95:[.31,.12056,.09208,0,.51111],97:[0,.43056,.07671,0,.51111],98:[0,.69444,.06312,0,.46],99:[0,.43056,.05653,0,.46],100:[0,.69444,.10333,0,.51111],101:[0,.43056,.07514,0,.46],102:[.19444,.69444,.21194,0,.30667],103:[.19444,.43056,.08847,0,.46],104:[0,.69444,.07671,0,.51111],105:[0,.65536,.1019,0,.30667],106:[.19444,.65536,.14467,0,.30667],107:[0,.69444,.10764,0,.46],108:[0,.69444,.10333,0,.25555],109:[0,.43056,.07671,0,.81777],110:[0,.43056,.07671,0,.56222],111:[0,.43056,.06312,0,.51111],112:[.19444,.43056,.06312,0,.51111],113:[.19444,.43056,.08847,0,.46],114:[0,.43056,.10764,0,.42166],115:[0,.43056,.08208,0,.40889],116:[0,.61508,.09486,0,.33222],117:[0,.43056,.07671,0,.53666],118:[0,.43056,.10764,0,.46],119:[0,.43056,.10764,0,.66444],120:[0,.43056,.12042,0,.46389],121:[.19444,.43056,.08847,0,.48555],122:[0,.43056,.12292,0,.40889],126:[.35,.31786,.11585,0,.51111],160:[0,0,0,0,.25],168:[0,.66786,.10474,0,.51111],176:[0,.69444,0,0,.83129],184:[.17014,0,0,0,.46],198:[0,.68333,.12028,0,.88277],216:[.04861,.73194,.09403,0,.76666],223:[.19444,.69444,.10514,0,.53666],230:[0,.43056,.07514,0,.71555],248:[.09722,.52778,.09194,0,.51111],338:[0,.68333,.12028,0,.98499],339:[0,.43056,.07514,0,.71555],710:[0,.69444,.06646,0,.51111],711:[0,.62847,.08295,0,.51111],713:[0,.56167,.10333,0,.51111],714:[0,.69444,.09694,0,.51111],715:[0,.69444,0,0,.51111],728:[0,.69444,.10806,0,.51111],729:[0,.66786,.11752,0,.30667],730:[0,.69444,0,0,.83129],732:[0,.66786,.11585,0,.51111],733:[0,.69444,.1225,0,.51111],915:[0,.68333,.13305,0,.62722],916:[0,.68333,0,0,.81777],920:[0,.68333,.09403,0,.76666],923:[0,.68333,0,0,.69222],926:[0,.68333,.15294,0,.66444],928:[0,.68333,.16389,0,.74333],931:[0,.68333,.12028,0,.71555],933:[0,.68333,.11111,0,.76666],934:[0,.68333,.05986,0,.71555],936:[0,.68333,.11111,0,.76666],937:[0,.68333,.10257,0,.71555],8211:[0,.43056,.09208,0,.51111],8212:[0,.43056,.09208,0,1.02222],8216:[0,.69444,.12417,0,.30667],8217:[0,.69444,.12417,0,.30667],8220:[0,.69444,.1685,0,.51444],8221:[0,.69444,.06961,0,.51444],8463:[0,.68889,0,0,.54028]},"Main-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.27778],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.77778],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.19444,.10556,0,0,.27778],45:[0,.43056,0,0,.33333],46:[0,.10556,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.64444,0,0,.5],49:[0,.64444,0,0,.5],50:[0,.64444,0,0,.5],51:[0,.64444,0,0,.5],52:[0,.64444,0,0,.5],53:[0,.64444,0,0,.5],54:[0,.64444,0,0,.5],55:[0,.64444,0,0,.5],56:[0,.64444,0,0,.5],57:[0,.64444,0,0,.5],58:[0,.43056,0,0,.27778],59:[.19444,.43056,0,0,.27778],60:[.0391,.5391,0,0,.77778],61:[-.13313,.36687,0,0,.77778],62:[.0391,.5391,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.77778],65:[0,.68333,0,0,.75],66:[0,.68333,0,0,.70834],67:[0,.68333,0,0,.72222],68:[0,.68333,0,0,.76389],69:[0,.68333,0,0,.68056],70:[0,.68333,0,0,.65278],71:[0,.68333,0,0,.78472],72:[0,.68333,0,0,.75],73:[0,.68333,0,0,.36111],74:[0,.68333,0,0,.51389],75:[0,.68333,0,0,.77778],76:[0,.68333,0,0,.625],77:[0,.68333,0,0,.91667],78:[0,.68333,0,0,.75],79:[0,.68333,0,0,.77778],80:[0,.68333,0,0,.68056],81:[.19444,.68333,0,0,.77778],82:[0,.68333,0,0,.73611],83:[0,.68333,0,0,.55556],84:[0,.68333,0,0,.72222],85:[0,.68333,0,0,.75],86:[0,.68333,.01389,0,.75],87:[0,.68333,.01389,0,1.02778],88:[0,.68333,0,0,.75],89:[0,.68333,.025,0,.75],90:[0,.68333,0,0,.61111],91:[.25,.75,0,0,.27778],92:[.25,.75,0,0,.5],93:[.25,.75,0,0,.27778],94:[0,.69444,0,0,.5],95:[.31,.12056,.02778,0,.5],97:[0,.43056,0,0,.5],98:[0,.69444,0,0,.55556],99:[0,.43056,0,0,.44445],100:[0,.69444,0,0,.55556],101:[0,.43056,0,0,.44445],102:[0,.69444,.07778,0,.30556],103:[.19444,.43056,.01389,0,.5],104:[0,.69444,0,0,.55556],105:[0,.66786,0,0,.27778],106:[.19444,.66786,0,0,.30556],107:[0,.69444,0,0,.52778],108:[0,.69444,0,0,.27778],109:[0,.43056,0,0,.83334],110:[0,.43056,0,0,.55556],111:[0,.43056,0,0,.5],112:[.19444,.43056,0,0,.55556],113:[.19444,.43056,0,0,.52778],114:[0,.43056,0,0,.39167],115:[0,.43056,0,0,.39445],116:[0,.61508,0,0,.38889],117:[0,.43056,0,0,.55556],118:[0,.43056,.01389,0,.52778],119:[0,.43056,.01389,0,.72222],120:[0,.43056,0,0,.52778],121:[.19444,.43056,.01389,0,.52778],122:[0,.43056,0,0,.44445],123:[.25,.75,0,0,.5],124:[.25,.75,0,0,.27778],125:[.25,.75,0,0,.5],126:[.35,.31786,0,0,.5],160:[0,0,0,0,.25],163:[0,.69444,0,0,.76909],167:[.19444,.69444,0,0,.44445],168:[0,.66786,0,0,.5],172:[0,.43056,0,0,.66667],176:[0,.69444,0,0,.75],177:[.08333,.58333,0,0,.77778],182:[.19444,.69444,0,0,.61111],184:[.17014,0,0,0,.44445],198:[0,.68333,0,0,.90278],215:[.08333,.58333,0,0,.77778],216:[.04861,.73194,0,0,.77778],223:[0,.69444,0,0,.5],230:[0,.43056,0,0,.72222],247:[.08333,.58333,0,0,.77778],248:[.09722,.52778,0,0,.5],305:[0,.43056,0,0,.27778],338:[0,.68333,0,0,1.01389],339:[0,.43056,0,0,.77778],567:[.19444,.43056,0,0,.30556],710:[0,.69444,0,0,.5],711:[0,.62847,0,0,.5],713:[0,.56778,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.66786,0,0,.27778],730:[0,.69444,0,0,.75],732:[0,.66786,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.68333,0,0,.625],916:[0,.68333,0,0,.83334],920:[0,.68333,0,0,.77778],923:[0,.68333,0,0,.69445],926:[0,.68333,0,0,.66667],928:[0,.68333,0,0,.75],931:[0,.68333,0,0,.72222],933:[0,.68333,0,0,.77778],934:[0,.68333,0,0,.72222],936:[0,.68333,0,0,.77778],937:[0,.68333,0,0,.72222],8211:[0,.43056,.02778,0,.5],8212:[0,.43056,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5],8224:[.19444,.69444,0,0,.44445],8225:[.19444,.69444,0,0,.44445],8230:[0,.123,0,0,1.172],8242:[0,.55556,0,0,.275],8407:[0,.71444,.15382,0,.5],8463:[0,.68889,0,0,.54028],8465:[0,.69444,0,0,.72222],8467:[0,.69444,0,.11111,.41667],8472:[.19444,.43056,0,.11111,.63646],8476:[0,.69444,0,0,.72222],8501:[0,.69444,0,0,.61111],8592:[-.13313,.36687,0,0,1],8593:[.19444,.69444,0,0,.5],8594:[-.13313,.36687,0,0,1],8595:[.19444,.69444,0,0,.5],8596:[-.13313,.36687,0,0,1],8597:[.25,.75,0,0,.5],8598:[.19444,.69444,0,0,1],8599:[.19444,.69444,0,0,1],8600:[.19444,.69444,0,0,1],8601:[.19444,.69444,0,0,1],8614:[.011,.511,0,0,1],8617:[.011,.511,0,0,1.126],8618:[.011,.511,0,0,1.126],8636:[-.13313,.36687,0,0,1],8637:[-.13313,.36687,0,0,1],8640:[-.13313,.36687,0,0,1],8641:[-.13313,.36687,0,0,1],8652:[.011,.671,0,0,1],8656:[-.13313,.36687,0,0,1],8657:[.19444,.69444,0,0,.61111],8658:[-.13313,.36687,0,0,1],8659:[.19444,.69444,0,0,.61111],8660:[-.13313,.36687,0,0,1],8661:[.25,.75,0,0,.61111],8704:[0,.69444,0,0,.55556],8706:[0,.69444,.05556,.08334,.5309],8707:[0,.69444,0,0,.55556],8709:[.05556,.75,0,0,.5],8711:[0,.68333,0,0,.83334],8712:[.0391,.5391,0,0,.66667],8715:[.0391,.5391,0,0,.66667],8722:[.08333,.58333,0,0,.77778],8723:[.08333,.58333,0,0,.77778],8725:[.25,.75,0,0,.5],8726:[.25,.75,0,0,.5],8727:[-.03472,.46528,0,0,.5],8728:[-.05555,.44445,0,0,.5],8729:[-.05555,.44445,0,0,.5],8730:[.2,.8,0,0,.83334],8733:[0,.43056,0,0,.77778],8734:[0,.43056,0,0,1],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.27778],8741:[.25,.75,0,0,.5],8743:[0,.55556,0,0,.66667],8744:[0,.55556,0,0,.66667],8745:[0,.55556,0,0,.66667],8746:[0,.55556,0,0,.66667],8747:[.19444,.69444,.11111,0,.41667],8764:[-.13313,.36687,0,0,.77778],8768:[.19444,.69444,0,0,.27778],8771:[-.03625,.46375,0,0,.77778],8773:[-.022,.589,0,0,.778],8776:[-.01688,.48312,0,0,.77778],8781:[-.03625,.46375,0,0,.77778],8784:[-.133,.673,0,0,.778],8801:[-.03625,.46375,0,0,.77778],8804:[.13597,.63597,0,0,.77778],8805:[.13597,.63597,0,0,.77778],8810:[.0391,.5391,0,0,1],8811:[.0391,.5391,0,0,1],8826:[.0391,.5391,0,0,.77778],8827:[.0391,.5391,0,0,.77778],8834:[.0391,.5391,0,0,.77778],8835:[.0391,.5391,0,0,.77778],8838:[.13597,.63597,0,0,.77778],8839:[.13597,.63597,0,0,.77778],8846:[0,.55556,0,0,.66667],8849:[.13597,.63597,0,0,.77778],8850:[.13597,.63597,0,0,.77778],8851:[0,.55556,0,0,.66667],8852:[0,.55556,0,0,.66667],8853:[.08333,.58333,0,0,.77778],8854:[.08333,.58333,0,0,.77778],8855:[.08333,.58333,0,0,.77778],8856:[.08333,.58333,0,0,.77778],8857:[.08333,.58333,0,0,.77778],8866:[0,.69444,0,0,.61111],8867:[0,.69444,0,0,.61111],8868:[0,.69444,0,0,.77778],8869:[0,.69444,0,0,.77778],8872:[.249,.75,0,0,.867],8900:[-.05555,.44445,0,0,.5],8901:[-.05555,.44445,0,0,.27778],8902:[-.03472,.46528,0,0,.5],8904:[.005,.505,0,0,.9],8942:[.03,.903,0,0,.278],8943:[-.19,.313,0,0,1.172],8945:[-.1,.823,0,0,1.282],8968:[.25,.75,0,0,.44445],8969:[.25,.75,0,0,.44445],8970:[.25,.75,0,0,.44445],8971:[.25,.75,0,0,.44445],8994:[-.14236,.35764,0,0,1],8995:[-.14236,.35764,0,0,1],9136:[.244,.744,0,0,.412],9137:[.244,.745,0,0,.412],9651:[.19444,.69444,0,0,.88889],9657:[-.03472,.46528,0,0,.5],9661:[.19444,.69444,0,0,.88889],9667:[-.03472,.46528,0,0,.5],9711:[.19444,.69444,0,0,1],9824:[.12963,.69444,0,0,.77778],9825:[.12963,.69444,0,0,.77778],9826:[.12963,.69444,0,0,.77778],9827:[.12963,.69444,0,0,.77778],9837:[0,.75,0,0,.38889],9838:[.19444,.69444,0,0,.38889],9839:[.19444,.69444,0,0,.38889],10216:[.25,.75,0,0,.38889],10217:[.25,.75,0,0,.38889],10222:[.244,.744,0,0,.412],10223:[.244,.745,0,0,.412],10229:[.011,.511,0,0,1.609],10230:[.011,.511,0,0,1.638],10231:[.011,.511,0,0,1.859],10232:[.024,.525,0,0,1.609],10233:[.024,.525,0,0,1.638],10234:[.024,.525,0,0,1.858],10236:[.011,.511,0,0,1.638],10815:[0,.68333,0,0,.75],10927:[.13597,.63597,0,0,.77778],10928:[.13597,.63597,0,0,.77778],57376:[.19444,.69444,0,0,0]},"Math-BoldItalic":{32:[0,0,0,0,.25],48:[0,.44444,0,0,.575],49:[0,.44444,0,0,.575],50:[0,.44444,0,0,.575],51:[.19444,.44444,0,0,.575],52:[.19444,.44444,0,0,.575],53:[.19444,.44444,0,0,.575],54:[0,.64444,0,0,.575],55:[.19444,.44444,0,0,.575],56:[0,.64444,0,0,.575],57:[.19444,.44444,0,0,.575],65:[0,.68611,0,0,.86944],66:[0,.68611,.04835,0,.8664],67:[0,.68611,.06979,0,.81694],68:[0,.68611,.03194,0,.93812],69:[0,.68611,.05451,0,.81007],70:[0,.68611,.15972,0,.68889],71:[0,.68611,0,0,.88673],72:[0,.68611,.08229,0,.98229],73:[0,.68611,.07778,0,.51111],74:[0,.68611,.10069,0,.63125],75:[0,.68611,.06979,0,.97118],76:[0,.68611,0,0,.75555],77:[0,.68611,.11424,0,1.14201],78:[0,.68611,.11424,0,.95034],79:[0,.68611,.03194,0,.83666],80:[0,.68611,.15972,0,.72309],81:[.19444,.68611,0,0,.86861],82:[0,.68611,.00421,0,.87235],83:[0,.68611,.05382,0,.69271],84:[0,.68611,.15972,0,.63663],85:[0,.68611,.11424,0,.80027],86:[0,.68611,.25555,0,.67778],87:[0,.68611,.15972,0,1.09305],88:[0,.68611,.07778,0,.94722],89:[0,.68611,.25555,0,.67458],90:[0,.68611,.06979,0,.77257],97:[0,.44444,0,0,.63287],98:[0,.69444,0,0,.52083],99:[0,.44444,0,0,.51342],100:[0,.69444,0,0,.60972],101:[0,.44444,0,0,.55361],102:[.19444,.69444,.11042,0,.56806],103:[.19444,.44444,.03704,0,.5449],104:[0,.69444,0,0,.66759],105:[0,.69326,0,0,.4048],106:[.19444,.69326,.0622,0,.47083],107:[0,.69444,.01852,0,.6037],108:[0,.69444,.0088,0,.34815],109:[0,.44444,0,0,1.0324],110:[0,.44444,0,0,.71296],111:[0,.44444,0,0,.58472],112:[.19444,.44444,0,0,.60092],113:[.19444,.44444,.03704,0,.54213],114:[0,.44444,.03194,0,.5287],115:[0,.44444,0,0,.53125],116:[0,.63492,0,0,.41528],117:[0,.44444,0,0,.68102],118:[0,.44444,.03704,0,.56666],119:[0,.44444,.02778,0,.83148],120:[0,.44444,0,0,.65903],121:[.19444,.44444,.03704,0,.59028],122:[0,.44444,.04213,0,.55509],160:[0,0,0,0,.25],915:[0,.68611,.15972,0,.65694],916:[0,.68611,0,0,.95833],920:[0,.68611,.03194,0,.86722],923:[0,.68611,0,0,.80555],926:[0,.68611,.07458,0,.84125],928:[0,.68611,.08229,0,.98229],931:[0,.68611,.05451,0,.88507],933:[0,.68611,.15972,0,.67083],934:[0,.68611,0,0,.76666],936:[0,.68611,.11653,0,.71402],937:[0,.68611,.04835,0,.8789],945:[0,.44444,0,0,.76064],946:[.19444,.69444,.03403,0,.65972],947:[.19444,.44444,.06389,0,.59003],948:[0,.69444,.03819,0,.52222],949:[0,.44444,0,0,.52882],950:[.19444,.69444,.06215,0,.50833],951:[.19444,.44444,.03704,0,.6],952:[0,.69444,.03194,0,.5618],953:[0,.44444,0,0,.41204],954:[0,.44444,0,0,.66759],955:[0,.69444,0,0,.67083],956:[.19444,.44444,0,0,.70787],957:[0,.44444,.06898,0,.57685],958:[.19444,.69444,.03021,0,.50833],959:[0,.44444,0,0,.58472],960:[0,.44444,.03704,0,.68241],961:[.19444,.44444,0,0,.6118],962:[.09722,.44444,.07917,0,.42361],963:[0,.44444,.03704,0,.68588],964:[0,.44444,.13472,0,.52083],965:[0,.44444,.03704,0,.63055],966:[.19444,.44444,0,0,.74722],967:[.19444,.44444,0,0,.71805],968:[.19444,.69444,.03704,0,.75833],969:[0,.44444,.03704,0,.71782],977:[0,.69444,0,0,.69155],981:[.19444,.69444,0,0,.7125],982:[0,.44444,.03194,0,.975],1009:[.19444,.44444,0,0,.6118],1013:[0,.44444,0,0,.48333],57649:[0,.44444,0,0,.39352],57911:[.19444,.44444,0,0,.43889]},"Math-Italic":{32:[0,0,0,0,.25],48:[0,.43056,0,0,.5],49:[0,.43056,0,0,.5],50:[0,.43056,0,0,.5],51:[.19444,.43056,0,0,.5],52:[.19444,.43056,0,0,.5],53:[.19444,.43056,0,0,.5],54:[0,.64444,0,0,.5],55:[.19444,.43056,0,0,.5],56:[0,.64444,0,0,.5],57:[.19444,.43056,0,0,.5],65:[0,.68333,0,.13889,.75],66:[0,.68333,.05017,.08334,.75851],67:[0,.68333,.07153,.08334,.71472],68:[0,.68333,.02778,.05556,.82792],69:[0,.68333,.05764,.08334,.7382],70:[0,.68333,.13889,.08334,.64306],71:[0,.68333,0,.08334,.78625],72:[0,.68333,.08125,.05556,.83125],73:[0,.68333,.07847,.11111,.43958],74:[0,.68333,.09618,.16667,.55451],75:[0,.68333,.07153,.05556,.84931],76:[0,.68333,0,.02778,.68056],77:[0,.68333,.10903,.08334,.97014],78:[0,.68333,.10903,.08334,.80347],79:[0,.68333,.02778,.08334,.76278],80:[0,.68333,.13889,.08334,.64201],81:[.19444,.68333,0,.08334,.79056],82:[0,.68333,.00773,.08334,.75929],83:[0,.68333,.05764,.08334,.6132],84:[0,.68333,.13889,.08334,.58438],85:[0,.68333,.10903,.02778,.68278],86:[0,.68333,.22222,0,.58333],87:[0,.68333,.13889,0,.94445],88:[0,.68333,.07847,.08334,.82847],89:[0,.68333,.22222,0,.58056],90:[0,.68333,.07153,.08334,.68264],97:[0,.43056,0,0,.52859],98:[0,.69444,0,0,.42917],99:[0,.43056,0,.05556,.43276],100:[0,.69444,0,.16667,.52049],101:[0,.43056,0,.05556,.46563],102:[.19444,.69444,.10764,.16667,.48959],103:[.19444,.43056,.03588,.02778,.47697],104:[0,.69444,0,0,.57616],105:[0,.65952,0,0,.34451],106:[.19444,.65952,.05724,0,.41181],107:[0,.69444,.03148,0,.5206],108:[0,.69444,.01968,.08334,.29838],109:[0,.43056,0,0,.87801],110:[0,.43056,0,0,.60023],111:[0,.43056,0,.05556,.48472],112:[.19444,.43056,0,.08334,.50313],113:[.19444,.43056,.03588,.08334,.44641],114:[0,.43056,.02778,.05556,.45116],115:[0,.43056,0,.05556,.46875],116:[0,.61508,0,.08334,.36111],117:[0,.43056,0,.02778,.57246],118:[0,.43056,.03588,.02778,.48472],119:[0,.43056,.02691,.08334,.71592],120:[0,.43056,0,.02778,.57153],121:[.19444,.43056,.03588,.05556,.49028],122:[0,.43056,.04398,.05556,.46505],160:[0,0,0,0,.25],915:[0,.68333,.13889,.08334,.61528],916:[0,.68333,0,.16667,.83334],920:[0,.68333,.02778,.08334,.76278],923:[0,.68333,0,.16667,.69445],926:[0,.68333,.07569,.08334,.74236],928:[0,.68333,.08125,.05556,.83125],931:[0,.68333,.05764,.08334,.77986],933:[0,.68333,.13889,.05556,.58333],934:[0,.68333,0,.08334,.66667],936:[0,.68333,.11,.05556,.61222],937:[0,.68333,.05017,.08334,.7724],945:[0,.43056,.0037,.02778,.6397],946:[.19444,.69444,.05278,.08334,.56563],947:[.19444,.43056,.05556,0,.51773],948:[0,.69444,.03785,.05556,.44444],949:[0,.43056,0,.08334,.46632],950:[.19444,.69444,.07378,.08334,.4375],951:[.19444,.43056,.03588,.05556,.49653],952:[0,.69444,.02778,.08334,.46944],953:[0,.43056,0,.05556,.35394],954:[0,.43056,0,0,.57616],955:[0,.69444,0,0,.58334],956:[.19444,.43056,0,.02778,.60255],957:[0,.43056,.06366,.02778,.49398],958:[.19444,.69444,.04601,.11111,.4375],959:[0,.43056,0,.05556,.48472],960:[0,.43056,.03588,0,.57003],961:[.19444,.43056,0,.08334,.51702],962:[.09722,.43056,.07986,.08334,.36285],963:[0,.43056,.03588,0,.57141],964:[0,.43056,.1132,.02778,.43715],965:[0,.43056,.03588,.02778,.54028],966:[.19444,.43056,0,.08334,.65417],967:[.19444,.43056,0,.05556,.62569],968:[.19444,.69444,.03588,.11111,.65139],969:[0,.43056,.03588,0,.62245],977:[0,.69444,0,.08334,.59144],981:[.19444,.69444,0,.08334,.59583],982:[0,.43056,.02778,0,.82813],1009:[.19444,.43056,0,.08334,.51702],1013:[0,.43056,0,.05556,.4059],57649:[0,.43056,0,.02778,.32246],57911:[.19444,.43056,0,.08334,.38403]},"SansSerif-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.36667],34:[0,.69444,0,0,.55834],35:[.19444,.69444,0,0,.91667],36:[.05556,.75,0,0,.55],37:[.05556,.75,0,0,1.02912],38:[0,.69444,0,0,.83056],39:[0,.69444,0,0,.30556],40:[.25,.75,0,0,.42778],41:[.25,.75,0,0,.42778],42:[0,.75,0,0,.55],43:[.11667,.61667,0,0,.85556],44:[.10556,.13056,0,0,.30556],45:[0,.45833,0,0,.36667],46:[0,.13056,0,0,.30556],47:[.25,.75,0,0,.55],48:[0,.69444,0,0,.55],49:[0,.69444,0,0,.55],50:[0,.69444,0,0,.55],51:[0,.69444,0,0,.55],52:[0,.69444,0,0,.55],53:[0,.69444,0,0,.55],54:[0,.69444,0,0,.55],55:[0,.69444,0,0,.55],56:[0,.69444,0,0,.55],57:[0,.69444,0,0,.55],58:[0,.45833,0,0,.30556],59:[.10556,.45833,0,0,.30556],61:[-.09375,.40625,0,0,.85556],63:[0,.69444,0,0,.51945],64:[0,.69444,0,0,.73334],65:[0,.69444,0,0,.73334],66:[0,.69444,0,0,.73334],67:[0,.69444,0,0,.70278],68:[0,.69444,0,0,.79445],69:[0,.69444,0,0,.64167],70:[0,.69444,0,0,.61111],71:[0,.69444,0,0,.73334],72:[0,.69444,0,0,.79445],73:[0,.69444,0,0,.33056],74:[0,.69444,0,0,.51945],75:[0,.69444,0,0,.76389],76:[0,.69444,0,0,.58056],77:[0,.69444,0,0,.97778],78:[0,.69444,0,0,.79445],79:[0,.69444,0,0,.79445],80:[0,.69444,0,0,.70278],81:[.10556,.69444,0,0,.79445],82:[0,.69444,0,0,.70278],83:[0,.69444,0,0,.61111],84:[0,.69444,0,0,.73334],85:[0,.69444,0,0,.76389],86:[0,.69444,.01528,0,.73334],87:[0,.69444,.01528,0,1.03889],88:[0,.69444,0,0,.73334],89:[0,.69444,.0275,0,.73334],90:[0,.69444,0,0,.67223],91:[.25,.75,0,0,.34306],93:[.25,.75,0,0,.34306],94:[0,.69444,0,0,.55],95:[.35,.10833,.03056,0,.55],97:[0,.45833,0,0,.525],98:[0,.69444,0,0,.56111],99:[0,.45833,0,0,.48889],100:[0,.69444,0,0,.56111],101:[0,.45833,0,0,.51111],102:[0,.69444,.07639,0,.33611],103:[.19444,.45833,.01528,0,.55],104:[0,.69444,0,0,.56111],105:[0,.69444,0,0,.25556],106:[.19444,.69444,0,0,.28611],107:[0,.69444,0,0,.53056],108:[0,.69444,0,0,.25556],109:[0,.45833,0,0,.86667],110:[0,.45833,0,0,.56111],111:[0,.45833,0,0,.55],112:[.19444,.45833,0,0,.56111],113:[.19444,.45833,0,0,.56111],114:[0,.45833,.01528,0,.37222],115:[0,.45833,0,0,.42167],116:[0,.58929,0,0,.40417],117:[0,.45833,0,0,.56111],118:[0,.45833,.01528,0,.5],119:[0,.45833,.01528,0,.74445],120:[0,.45833,0,0,.5],121:[.19444,.45833,.01528,0,.5],122:[0,.45833,0,0,.47639],126:[.35,.34444,0,0,.55],160:[0,0,0,0,.25],168:[0,.69444,0,0,.55],176:[0,.69444,0,0,.73334],180:[0,.69444,0,0,.55],184:[.17014,0,0,0,.48889],305:[0,.45833,0,0,.25556],567:[.19444,.45833,0,0,.28611],710:[0,.69444,0,0,.55],711:[0,.63542,0,0,.55],713:[0,.63778,0,0,.55],728:[0,.69444,0,0,.55],729:[0,.69444,0,0,.30556],730:[0,.69444,0,0,.73334],732:[0,.69444,0,0,.55],733:[0,.69444,0,0,.55],915:[0,.69444,0,0,.58056],916:[0,.69444,0,0,.91667],920:[0,.69444,0,0,.85556],923:[0,.69444,0,0,.67223],926:[0,.69444,0,0,.73334],928:[0,.69444,0,0,.79445],931:[0,.69444,0,0,.79445],933:[0,.69444,0,0,.85556],934:[0,.69444,0,0,.79445],936:[0,.69444,0,0,.85556],937:[0,.69444,0,0,.79445],8211:[0,.45833,.03056,0,.55],8212:[0,.45833,.03056,0,1.10001],8216:[0,.69444,0,0,.30556],8217:[0,.69444,0,0,.30556],8220:[0,.69444,0,0,.55834],8221:[0,.69444,0,0,.55834]},"SansSerif-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.05733,0,.31945],34:[0,.69444,.00316,0,.5],35:[.19444,.69444,.05087,0,.83334],36:[.05556,.75,.11156,0,.5],37:[.05556,.75,.03126,0,.83334],38:[0,.69444,.03058,0,.75834],39:[0,.69444,.07816,0,.27778],40:[.25,.75,.13164,0,.38889],41:[.25,.75,.02536,0,.38889],42:[0,.75,.11775,0,.5],43:[.08333,.58333,.02536,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,.01946,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,.13164,0,.5],48:[0,.65556,.11156,0,.5],49:[0,.65556,.11156,0,.5],50:[0,.65556,.11156,0,.5],51:[0,.65556,.11156,0,.5],52:[0,.65556,.11156,0,.5],53:[0,.65556,.11156,0,.5],54:[0,.65556,.11156,0,.5],55:[0,.65556,.11156,0,.5],56:[0,.65556,.11156,0,.5],57:[0,.65556,.11156,0,.5],58:[0,.44444,.02502,0,.27778],59:[.125,.44444,.02502,0,.27778],61:[-.13,.37,.05087,0,.77778],63:[0,.69444,.11809,0,.47222],64:[0,.69444,.07555,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,.08293,0,.66667],67:[0,.69444,.11983,0,.63889],68:[0,.69444,.07555,0,.72223],69:[0,.69444,.11983,0,.59722],70:[0,.69444,.13372,0,.56945],71:[0,.69444,.11983,0,.66667],72:[0,.69444,.08094,0,.70834],73:[0,.69444,.13372,0,.27778],74:[0,.69444,.08094,0,.47222],75:[0,.69444,.11983,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,.08094,0,.875],78:[0,.69444,.08094,0,.70834],79:[0,.69444,.07555,0,.73611],80:[0,.69444,.08293,0,.63889],81:[.125,.69444,.07555,0,.73611],82:[0,.69444,.08293,0,.64584],83:[0,.69444,.09205,0,.55556],84:[0,.69444,.13372,0,.68056],85:[0,.69444,.08094,0,.6875],86:[0,.69444,.1615,0,.66667],87:[0,.69444,.1615,0,.94445],88:[0,.69444,.13372,0,.66667],89:[0,.69444,.17261,0,.66667],90:[0,.69444,.11983,0,.61111],91:[.25,.75,.15942,0,.28889],93:[.25,.75,.08719,0,.28889],94:[0,.69444,.0799,0,.5],95:[.35,.09444,.08616,0,.5],97:[0,.44444,.00981,0,.48056],98:[0,.69444,.03057,0,.51667],99:[0,.44444,.08336,0,.44445],100:[0,.69444,.09483,0,.51667],101:[0,.44444,.06778,0,.44445],102:[0,.69444,.21705,0,.30556],103:[.19444,.44444,.10836,0,.5],104:[0,.69444,.01778,0,.51667],105:[0,.67937,.09718,0,.23889],106:[.19444,.67937,.09162,0,.26667],107:[0,.69444,.08336,0,.48889],108:[0,.69444,.09483,0,.23889],109:[0,.44444,.01778,0,.79445],110:[0,.44444,.01778,0,.51667],111:[0,.44444,.06613,0,.5],112:[.19444,.44444,.0389,0,.51667],113:[.19444,.44444,.04169,0,.51667],114:[0,.44444,.10836,0,.34167],115:[0,.44444,.0778,0,.38333],116:[0,.57143,.07225,0,.36111],117:[0,.44444,.04169,0,.51667],118:[0,.44444,.10836,0,.46111],119:[0,.44444,.10836,0,.68334],120:[0,.44444,.09169,0,.46111],121:[.19444,.44444,.10836,0,.46111],122:[0,.44444,.08752,0,.43472],126:[.35,.32659,.08826,0,.5],160:[0,0,0,0,.25],168:[0,.67937,.06385,0,.5],176:[0,.69444,0,0,.73752],184:[.17014,0,0,0,.44445],305:[0,.44444,.04169,0,.23889],567:[.19444,.44444,.04169,0,.26667],710:[0,.69444,.0799,0,.5],711:[0,.63194,.08432,0,.5],713:[0,.60889,.08776,0,.5],714:[0,.69444,.09205,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,.09483,0,.5],729:[0,.67937,.07774,0,.27778],730:[0,.69444,0,0,.73752],732:[0,.67659,.08826,0,.5],733:[0,.69444,.09205,0,.5],915:[0,.69444,.13372,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,.07555,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,.12816,0,.66667],928:[0,.69444,.08094,0,.70834],931:[0,.69444,.11983,0,.72222],933:[0,.69444,.09031,0,.77778],934:[0,.69444,.04603,0,.72222],936:[0,.69444,.09031,0,.77778],937:[0,.69444,.08293,0,.72222],8211:[0,.44444,.08616,0,.5],8212:[0,.44444,.08616,0,1],8216:[0,.69444,.07816,0,.27778],8217:[0,.69444,.07816,0,.27778],8220:[0,.69444,.14205,0,.5],8221:[0,.69444,.00316,0,.5]},"SansSerif-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.31945],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.75834],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,0,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.65556,0,0,.5],49:[0,.65556,0,0,.5],50:[0,.65556,0,0,.5],51:[0,.65556,0,0,.5],52:[0,.65556,0,0,.5],53:[0,.65556,0,0,.5],54:[0,.65556,0,0,.5],55:[0,.65556,0,0,.5],56:[0,.65556,0,0,.5],57:[0,.65556,0,0,.5],58:[0,.44444,0,0,.27778],59:[.125,.44444,0,0,.27778],61:[-.13,.37,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,0,0,.66667],67:[0,.69444,0,0,.63889],68:[0,.69444,0,0,.72223],69:[0,.69444,0,0,.59722],70:[0,.69444,0,0,.56945],71:[0,.69444,0,0,.66667],72:[0,.69444,0,0,.70834],73:[0,.69444,0,0,.27778],74:[0,.69444,0,0,.47222],75:[0,.69444,0,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,0,0,.875],78:[0,.69444,0,0,.70834],79:[0,.69444,0,0,.73611],80:[0,.69444,0,0,.63889],81:[.125,.69444,0,0,.73611],82:[0,.69444,0,0,.64584],83:[0,.69444,0,0,.55556],84:[0,.69444,0,0,.68056],85:[0,.69444,0,0,.6875],86:[0,.69444,.01389,0,.66667],87:[0,.69444,.01389,0,.94445],88:[0,.69444,0,0,.66667],89:[0,.69444,.025,0,.66667],90:[0,.69444,0,0,.61111],91:[.25,.75,0,0,.28889],93:[.25,.75,0,0,.28889],94:[0,.69444,0,0,.5],95:[.35,.09444,.02778,0,.5],97:[0,.44444,0,0,.48056],98:[0,.69444,0,0,.51667],99:[0,.44444,0,0,.44445],100:[0,.69444,0,0,.51667],101:[0,.44444,0,0,.44445],102:[0,.69444,.06944,0,.30556],103:[.19444,.44444,.01389,0,.5],104:[0,.69444,0,0,.51667],105:[0,.67937,0,0,.23889],106:[.19444,.67937,0,0,.26667],107:[0,.69444,0,0,.48889],108:[0,.69444,0,0,.23889],109:[0,.44444,0,0,.79445],110:[0,.44444,0,0,.51667],111:[0,.44444,0,0,.5],112:[.19444,.44444,0,0,.51667],113:[.19444,.44444,0,0,.51667],114:[0,.44444,.01389,0,.34167],115:[0,.44444,0,0,.38333],116:[0,.57143,0,0,.36111],117:[0,.44444,0,0,.51667],118:[0,.44444,.01389,0,.46111],119:[0,.44444,.01389,0,.68334],120:[0,.44444,0,0,.46111],121:[.19444,.44444,.01389,0,.46111],122:[0,.44444,0,0,.43472],126:[.35,.32659,0,0,.5],160:[0,0,0,0,.25],168:[0,.67937,0,0,.5],176:[0,.69444,0,0,.66667],184:[.17014,0,0,0,.44445],305:[0,.44444,0,0,.23889],567:[.19444,.44444,0,0,.26667],710:[0,.69444,0,0,.5],711:[0,.63194,0,0,.5],713:[0,.60889,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.67937,0,0,.27778],730:[0,.69444,0,0,.66667],732:[0,.67659,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.69444,0,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,0,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,0,0,.66667],928:[0,.69444,0,0,.70834],931:[0,.69444,0,0,.72222],933:[0,.69444,0,0,.77778],934:[0,.69444,0,0,.72222],936:[0,.69444,0,0,.77778],937:[0,.69444,0,0,.72222],8211:[0,.44444,.02778,0,.5],8212:[0,.44444,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5]},"Script-Regular":{32:[0,0,0,0,.25],65:[0,.7,.22925,0,.80253],66:[0,.7,.04087,0,.90757],67:[0,.7,.1689,0,.66619],68:[0,.7,.09371,0,.77443],69:[0,.7,.18583,0,.56162],70:[0,.7,.13634,0,.89544],71:[0,.7,.17322,0,.60961],72:[0,.7,.29694,0,.96919],73:[0,.7,.19189,0,.80907],74:[.27778,.7,.19189,0,1.05159],75:[0,.7,.31259,0,.91364],76:[0,.7,.19189,0,.87373],77:[0,.7,.15981,0,1.08031],78:[0,.7,.3525,0,.9015],79:[0,.7,.08078,0,.73787],80:[0,.7,.08078,0,1.01262],81:[0,.7,.03305,0,.88282],82:[0,.7,.06259,0,.85],83:[0,.7,.19189,0,.86767],84:[0,.7,.29087,0,.74697],85:[0,.7,.25815,0,.79996],86:[0,.7,.27523,0,.62204],87:[0,.7,.27523,0,.80532],88:[0,.7,.26006,0,.94445],89:[0,.7,.2939,0,.70961],90:[0,.7,.24037,0,.8212],160:[0,0,0,0,.25]},"Size1-Regular":{32:[0,0,0,0,.25],40:[.35001,.85,0,0,.45834],41:[.35001,.85,0,0,.45834],47:[.35001,.85,0,0,.57778],91:[.35001,.85,0,0,.41667],92:[.35001,.85,0,0,.57778],93:[.35001,.85,0,0,.41667],123:[.35001,.85,0,0,.58334],125:[.35001,.85,0,0,.58334],160:[0,0,0,0,.25],710:[0,.72222,0,0,.55556],732:[0,.72222,0,0,.55556],770:[0,.72222,0,0,.55556],771:[0,.72222,0,0,.55556],8214:[-99e-5,.601,0,0,.77778],8593:[1e-5,.6,0,0,.66667],8595:[1e-5,.6,0,0,.66667],8657:[1e-5,.6,0,0,.77778],8659:[1e-5,.6,0,0,.77778],8719:[.25001,.75,0,0,.94445],8720:[.25001,.75,0,0,.94445],8721:[.25001,.75,0,0,1.05556],8730:[.35001,.85,0,0,1],8739:[-.00599,.606,0,0,.33333],8741:[-.00599,.606,0,0,.55556],8747:[.30612,.805,.19445,0,.47222],8748:[.306,.805,.19445,0,.47222],8749:[.306,.805,.19445,0,.47222],8750:[.30612,.805,.19445,0,.47222],8896:[.25001,.75,0,0,.83334],8897:[.25001,.75,0,0,.83334],8898:[.25001,.75,0,0,.83334],8899:[.25001,.75,0,0,.83334],8968:[.35001,.85,0,0,.47222],8969:[.35001,.85,0,0,.47222],8970:[.35001,.85,0,0,.47222],8971:[.35001,.85,0,0,.47222],9168:[-99e-5,.601,0,0,.66667],10216:[.35001,.85,0,0,.47222],10217:[.35001,.85,0,0,.47222],10752:[.25001,.75,0,0,1.11111],10753:[.25001,.75,0,0,1.11111],10754:[.25001,.75,0,0,1.11111],10756:[.25001,.75,0,0,.83334],10758:[.25001,.75,0,0,.83334]},"Size2-Regular":{32:[0,0,0,0,.25],40:[.65002,1.15,0,0,.59722],41:[.65002,1.15,0,0,.59722],47:[.65002,1.15,0,0,.81111],91:[.65002,1.15,0,0,.47222],92:[.65002,1.15,0,0,.81111],93:[.65002,1.15,0,0,.47222],123:[.65002,1.15,0,0,.66667],125:[.65002,1.15,0,0,.66667],160:[0,0,0,0,.25],710:[0,.75,0,0,1],732:[0,.75,0,0,1],770:[0,.75,0,0,1],771:[0,.75,0,0,1],8719:[.55001,1.05,0,0,1.27778],8720:[.55001,1.05,0,0,1.27778],8721:[.55001,1.05,0,0,1.44445],8730:[.65002,1.15,0,0,1],8747:[.86225,1.36,.44445,0,.55556],8748:[.862,1.36,.44445,0,.55556],8749:[.862,1.36,.44445,0,.55556],8750:[.86225,1.36,.44445,0,.55556],8896:[.55001,1.05,0,0,1.11111],8897:[.55001,1.05,0,0,1.11111],8898:[.55001,1.05,0,0,1.11111],8899:[.55001,1.05,0,0,1.11111],8968:[.65002,1.15,0,0,.52778],8969:[.65002,1.15,0,0,.52778],8970:[.65002,1.15,0,0,.52778],8971:[.65002,1.15,0,0,.52778],10216:[.65002,1.15,0,0,.61111],10217:[.65002,1.15,0,0,.61111],10752:[.55001,1.05,0,0,1.51112],10753:[.55001,1.05,0,0,1.51112],10754:[.55001,1.05,0,0,1.51112],10756:[.55001,1.05,0,0,1.11111],10758:[.55001,1.05,0,0,1.11111]},"Size3-Regular":{32:[0,0,0,0,.25],40:[.95003,1.45,0,0,.73611],41:[.95003,1.45,0,0,.73611],47:[.95003,1.45,0,0,1.04445],91:[.95003,1.45,0,0,.52778],92:[.95003,1.45,0,0,1.04445],93:[.95003,1.45,0,0,.52778],123:[.95003,1.45,0,0,.75],125:[.95003,1.45,0,0,.75],160:[0,0,0,0,.25],710:[0,.75,0,0,1.44445],732:[0,.75,0,0,1.44445],770:[0,.75,0,0,1.44445],771:[0,.75,0,0,1.44445],8730:[.95003,1.45,0,0,1],8968:[.95003,1.45,0,0,.58334],8969:[.95003,1.45,0,0,.58334],8970:[.95003,1.45,0,0,.58334],8971:[.95003,1.45,0,0,.58334],10216:[.95003,1.45,0,0,.75],10217:[.95003,1.45,0,0,.75]},"Size4-Regular":{32:[0,0,0,0,.25],40:[1.25003,1.75,0,0,.79167],41:[1.25003,1.75,0,0,.79167],47:[1.25003,1.75,0,0,1.27778],91:[1.25003,1.75,0,0,.58334],92:[1.25003,1.75,0,0,1.27778],93:[1.25003,1.75,0,0,.58334],123:[1.25003,1.75,0,0,.80556],125:[1.25003,1.75,0,0,.80556],160:[0,0,0,0,.25],710:[0,.825,0,0,1.8889],732:[0,.825,0,0,1.8889],770:[0,.825,0,0,1.8889],771:[0,.825,0,0,1.8889],8730:[1.25003,1.75,0,0,1],8968:[1.25003,1.75,0,0,.63889],8969:[1.25003,1.75,0,0,.63889],8970:[1.25003,1.75,0,0,.63889],8971:[1.25003,1.75,0,0,.63889],9115:[.64502,1.155,0,0,.875],9116:[1e-5,.6,0,0,.875],9117:[.64502,1.155,0,0,.875],9118:[.64502,1.155,0,0,.875],9119:[1e-5,.6,0,0,.875],9120:[.64502,1.155,0,0,.875],9121:[.64502,1.155,0,0,.66667],9122:[-99e-5,.601,0,0,.66667],9123:[.64502,1.155,0,0,.66667],9124:[.64502,1.155,0,0,.66667],9125:[-99e-5,.601,0,0,.66667],9126:[.64502,1.155,0,0,.66667],9127:[1e-5,.9,0,0,.88889],9128:[.65002,1.15,0,0,.88889],9129:[.90001,0,0,0,.88889],9130:[0,.3,0,0,.88889],9131:[1e-5,.9,0,0,.88889],9132:[.65002,1.15,0,0,.88889],9133:[.90001,0,0,0,.88889],9143:[.88502,.915,0,0,1.05556],10216:[1.25003,1.75,0,0,.80556],10217:[1.25003,1.75,0,0,.80556],57344:[-.00499,.605,0,0,1.05556],57345:[-.00499,.605,0,0,1.05556],57680:[0,.12,0,0,.45],57681:[0,.12,0,0,.45],57682:[0,.12,0,0,.45],57683:[0,.12,0,0,.45]},"Typewriter-Regular":{32:[0,0,0,0,.525],33:[0,.61111,0,0,.525],34:[0,.61111,0,0,.525],35:[0,.61111,0,0,.525],36:[.08333,.69444,0,0,.525],37:[.08333,.69444,0,0,.525],38:[0,.61111,0,0,.525],39:[0,.61111,0,0,.525],40:[.08333,.69444,0,0,.525],41:[.08333,.69444,0,0,.525],42:[0,.52083,0,0,.525],43:[-.08056,.53055,0,0,.525],44:[.13889,.125,0,0,.525],45:[-.08056,.53055,0,0,.525],46:[0,.125,0,0,.525],47:[.08333,.69444,0,0,.525],48:[0,.61111,0,0,.525],49:[0,.61111,0,0,.525],50:[0,.61111,0,0,.525],51:[0,.61111,0,0,.525],52:[0,.61111,0,0,.525],53:[0,.61111,0,0,.525],54:[0,.61111,0,0,.525],55:[0,.61111,0,0,.525],56:[0,.61111,0,0,.525],57:[0,.61111,0,0,.525],58:[0,.43056,0,0,.525],59:[.13889,.43056,0,0,.525],60:[-.05556,.55556,0,0,.525],61:[-.19549,.41562,0,0,.525],62:[-.05556,.55556,0,0,.525],63:[0,.61111,0,0,.525],64:[0,.61111,0,0,.525],65:[0,.61111,0,0,.525],66:[0,.61111,0,0,.525],67:[0,.61111,0,0,.525],68:[0,.61111,0,0,.525],69:[0,.61111,0,0,.525],70:[0,.61111,0,0,.525],71:[0,.61111,0,0,.525],72:[0,.61111,0,0,.525],73:[0,.61111,0,0,.525],74:[0,.61111,0,0,.525],75:[0,.61111,0,0,.525],76:[0,.61111,0,0,.525],77:[0,.61111,0,0,.525],78:[0,.61111,0,0,.525],79:[0,.61111,0,0,.525],80:[0,.61111,0,0,.525],81:[.13889,.61111,0,0,.525],82:[0,.61111,0,0,.525],83:[0,.61111,0,0,.525],84:[0,.61111,0,0,.525],85:[0,.61111,0,0,.525],86:[0,.61111,0,0,.525],87:[0,.61111,0,0,.525],88:[0,.61111,0,0,.525],89:[0,.61111,0,0,.525],90:[0,.61111,0,0,.525],91:[.08333,.69444,0,0,.525],92:[.08333,.69444,0,0,.525],93:[.08333,.69444,0,0,.525],94:[0,.61111,0,0,.525],95:[.09514,0,0,0,.525],96:[0,.61111,0,0,.525],97:[0,.43056,0,0,.525],98:[0,.61111,0,0,.525],99:[0,.43056,0,0,.525],100:[0,.61111,0,0,.525],101:[0,.43056,0,0,.525],102:[0,.61111,0,0,.525],103:[.22222,.43056,0,0,.525],104:[0,.61111,0,0,.525],105:[0,.61111,0,0,.525],106:[.22222,.61111,0,0,.525],107:[0,.61111,0,0,.525],108:[0,.61111,0,0,.525],109:[0,.43056,0,0,.525],110:[0,.43056,0,0,.525],111:[0,.43056,0,0,.525],112:[.22222,.43056,0,0,.525],113:[.22222,.43056,0,0,.525],114:[0,.43056,0,0,.525],115:[0,.43056,0,0,.525],116:[0,.55358,0,0,.525],117:[0,.43056,0,0,.525],118:[0,.43056,0,0,.525],119:[0,.43056,0,0,.525],120:[0,.43056,0,0,.525],121:[.22222,.43056,0,0,.525],122:[0,.43056,0,0,.525],123:[.08333,.69444,0,0,.525],124:[.08333,.69444,0,0,.525],125:[.08333,.69444,0,0,.525],126:[0,.61111,0,0,.525],127:[0,.61111,0,0,.525],160:[0,0,0,0,.525],176:[0,.61111,0,0,.525],184:[.19445,0,0,0,.525],305:[0,.43056,0,0,.525],567:[.22222,.43056,0,0,.525],711:[0,.56597,0,0,.525],713:[0,.56555,0,0,.525],714:[0,.61111,0,0,.525],715:[0,.61111,0,0,.525],728:[0,.61111,0,0,.525],730:[0,.61111,0,0,.525],770:[0,.61111,0,0,.525],771:[0,.61111,0,0,.525],776:[0,.61111,0,0,.525],915:[0,.61111,0,0,.525],916:[0,.61111,0,0,.525],920:[0,.61111,0,0,.525],923:[0,.61111,0,0,.525],926:[0,.61111,0,0,.525],928:[0,.61111,0,0,.525],931:[0,.61111,0,0,.525],933:[0,.61111,0,0,.525],934:[0,.61111,0,0,.525],936:[0,.61111,0,0,.525],937:[0,.61111,0,0,.525],8216:[0,.61111,0,0,.525],8217:[0,.61111,0,0,.525],8242:[0,.61111,0,0,.525],9251:[.11111,.21944,0,0,.525]}},N={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25],defaultRuleThickness:[.04,.049,.049],bigOpSpacing1:[.111,.111,.111],bigOpSpacing2:[.166,.166,.166],bigOpSpacing3:[.2,.2,.2],bigOpSpacing4:[.6,.611,.611],bigOpSpacing5:[.1,.143,.143],sqrtRuleThickness:[.04,.04,.04],ptPerEm:[10,10,10],doubleRuleSep:[.2,.2,.2],arrayRuleWidth:[.04,.04,.04],fboxsep:[.3,.3,.3],fboxrule:[.04,.04,.04]},q={"\xc5":"A","\xd0":"D","\xde":"o","\xe5":"a","\xf0":"d","\xfe":"o","\u0410":"A","\u0411":"B","\u0412":"B","\u0413":"F","\u0414":"A","\u0415":"E","\u0416":"K","\u0417":"3","\u0418":"N","\u0419":"N","\u041a":"K","\u041b":"N","\u041c":"M","\u041d":"H","\u041e":"O","\u041f":"N","\u0420":"P","\u0421":"C","\u0422":"T","\u0423":"y","\u0424":"O","\u0425":"X","\u0426":"U","\u0427":"h","\u0428":"W","\u0429":"W","\u042a":"B","\u042b":"X","\u042c":"B","\u042d":"3","\u042e":"X","\u042f":"R","\u0430":"a","\u0431":"b","\u0432":"a","\u0433":"r","\u0434":"y","\u0435":"e","\u0436":"m","\u0437":"e","\u0438":"n","\u0439":"n","\u043a":"n","\u043b":"n","\u043c":"m","\u043d":"n","\u043e":"o","\u043f":"n","\u0440":"p","\u0441":"c","\u0442":"o","\u0443":"y","\u0444":"b","\u0445":"x","\u0446":"n","\u0447":"n","\u0448":"w","\u0449":"w","\u044a":"a","\u044b":"m","\u044c":"a","\u044d":"e","\u044e":"m","\u044f":"r"};function I(e,t,r){if(!C[t])throw new Error("Font metrics not found for font: "+t+".");var a=e.charCodeAt(0),n=C[t][a];if(!n&&e[0]in q&&(a=q[e[0]].charCodeAt(0),n=C[t][a]),n||"text"!==r||z(a)&&(n=C[t][77]),n)return{depth:n[0],height:n[1],italic:n[2],skew:n[3],width:n[4]}}var R={};var H=[[1,1,1],[2,1,1],[3,1,1],[4,2,1],[5,2,1],[6,3,1],[7,4,2],[8,6,3],[9,7,6],[10,8,7],[11,10,9]],O=[.5,.6,.7,.8,.9,1,1.2,1.44,1.728,2.074,2.488],E=function(e,t){return t.size<2?e:H[e-1][t.size-1]};class L{constructor(e){this.style=void 0,this.color=void 0,this.size=void 0,this.textSize=void 0,this.phantom=void 0,this.font=void 0,this.fontFamily=void 0,this.fontWeight=void 0,this.fontShape=void 0,this.sizeMultiplier=void 0,this.maxSize=void 0,this.minRuleThickness=void 0,this._fontMetrics=void 0,this.style=e.style,this.color=e.color,this.size=e.size||L.BASESIZE,this.textSize=e.textSize||this.size,this.phantom=!!e.phantom,this.font=e.font||"",this.fontFamily=e.fontFamily||"",this.fontWeight=e.fontWeight||"",this.fontShape=e.fontShape||"",this.sizeMultiplier=O[this.size-1],this.maxSize=e.maxSize,this.minRuleThickness=e.minRuleThickness,this._fontMetrics=void 0}extend(e){var t={style:this.style,size:this.size,textSize:this.textSize,color:this.color,phantom:this.phantom,font:this.font,fontFamily:this.fontFamily,fontWeight:this.fontWeight,fontShape:this.fontShape,maxSize:this.maxSize,minRuleThickness:this.minRuleThickness};for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);return new L(t)}havingStyle(e){return this.style===e?this:this.extend({style:e,size:E(this.textSize,e)})}havingCrampedStyle(){return this.havingStyle(this.style.cramp())}havingSize(e){return this.size===e&&this.textSize===e?this:this.extend({style:this.style.text(),size:e,textSize:e,sizeMultiplier:O[e-1]})}havingBaseStyle(e){e=e||this.style.text();var t=E(L.BASESIZE,e);return this.size===t&&this.textSize===L.BASESIZE&&this.style===e?this:this.extend({style:e,size:t})}havingBaseSizing(){var e;switch(this.style.id){case 4:case 5:e=3;break;case 6:case 7:e=1;break;default:e=6}return this.extend({style:this.style.text(),size:e})}withColor(e){return this.extend({color:e})}withPhantom(){return this.extend({phantom:!0})}withFont(e){return this.extend({font:e})}withTextFontFamily(e){return this.extend({fontFamily:e,font:""})}withTextFontWeight(e){return this.extend({fontWeight:e,font:""})}withTextFontShape(e){return this.extend({fontShape:e,font:""})}sizingClasses(e){return e.size!==this.size?["sizing","reset-size"+e.size,"size"+this.size]:[]}baseSizingClasses(){return this.size!==L.BASESIZE?["sizing","reset-size"+this.size,"size"+L.BASESIZE]:[]}fontMetrics(){return this._fontMetrics||(this._fontMetrics=function(e){var t;if(!R[t=e>=5?0:e>=3?1:2]){var r=R[t]={cssEmPerMu:N.quad[t]/18};for(var a in N)N.hasOwnProperty(a)&&(r[a]=N[a][t])}return R[t]}(this.size)),this._fontMetrics}getColor(){return this.phantom?"transparent":this.color}}L.BASESIZE=6;var D={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:1.00375,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:1.00375},V={ex:!0,em:!0,mu:!0},P=function(e){return"string"!=typeof e&&(e=e.unit),e in D||e in V||"ex"===e},F=function(e,t){var r;if(e.unit in D)r=D[e.unit]/t.fontMetrics().ptPerEm/t.sizeMultiplier;else if("mu"===e.unit)r=t.fontMetrics().cssEmPerMu;else{var a;if(a=t.style.isTight()?t.havingStyle(t.style.text()):t,"ex"===e.unit)r=a.fontMetrics().xHeight;else{if("em"!==e.unit)throw new i("Invalid unit: '"+e.unit+"'");r=a.fontMetrics().quad}a!==t&&(r*=a.sizeMultiplier/t.sizeMultiplier)}return Math.min(e.number*r,t.maxSize)},G=function(e){return+e.toFixed(4)+"em"},U=function(e){return e.filter((e=>e)).join(" ")},Y=function(e,t,r){if(this.classes=e||[],this.attributes={},this.height=0,this.depth=0,this.maxFontSize=0,this.style=r||{},t){t.style.isTight()&&this.classes.push("mtight");var a=t.getColor();a&&(this.style.color=a)}},X=function(e){var t=document.createElement(e);for(var r in t.className=U(this.classes),this.style)this.style.hasOwnProperty(r)&&(t.style[r]=this.style[r]);for(var a in this.attributes)this.attributes.hasOwnProperty(a)&&t.setAttribute(a,this.attributes[a]);for(var n=0;n"};class _{constructor(e,t,r,a){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,Y.call(this,e,r,a),this.children=t||[]}setAttribute(e,t){this.attributes[e]=t}hasClass(e){return m.contains(this.classes,e)}toNode(){return X.call(this,"span")}toMarkup(){return W.call(this,"span")}}class j{constructor(e,t,r,a){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,Y.call(this,t,a),this.children=r||[],this.setAttribute("href",e)}setAttribute(e,t){this.attributes[e]=t}hasClass(e){return m.contains(this.classes,e)}toNode(){return X.call(this,"a")}toMarkup(){return W.call(this,"a")}}class ${constructor(e,t,r){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=t,this.src=e,this.classes=["mord"],this.style=r}hasClass(e){return m.contains(this.classes,e)}toNode(){var e=document.createElement("img");for(var t in e.src=this.src,e.alt=this.alt,e.className="mord",this.style)this.style.hasOwnProperty(t)&&(e.style[t]=this.style[t]);return e}toMarkup(){var e=''+m.escape(this.alt)+'=n[0]&&e<=n[1])return r.name}return null}(this.text.charCodeAt(0));l&&this.classes.push(l+"_fallback"),/[\xee\xef\xed\xec]/.test(this.text)&&(this.text=Z[this.text])}hasClass(e){return m.contains(this.classes,e)}toNode(){var e=document.createTextNode(this.text),t=null;for(var r in this.italic>0&&((t=document.createElement("span")).style.marginRight=G(this.italic)),this.classes.length>0&&((t=t||document.createElement("span")).className=U(this.classes)),this.style)this.style.hasOwnProperty(r)&&((t=t||document.createElement("span")).style[r]=this.style[r]);return t?(t.appendChild(e),t):e}toMarkup(){var e=!1,t="0&&(r+="margin-right:"+this.italic+"em;"),this.style)this.style.hasOwnProperty(a)&&(r+=m.hyphenate(a)+":"+this.style[a]+";");r&&(e=!0,t+=' style="'+m.escape(r)+'"');var n=m.escape(this.text);return e?(t+=">",t+=n,t+=""):n}}class J{constructor(e,t){this.children=void 0,this.attributes=void 0,this.children=e||[],this.attributes=t||{}}toNode(){var e=document.createElementNS("http://www.w3.org/2000/svg","svg");for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);for(var r=0;r':''}}class ee{constructor(e){this.attributes=void 0,this.attributes=e||{}}toNode(){var e=document.createElementNS("http://www.w3.org/2000/svg","line");for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);return e}toMarkup(){var e="","\\gt",!0),ie(oe,le,be,"\u2208","\\in",!0),ie(oe,le,be,"\ue020","\\@not"),ie(oe,le,be,"\u2282","\\subset",!0),ie(oe,le,be,"\u2283","\\supset",!0),ie(oe,le,be,"\u2286","\\subseteq",!0),ie(oe,le,be,"\u2287","\\supseteq",!0),ie(oe,he,be,"\u2288","\\nsubseteq",!0),ie(oe,he,be,"\u2289","\\nsupseteq",!0),ie(oe,le,be,"\u22a8","\\models"),ie(oe,le,be,"\u2190","\\leftarrow",!0),ie(oe,le,be,"\u2264","\\le"),ie(oe,le,be,"\u2264","\\leq",!0),ie(oe,le,be,"<","\\lt",!0),ie(oe,le,be,"\u2192","\\rightarrow",!0),ie(oe,le,be,"\u2192","\\to"),ie(oe,he,be,"\u2271","\\ngeq",!0),ie(oe,he,be,"\u2270","\\nleq",!0),ie(oe,le,ye,"\xa0","\\ "),ie(oe,le,ye,"\xa0","\\space"),ie(oe,le,ye,"\xa0","\\nobreakspace"),ie(se,le,ye,"\xa0","\\ "),ie(se,le,ye,"\xa0"," "),ie(se,le,ye,"\xa0","\\space"),ie(se,le,ye,"\xa0","\\nobreakspace"),ie(oe,le,ye,null,"\\nobreak"),ie(oe,le,ye,null,"\\allowbreak"),ie(oe,le,ve,",",","),ie(oe,le,ve,";",";"),ie(oe,he,ce,"\u22bc","\\barwedge",!0),ie(oe,he,ce,"\u22bb","\\veebar",!0),ie(oe,le,ce,"\u2299","\\odot",!0),ie(oe,le,ce,"\u2295","\\oplus",!0),ie(oe,le,ce,"\u2297","\\otimes",!0),ie(oe,le,xe,"\u2202","\\partial",!0),ie(oe,le,ce,"\u2298","\\oslash",!0),ie(oe,he,ce,"\u229a","\\circledcirc",!0),ie(oe,he,ce,"\u22a1","\\boxdot",!0),ie(oe,le,ce,"\u25b3","\\bigtriangleup"),ie(oe,le,ce,"\u25bd","\\bigtriangledown"),ie(oe,le,ce,"\u2020","\\dagger"),ie(oe,le,ce,"\u22c4","\\diamond"),ie(oe,le,ce,"\u22c6","\\star"),ie(oe,le,ce,"\u25c3","\\triangleleft"),ie(oe,le,ce,"\u25b9","\\triangleright"),ie(oe,le,fe,"{","\\{"),ie(se,le,xe,"{","\\{"),ie(se,le,xe,"{","\\textbraceleft"),ie(oe,le,pe,"}","\\}"),ie(se,le,xe,"}","\\}"),ie(se,le,xe,"}","\\textbraceright"),ie(oe,le,fe,"{","\\lbrace"),ie(oe,le,pe,"}","\\rbrace"),ie(oe,le,fe,"[","\\lbrack",!0),ie(se,le,xe,"[","\\lbrack",!0),ie(oe,le,pe,"]","\\rbrack",!0),ie(se,le,xe,"]","\\rbrack",!0),ie(oe,le,fe,"(","\\lparen",!0),ie(oe,le,pe,")","\\rparen",!0),ie(se,le,xe,"<","\\textless",!0),ie(se,le,xe,">","\\textgreater",!0),ie(oe,le,fe,"\u230a","\\lfloor",!0),ie(oe,le,pe,"\u230b","\\rfloor",!0),ie(oe,le,fe,"\u2308","\\lceil",!0),ie(oe,le,pe,"\u2309","\\rceil",!0),ie(oe,le,xe,"\\","\\backslash"),ie(oe,le,xe,"\u2223","|"),ie(oe,le,xe,"\u2223","\\vert"),ie(se,le,xe,"|","\\textbar",!0),ie(oe,le,xe,"\u2225","\\|"),ie(oe,le,xe,"\u2225","\\Vert"),ie(se,le,xe,"\u2225","\\textbardbl"),ie(se,le,xe,"~","\\textasciitilde"),ie(se,le,xe,"\\","\\textbackslash"),ie(se,le,xe,"^","\\textasciicircum"),ie(oe,le,be,"\u2191","\\uparrow",!0),ie(oe,le,be,"\u21d1","\\Uparrow",!0),ie(oe,le,be,"\u2193","\\downarrow",!0),ie(oe,le,be,"\u21d3","\\Downarrow",!0),ie(oe,le,be,"\u2195","\\updownarrow",!0),ie(oe,le,be,"\u21d5","\\Updownarrow",!0),ie(oe,le,ge,"\u2210","\\coprod"),ie(oe,le,ge,"\u22c1","\\bigvee"),ie(oe,le,ge,"\u22c0","\\bigwedge"),ie(oe,le,ge,"\u2a04","\\biguplus"),ie(oe,le,ge,"\u22c2","\\bigcap"),ie(oe,le,ge,"\u22c3","\\bigcup"),ie(oe,le,ge,"\u222b","\\int"),ie(oe,le,ge,"\u222b","\\intop"),ie(oe,le,ge,"\u222c","\\iint"),ie(oe,le,ge,"\u222d","\\iiint"),ie(oe,le,ge,"\u220f","\\prod"),ie(oe,le,ge,"\u2211","\\sum"),ie(oe,le,ge,"\u2a02","\\bigotimes"),ie(oe,le,ge,"\u2a01","\\bigoplus"),ie(oe,le,ge,"\u2a00","\\bigodot"),ie(oe,le,ge,"\u222e","\\oint"),ie(oe,le,ge,"\u222f","\\oiint"),ie(oe,le,ge,"\u2230","\\oiiint"),ie(oe,le,ge,"\u2a06","\\bigsqcup"),ie(oe,le,ge,"\u222b","\\smallint"),ie(se,le,ue,"\u2026","\\textellipsis"),ie(oe,le,ue,"\u2026","\\mathellipsis"),ie(se,le,ue,"\u2026","\\ldots",!0),ie(oe,le,ue,"\u2026","\\ldots",!0),ie(oe,le,ue,"\u22ef","\\@cdots",!0),ie(oe,le,ue,"\u22f1","\\ddots",!0),ie(oe,le,xe,"\u22ee","\\varvdots"),ie(oe,le,me,"\u02ca","\\acute"),ie(oe,le,me,"\u02cb","\\grave"),ie(oe,le,me,"\xa8","\\ddot"),ie(oe,le,me,"~","\\tilde"),ie(oe,le,me,"\u02c9","\\bar"),ie(oe,le,me,"\u02d8","\\breve"),ie(oe,le,me,"\u02c7","\\check"),ie(oe,le,me,"^","\\hat"),ie(oe,le,me,"\u20d7","\\vec"),ie(oe,le,me,"\u02d9","\\dot"),ie(oe,le,me,"\u02da","\\mathring"),ie(oe,le,de,"\ue131","\\@imath"),ie(oe,le,de,"\ue237","\\@jmath"),ie(oe,le,xe,"\u0131","\u0131"),ie(oe,le,xe,"\u0237","\u0237"),ie(se,le,xe,"\u0131","\\i",!0),ie(se,le,xe,"\u0237","\\j",!0),ie(se,le,xe,"\xdf","\\ss",!0),ie(se,le,xe,"\xe6","\\ae",!0),ie(se,le,xe,"\u0153","\\oe",!0),ie(se,le,xe,"\xf8","\\o",!0),ie(se,le,xe,"\xc6","\\AE",!0),ie(se,le,xe,"\u0152","\\OE",!0),ie(se,le,xe,"\xd8","\\O",!0),ie(se,le,me,"\u02ca","\\'"),ie(se,le,me,"\u02cb","\\`"),ie(se,le,me,"\u02c6","\\^"),ie(se,le,me,"\u02dc","\\~"),ie(se,le,me,"\u02c9","\\="),ie(se,le,me,"\u02d8","\\u"),ie(se,le,me,"\u02d9","\\."),ie(se,le,me,"\xb8","\\c"),ie(se,le,me,"\u02da","\\r"),ie(se,le,me,"\u02c7","\\v"),ie(se,le,me,"\xa8",'\\"'),ie(se,le,me,"\u02dd","\\H"),ie(se,le,me,"\u25ef","\\textcircled");var we={"--":!0,"---":!0,"``":!0,"''":!0};ie(se,le,xe,"\u2013","--",!0),ie(se,le,xe,"\u2013","\\textendash"),ie(se,le,xe,"\u2014","---",!0),ie(se,le,xe,"\u2014","\\textemdash"),ie(se,le,xe,"\u2018","`",!0),ie(se,le,xe,"\u2018","\\textquoteleft"),ie(se,le,xe,"\u2019","'",!0),ie(se,le,xe,"\u2019","\\textquoteright"),ie(se,le,xe,"\u201c","``",!0),ie(se,le,xe,"\u201c","\\textquotedblleft"),ie(se,le,xe,"\u201d","''",!0),ie(se,le,xe,"\u201d","\\textquotedblright"),ie(oe,le,xe,"\xb0","\\degree",!0),ie(se,le,xe,"\xb0","\\degree"),ie(se,le,xe,"\xb0","\\textdegree",!0),ie(oe,le,xe,"\xa3","\\pounds"),ie(oe,le,xe,"\xa3","\\mathsterling",!0),ie(se,le,xe,"\xa3","\\pounds"),ie(se,le,xe,"\xa3","\\textsterling",!0),ie(oe,he,xe,"\u2720","\\maltese"),ie(se,he,xe,"\u2720","\\maltese");for(var ke='0123456789/@."',Se=0;Se<14;Se++){var Me=ke.charAt(Se);ie(oe,le,xe,Me,Me)}for(var ze='0123456789!@*()-=+";:?/.,',Ae=0;Ae<25;Ae++){var Te=ze.charAt(Ae);ie(se,le,xe,Te,Te)}for(var Be="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",Ce=0;Ce<52;Ce++){var Ne=Be.charAt(Ce);ie(oe,le,de,Ne,Ne),ie(se,le,xe,Ne,Ne)}ie(oe,he,xe,"C","\u2102"),ie(se,he,xe,"C","\u2102"),ie(oe,he,xe,"H","\u210d"),ie(se,he,xe,"H","\u210d"),ie(oe,he,xe,"N","\u2115"),ie(se,he,xe,"N","\u2115"),ie(oe,he,xe,"P","\u2119"),ie(se,he,xe,"P","\u2119"),ie(oe,he,xe,"Q","\u211a"),ie(se,he,xe,"Q","\u211a"),ie(oe,he,xe,"R","\u211d"),ie(se,he,xe,"R","\u211d"),ie(oe,he,xe,"Z","\u2124"),ie(se,he,xe,"Z","\u2124"),ie(oe,le,de,"h","\u210e"),ie(se,le,de,"h","\u210e");for(var qe="",Ie=0;Ie<52;Ie++){var Re=Be.charAt(Ie);ie(oe,le,de,Re,qe=String.fromCharCode(55349,56320+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56372+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56424+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56580+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56684+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56736+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56788+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56840+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56944+Ie)),ie(se,le,xe,Re,qe),Ie<26&&(ie(oe,le,de,Re,qe=String.fromCharCode(55349,56632+Ie)),ie(se,le,xe,Re,qe),ie(oe,le,de,Re,qe=String.fromCharCode(55349,56476+Ie)),ie(se,le,xe,Re,qe))}ie(oe,le,de,"k",qe=String.fromCharCode(55349,56668)),ie(se,le,xe,"k",qe);for(var He=0;He<10;He++){var Oe=He.toString();ie(oe,le,de,Oe,qe=String.fromCharCode(55349,57294+He)),ie(se,le,xe,Oe,qe),ie(oe,le,de,Oe,qe=String.fromCharCode(55349,57314+He)),ie(se,le,xe,Oe,qe),ie(oe,le,de,Oe,qe=String.fromCharCode(55349,57324+He)),ie(se,le,xe,Oe,qe),ie(oe,le,de,Oe,qe=String.fromCharCode(55349,57334+He)),ie(se,le,xe,Oe,qe)}for(var Ee="\xd0\xde\xfe",Le=0;Le<3;Le++){var De=Ee.charAt(Le);ie(oe,le,de,De,De),ie(se,le,xe,De,De)}var Ve=[["mathbf","textbf","Main-Bold"],["mathbf","textbf","Main-Bold"],["mathnormal","textit","Math-Italic"],["mathnormal","textit","Math-Italic"],["boldsymbol","boldsymbol","Main-BoldItalic"],["boldsymbol","boldsymbol","Main-BoldItalic"],["mathscr","textscr","Script-Regular"],["","",""],["","",""],["","",""],["mathfrak","textfrak","Fraktur-Regular"],["mathfrak","textfrak","Fraktur-Regular"],["mathbb","textbb","AMS-Regular"],["mathbb","textbb","AMS-Regular"],["mathboldfrak","textboldfrak","Fraktur-Regular"],["mathboldfrak","textboldfrak","Fraktur-Regular"],["mathsf","textsf","SansSerif-Regular"],["mathsf","textsf","SansSerif-Regular"],["mathboldsf","textboldsf","SansSerif-Bold"],["mathboldsf","textboldsf","SansSerif-Bold"],["mathitsf","textitsf","SansSerif-Italic"],["mathitsf","textitsf","SansSerif-Italic"],["","",""],["","",""],["mathtt","texttt","Typewriter-Regular"],["mathtt","texttt","Typewriter-Regular"]],Pe=[["mathbf","textbf","Main-Bold"],["","",""],["mathsf","textsf","SansSerif-Regular"],["mathboldsf","textboldsf","SansSerif-Bold"],["mathtt","texttt","Typewriter-Regular"]],Fe=function(e,t,r){return ne[r][e]&&ne[r][e].replace&&(e=ne[r][e].replace),{value:e,metrics:I(e,t,r)}},Ge=function(e,t,r,a,n){var i,o=Fe(e,t,r),s=o.metrics;if(e=o.value,s){var l=s.italic;("text"===r||a&&"mathit"===a.font)&&(l=0),i=new K(e,s.height,s.depth,l,s.skew,s.width,n)}else"undefined"!=typeof console&&console.warn("No character metrics for '"+e+"' in style '"+t+"' and mode '"+r+"'"),i=new K(e,0,0,0,0,0,n);if(a){i.maxFontSize=a.sizeMultiplier,a.style.isTight()&&i.classes.push("mtight");var h=a.getColor();h&&(i.style.color=h)}return i},Ue=(e,t)=>{if(U(e.classes)!==U(t.classes)||e.skew!==t.skew||e.maxFontSize!==t.maxFontSize)return!1;if(1===e.classes.length){var r=e.classes[0];if("mbin"===r||"mord"===r)return!1}for(var a in e.style)if(e.style.hasOwnProperty(a)&&e.style[a]!==t.style[a])return!1;for(var n in t.style)if(t.style.hasOwnProperty(n)&&e.style[n]!==t.style[n])return!1;return!0},Ye=function(e){for(var t=0,r=0,a=0,n=0;nt&&(t=i.height),i.depth>r&&(r=i.depth),i.maxFontSize>a&&(a=i.maxFontSize)}e.height=t,e.depth=r,e.maxFontSize=a},Xe=function(e,t,r,a){var n=new _(e,t,r,a);return Ye(n),n},We=(e,t,r,a)=>new _(e,t,r,a),_e=function(e){var t=new B(e);return Ye(t),t},je=function(e,t,r){var a="";switch(e){case"amsrm":a="AMS";break;case"textrm":a="Main";break;case"textsf":a="SansSerif";break;case"texttt":a="Typewriter";break;default:a=e}return a+"-"+("textbf"===t&&"textit"===r?"BoldItalic":"textbf"===t?"Bold":"textit"===t?"Italic":"Regular")},$e={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathnormal:{variant:"italic",fontName:"Math-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},Ze={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},Ke={fontMap:$e,makeSymbol:Ge,mathsym:function(e,t,r,a){return void 0===a&&(a=[]),"boldsymbol"===r.font&&Fe(e,"Main-Bold",t).metrics?Ge(e,"Main-Bold",t,r,a.concat(["mathbf"])):"\\"===e||"main"===ne[t][e].font?Ge(e,"Main-Regular",t,r,a):Ge(e,"AMS-Regular",t,r,a.concat(["amsrm"]))},makeSpan:Xe,makeSvgSpan:We,makeLineSpan:function(e,t,r){var a=Xe([e],[],t);return a.height=Math.max(r||t.fontMetrics().defaultRuleThickness,t.minRuleThickness),a.style.borderBottomWidth=G(a.height),a.maxFontSize=1,a},makeAnchor:function(e,t,r,a){var n=new j(e,t,r,a);return Ye(n),n},makeFragment:_e,wrapFragment:function(e,t){return e instanceof B?Xe([],[e],t):e},makeVList:function(e,t){for(var{children:r,depth:a}=function(e){if("individualShift"===e.positionType){for(var t=e.children,r=[t[0]],a=-t[0].shift-t[0].elem.depth,n=a,i=1;i0)return Ge(n,h,a,t,o.concat(m));if(l){var c,p;if("boldsymbol"===l){var u=function(e,t,r,a,n){return"textord"!==n&&Fe(e,"Math-BoldItalic",t).metrics?{fontName:"Math-BoldItalic",fontClass:"boldsymbol"}:{fontName:"Main-Bold",fontClass:"mathbf"}}(n,a,0,0,r);c=u.fontName,p=[u.fontClass]}else s?(c=$e[l].fontName,p=[l]):(c=je(l,t.fontWeight,t.fontShape),p=[l,t.fontWeight,t.fontShape]);if(Fe(n,c,a).metrics)return Ge(n,c,a,t,o.concat(p));if(we.hasOwnProperty(n)&&"Typewriter"===c.slice(0,10)){for(var d=[],g=0;g{var r=Xe(["mspace"],[],t),a=F(e,t);return r.style.marginRight=G(a),r},staticSvg:function(e,t){var[r,a,n]=Ze[e],i=new Q(r),o=new J([i],{width:G(a),height:G(n),style:"width:"+G(a),viewBox:"0 0 "+1e3*a+" "+1e3*n,preserveAspectRatio:"xMinYMin"}),s=We(["overlay"],[o],t);return s.height=n,s.style.height=G(n),s.style.width=G(a),s},svgData:Ze,tryCombineChars:e=>{for(var t=0;t{var r=t.classes[0],a=e.classes[0];"mbin"===r&&m.contains(pt,a)?t.classes[0]="mord":"mbin"===a&&m.contains(ct,r)&&(e.classes[0]="mord")}),{node:c},p,u),ft(n,((e,t)=>{var r=yt(t),a=yt(e),n=r&&a?e.hasClass("mtight")?rt[r][a]:tt[r][a]:null;if(n)return Ke.makeGlue(n,l)}),{node:c},p,u),n},ft=function e(t,r,a,n,i){n&&t.push(n);for(var o=0;or=>{t.splice(e+1,0,r),o++})(o)}}n&&t.pop()},vt=function(e){return e instanceof B||e instanceof j||e instanceof _&&e.hasClass("enclosing")?e:null},bt=function e(t,r){var a=vt(t);if(a){var n=a.children;if(n.length){if("right"===r)return e(n[n.length-1],"right");if("left"===r)return e(n[0],"left")}}return t},yt=function(e,t){return e?(t&&(e=bt(e,t)),dt[e.classes[0]]||null):null},xt=function(e,t){var r=["nulldelimiter"].concat(e.baseSizingClasses());return mt(t.concat(r))},wt=function(e,t,r){if(!e)return mt();if(nt[e.type]){var a=nt[e.type](e,t);if(r&&t.size!==r.size){a=mt(t.sizingClasses(r),[a],t);var n=t.sizeMultiplier/r.sizeMultiplier;a.height*=n,a.depth*=n}return a}throw new i("Got group of unknown type: '"+e.type+"'")};function kt(e,t){var r=mt(["base"],e,t),a=mt(["strut"]);return a.style.height=G(r.height+r.depth),r.depth&&(a.style.verticalAlign=G(-r.depth)),r.children.unshift(a),r}function St(e,t){var r=null;1===e.length&&"tag"===e[0].type&&(r=e[0].tag,e=e[0].body);var a,n=gt(e,t,"root");2===n.length&&n[1].hasClass("tag")&&(a=n.pop());for(var i,o=[],s=[],l=0;l0&&(o.push(kt(s,t)),s=[]),o.push(n[l]));s.length>0&&o.push(kt(s,t)),r?((i=kt(gt(r,t,!0))).classes=["tag"],o.push(i)):a&&o.push(a);var m=mt(["katex-html"],o);if(m.setAttribute("aria-hidden","true"),i){var c=i.children[0];c.style.height=G(m.height+m.depth),m.depth&&(c.style.verticalAlign=G(-m.depth))}return m}function Mt(e){return new B(e)}class zt{constructor(e,t,r){this.type=void 0,this.attributes=void 0,this.children=void 0,this.classes=void 0,this.type=e,this.attributes={},this.children=t||[],this.classes=r||[]}setAttribute(e,t){this.attributes[e]=t}getAttribute(e){return this.attributes[e]}toNode(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);this.classes.length>0&&(e.className=U(this.classes));for(var r=0;r0&&(e+=' class ="'+m.escape(U(this.classes))+'"'),e+=">";for(var r=0;r"}toText(){return this.children.map((e=>e.toText())).join("")}}class At{constructor(e){this.text=void 0,this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return m.escape(this.toText())}toText(){return this.text}}var Tt={MathNode:zt,TextNode:At,SpaceNode:class{constructor(e){this.width=void 0,this.character=void 0,this.width=e,this.character=e>=.05555&&e<=.05556?"\u200a":e>=.1666&&e<=.1667?"\u2009":e>=.2222&&e<=.2223?"\u2005":e>=.2777&&e<=.2778?"\u2005\u200a":e>=-.05556&&e<=-.05555?"\u200a\u2063":e>=-.1667&&e<=-.1666?"\u2009\u2063":e>=-.2223&&e<=-.2222?"\u205f\u2063":e>=-.2778&&e<=-.2777?"\u2005\u2063":null}toNode(){if(this.character)return document.createTextNode(this.character);var e=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return e.setAttribute("width",G(this.width)),e}toMarkup(){return this.character?""+this.character+"":''}toText(){return this.character?this.character:" "}},newDocumentFragment:Mt},Bt=function(e,t,r){return!ne[t][e]||!ne[t][e].replace||55349===e.charCodeAt(0)||we.hasOwnProperty(e)&&r&&(r.fontFamily&&"tt"===r.fontFamily.slice(4,6)||r.font&&"tt"===r.font.slice(4,6))||(e=ne[t][e].replace),new Tt.TextNode(e)},Ct=function(e){return 1===e.length?e[0]:new Tt.MathNode("mrow",e)},Nt=function(e,t){if("texttt"===t.fontFamily)return"monospace";if("textsf"===t.fontFamily)return"textit"===t.fontShape&&"textbf"===t.fontWeight?"sans-serif-bold-italic":"textit"===t.fontShape?"sans-serif-italic":"textbf"===t.fontWeight?"bold-sans-serif":"sans-serif";if("textit"===t.fontShape&&"textbf"===t.fontWeight)return"bold-italic";if("textit"===t.fontShape)return"italic";if("textbf"===t.fontWeight)return"bold";var r=t.font;if(!r||"mathnormal"===r)return null;var a=e.mode;if("mathit"===r)return"italic";if("boldsymbol"===r)return"textord"===e.type?"bold":"bold-italic";if("mathbf"===r)return"bold";if("mathbb"===r)return"double-struck";if("mathfrak"===r)return"fraktur";if("mathscr"===r||"mathcal"===r)return"script";if("mathsf"===r)return"sans-serif";if("mathtt"===r)return"monospace";var n=e.text;return m.contains(["\\imath","\\jmath"],n)?null:(ne[a][n]&&ne[a][n].replace&&(n=ne[a][n].replace),I(n,Ke.fontMap[r].fontName,a)?Ke.fontMap[r].variant:null)},qt=function(e,t,r){if(1===e.length){var a=Rt(e[0],t);return r&&a instanceof zt&&"mo"===a.type&&(a.setAttribute("lspace","0em"),a.setAttribute("rspace","0em")),[a]}for(var n,i=[],o=0;o0&&(m.text=m.text.slice(0,1)+"\u0338"+m.text.slice(1),i.pop())}}}i.push(s),n=s}return i},It=function(e,t,r){return Ct(qt(e,t,r))},Rt=function(e,t){if(!e)return new Tt.MathNode("mrow");if(it[e.type])return it[e.type](e,t);throw new i("Got group of unknown type: '"+e.type+"'")};function Ht(e,t,r,a,n){var i,o=qt(e,r);i=1===o.length&&o[0]instanceof zt&&m.contains(["mrow","mtable"],o[0].type)?o[0]:new Tt.MathNode("mrow",o);var s=new Tt.MathNode("annotation",[new Tt.TextNode(t)]);s.setAttribute("encoding","application/x-tex");var l=new Tt.MathNode("semantics",[i,s]),h=new Tt.MathNode("math",[l]);h.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),a&&h.setAttribute("display","block");var c=n?"katex":"katex-mathml";return Ke.makeSpan([c],[h])}var Ot=function(e){return new L({style:e.displayMode?k.DISPLAY:k.TEXT,maxSize:e.maxSize,minRuleThickness:e.minRuleThickness})},Et=function(e,t){if(t.displayMode){var r=["katex-display"];t.leqno&&r.push("leqno"),t.fleqn&&r.push("fleqn"),e=Ke.makeSpan(r,[e])}return e},Lt={widehat:"^",widecheck:"\u02c7",widetilde:"~",utilde:"~",overleftarrow:"\u2190",underleftarrow:"\u2190",xleftarrow:"\u2190",overrightarrow:"\u2192",underrightarrow:"\u2192",xrightarrow:"\u2192",underbrace:"\u23df",overbrace:"\u23de",overgroup:"\u23e0",undergroup:"\u23e1",overleftrightarrow:"\u2194",underleftrightarrow:"\u2194",xleftrightarrow:"\u2194",Overrightarrow:"\u21d2",xRightarrow:"\u21d2",overleftharpoon:"\u21bc",xleftharpoonup:"\u21bc",overrightharpoon:"\u21c0",xrightharpoonup:"\u21c0",xLeftarrow:"\u21d0",xLeftrightarrow:"\u21d4",xhookleftarrow:"\u21a9",xhookrightarrow:"\u21aa",xmapsto:"\u21a6",xrightharpoondown:"\u21c1",xleftharpoondown:"\u21bd",xrightleftharpoons:"\u21cc",xleftrightharpoons:"\u21cb",xtwoheadleftarrow:"\u219e",xtwoheadrightarrow:"\u21a0",xlongequal:"=",xtofrom:"\u21c4",xrightleftarrows:"\u21c4",xrightequilibrium:"\u21cc",xleftequilibrium:"\u21cb","\\cdrightarrow":"\u2192","\\cdleftarrow":"\u2190","\\cdlongequal":"="},Dt={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],"\\cdrightarrow":[["rightarrow"],3,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],"\\cdleftarrow":[["leftarrow"],3,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],"\\cdlongequal":[["longequal"],3,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},Vt=function(e,t,r,a,n){var i,o=e.height+e.depth+r+a;if(/fbox|color|angl/.test(t)){if(i=Ke.makeSpan(["stretchy",t],[],n),"fbox"===t){var s=n.color&&n.getColor();s&&(i.style.borderColor=s)}}else{var l=[];/^[bx]cancel$/.test(t)&&l.push(new ee({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(t)&&l.push(new ee({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var h=new J(l,{width:"100%",height:G(o)});i=Ke.makeSvgSpan([],[h],n)}return i.height=o,i.style.height=G(o),i},Pt=function(e){var t=new Tt.MathNode("mo",[new Tt.TextNode(Lt[e.replace(/^\\/,"")])]);return t.setAttribute("stretchy","true"),t},Ft=function(e,t){var{span:r,minWidth:a,height:n}=function(){var r=4e5,a=e.label.slice(1);if(m.contains(["widehat","widecheck","widetilde","utilde"],a)){var n,i,o,s="ordgroup"===(d=e.base).type?d.body.length:1;if(s>5)"widehat"===a||"widecheck"===a?(n=420,r=2364,o=.42,i=a+"4"):(n=312,r=2340,o=.34,i="tilde4");else{var l=[1,1,2,2,3,3][s];"widehat"===a||"widecheck"===a?(r=[0,1062,2364,2364,2364][l],n=[0,239,300,360,420][l],o=[0,.24,.3,.3,.36,.42][l],i=a+l):(r=[0,600,1033,2339,2340][l],n=[0,260,286,306,312][l],o=[0,.26,.286,.3,.306,.34][l],i="tilde"+l)}var h=new Q(i),c=new J([h],{width:"100%",height:G(o),viewBox:"0 0 "+r+" "+n,preserveAspectRatio:"none"});return{span:Ke.makeSvgSpan([],[c],t),minWidth:0,height:o}}var p,u,d,g=[],f=Dt[a],[v,b,y]=f,x=y/1e3,w=v.length;if(1===w)p=["hide-tail"],u=[f[3]];else if(2===w)p=["halfarrow-left","halfarrow-right"],u=["xMinYMin","xMaxYMin"];else{if(3!==w)throw new Error("Correct katexImagesData or update code here to support\n "+w+" children.");p=["brace-left","brace-center","brace-right"],u=["xMinYMin","xMidYMin","xMaxYMin"]}for(var k=0;k0&&(r.style.minWidth=G(a)),r};function Gt(e,t){if(!e||e.type!==t)throw new Error("Expected node of type "+t+", but got "+(e?"node of type "+e.type:String(e)));return e}function Ut(e){var t=Yt(e);if(!t)throw new Error("Expected node of symbol group type, but got "+(e?"node of type "+e.type:String(e)));return t}function Yt(e){return e&&("atom"===e.type||ae.hasOwnProperty(e.type))?e:null}var Xt=(e,t)=>{var r,a,n;e&&"supsub"===e.type?(r=(a=Gt(e.base,"accent")).base,e.base=r,n=function(e){if(e instanceof _)return e;throw new Error("Expected span but got "+String(e)+".")}(wt(e,t)),e.base=a):r=(a=Gt(e,"accent")).base;var i=wt(r,t.havingCrampedStyle()),o=0;if(a.isShifty&&m.isCharacterBox(r)){var s=m.getBaseElem(r);o=te(wt(s,t.havingCrampedStyle())).skew}var l,h="\\c"===a.label,c=h?i.height+i.depth:Math.min(i.height,t.fontMetrics().xHeight);if(a.isStretchy)l=Ft(a,t),l=Ke.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:i},{type:"elem",elem:l,wrapperClasses:["svg-align"],wrapperStyle:o>0?{width:"calc(100% - "+G(2*o)+")",marginLeft:G(2*o)}:void 0}]},t);else{var p,u;"\\vec"===a.label?(p=Ke.staticSvg("vec",t),u=Ke.svgData.vec[1]):((p=te(p=Ke.makeOrd({mode:a.mode,text:a.label},t,"textord"))).italic=0,u=p.width,h&&(c+=p.depth)),l=Ke.makeSpan(["accent-body"],[p]);var d="\\textcircled"===a.label;d&&(l.classes.push("accent-full"),c=i.height);var g=o;d||(g-=u/2),l.style.left=G(g),"\\textcircled"===a.label&&(l.style.top=".2em"),l=Ke.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:i},{type:"kern",size:-c},{type:"elem",elem:l}]},t)}var f=Ke.makeSpan(["mord","accent"],[l],t);return n?(n.children[0]=f,n.height=Math.max(f.height,n.height),n.classes[0]="mord",n):f},Wt=(e,t)=>{var r=e.isStretchy?Pt(e.label):new Tt.MathNode("mo",[Bt(e.label,e.mode)]),a=new Tt.MathNode("mover",[Rt(e.base,t),r]);return a.setAttribute("accent","true"),a},_t=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map((e=>"\\"+e)).join("|"));ot({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:(e,t)=>{var r=lt(t[0]),a=!_t.test(e.funcName),n=!a||"\\widehat"===e.funcName||"\\widetilde"===e.funcName||"\\widecheck"===e.funcName;return{type:"accent",mode:e.parser.mode,label:e.funcName,isStretchy:a,isShifty:n,base:r}},htmlBuilder:Xt,mathmlBuilder:Wt}),ot({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\c","\\r","\\H","\\v","\\textcircled"],props:{numArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["primitive"]},handler:(e,t)=>{var r=t[0],a=e.parser.mode;return"math"===a&&(e.parser.settings.reportNonstrict("mathVsTextAccents","LaTeX's accent "+e.funcName+" works only in text mode"),a="text"),{type:"accent",mode:a,label:e.funcName,isStretchy:!1,isShifty:!0,base:r}},htmlBuilder:Xt,mathmlBuilder:Wt}),ot({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],props:{numArgs:1},handler:(e,t)=>{var{parser:r,funcName:a}=e,n=t[0];return{type:"accentUnder",mode:r.mode,label:a,base:n}},htmlBuilder:(e,t)=>{var r=wt(e.base,t),a=Ft(e,t),n="\\utilde"===e.label?.12:0,i=Ke.makeVList({positionType:"top",positionData:r.height,children:[{type:"elem",elem:a,wrapperClasses:["svg-align"]},{type:"kern",size:n},{type:"elem",elem:r}]},t);return Ke.makeSpan(["mord","accentunder"],[i],t)},mathmlBuilder:(e,t)=>{var r=Pt(e.label),a=new Tt.MathNode("munder",[Rt(e.base,t),r]);return a.setAttribute("accentunder","true"),a}});var jt=e=>{var t=new Tt.MathNode("mpadded",e?[e]:[]);return t.setAttribute("width","+0.6em"),t.setAttribute("lspace","0.3em"),t};ot({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium","\\\\cdrightarrow","\\\\cdleftarrow","\\\\cdlongequal"],props:{numArgs:1,numOptionalArgs:1},handler(e,t,r){var{parser:a,funcName:n}=e;return{type:"xArrow",mode:a.mode,label:n,body:t[0],below:r[0]}},htmlBuilder(e,t){var r,a=t.style,n=t.havingStyle(a.sup()),i=Ke.wrapFragment(wt(e.body,n,t),t),o="\\x"===e.label.slice(0,2)?"x":"cd";i.classes.push(o+"-arrow-pad"),e.below&&(n=t.havingStyle(a.sub()),(r=Ke.wrapFragment(wt(e.below,n,t),t)).classes.push(o+"-arrow-pad"));var s,l=Ft(e,t),h=-t.fontMetrics().axisHeight+.5*l.height,m=-t.fontMetrics().axisHeight-.5*l.height-.111;if((i.depth>.25||"\\xleftequilibrium"===e.label)&&(m-=i.depth),r){var c=-t.fontMetrics().axisHeight+r.height+.5*l.height+.111;s=Ke.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:m},{type:"elem",elem:l,shift:h},{type:"elem",elem:r,shift:c}]},t)}else s=Ke.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:m},{type:"elem",elem:l,shift:h}]},t);return s.children[0].children[0].children[1].classes.push("svg-align"),Ke.makeSpan(["mrel","x-arrow"],[s],t)},mathmlBuilder(e,t){var r,a=Pt(e.label);if(a.setAttribute("minsize","x"===e.label.charAt(0)?"1.75em":"3.0em"),e.body){var n=jt(Rt(e.body,t));if(e.below){var i=jt(Rt(e.below,t));r=new Tt.MathNode("munderover",[a,i,n])}else r=new Tt.MathNode("mover",[a,n])}else if(e.below){var o=jt(Rt(e.below,t));r=new Tt.MathNode("munder",[a,o])}else r=jt(),r=new Tt.MathNode("mover",[a,r]);return r}});var $t=Ke.makeSpan;function Zt(e,t){var r=gt(e.body,t,!0);return $t([e.mclass],r,t)}function Kt(e,t){var r,a=qt(e.body,t);return"minner"===e.mclass?r=new Tt.MathNode("mpadded",a):"mord"===e.mclass?e.isCharacterBox?(r=a[0]).type="mi":r=new Tt.MathNode("mi",a):(e.isCharacterBox?(r=a[0]).type="mo":r=new Tt.MathNode("mo",a),"mbin"===e.mclass?(r.attributes.lspace="0.22em",r.attributes.rspace="0.22em"):"mpunct"===e.mclass?(r.attributes.lspace="0em",r.attributes.rspace="0.17em"):"mopen"===e.mclass||"mclose"===e.mclass?(r.attributes.lspace="0em",r.attributes.rspace="0em"):"minner"===e.mclass&&(r.attributes.lspace="0.0556em",r.attributes.width="+0.1111em")),r}ot({type:"mclass",names:["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],props:{numArgs:1,primitive:!0},handler(e,t){var{parser:r,funcName:a}=e,n=t[0];return{type:"mclass",mode:r.mode,mclass:"m"+a.slice(5),body:ht(n),isCharacterBox:m.isCharacterBox(n)}},htmlBuilder:Zt,mathmlBuilder:Kt});var Jt=e=>{var t="ordgroup"===e.type&&e.body.length?e.body[0]:e;return"atom"!==t.type||"bin"!==t.family&&"rel"!==t.family?"mord":"m"+t.family};ot({type:"mclass",names:["\\@binrel"],props:{numArgs:2},handler(e,t){var{parser:r}=e;return{type:"mclass",mode:r.mode,mclass:Jt(t[0]),body:ht(t[1]),isCharacterBox:m.isCharacterBox(t[1])}}}),ot({type:"mclass",names:["\\stackrel","\\overset","\\underset"],props:{numArgs:2},handler(e,t){var r,{parser:a,funcName:n}=e,i=t[1],o=t[0];r="\\stackrel"!==n?Jt(i):"mrel";var s={type:"op",mode:i.mode,limits:!0,alwaysHandleSupSub:!0,parentIsSupSub:!1,symbol:!1,suppressBaseShift:"\\stackrel"!==n,body:ht(i)},l={type:"supsub",mode:o.mode,base:s,sup:"\\underset"===n?null:o,sub:"\\underset"===n?o:null};return{type:"mclass",mode:a.mode,mclass:r,body:[l],isCharacterBox:m.isCharacterBox(l)}},htmlBuilder:Zt,mathmlBuilder:Kt}),ot({type:"pmb",names:["\\pmb"],props:{numArgs:1,allowedInText:!0},handler(e,t){var{parser:r}=e;return{type:"pmb",mode:r.mode,mclass:Jt(t[0]),body:ht(t[0])}},htmlBuilder(e,t){var r=gt(e.body,t,!0),a=Ke.makeSpan([e.mclass],r,t);return a.style.textShadow="0.02em 0.01em 0.04px",a},mathmlBuilder(e,t){var r=qt(e.body,t),a=new Tt.MathNode("mstyle",r);return a.setAttribute("style","text-shadow: 0.02em 0.01em 0.04px"),a}});var Qt={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},er=e=>"textord"===e.type&&"@"===e.text;function tr(e,t,r){var a=Qt[e];switch(a){case"\\\\cdrightarrow":case"\\\\cdleftarrow":return r.callFunction(a,[t[0]],[t[1]]);case"\\uparrow":case"\\downarrow":var n={type:"atom",text:a,mode:"math",family:"rel"},i={type:"ordgroup",mode:"math",body:[r.callFunction("\\\\cdleft",[t[0]],[]),r.callFunction("\\Big",[n],[]),r.callFunction("\\\\cdright",[t[1]],[])]};return r.callFunction("\\\\cdparent",[i],[]);case"\\\\cdlongequal":return r.callFunction("\\\\cdlongequal",[],[]);case"\\Vert":return r.callFunction("\\Big",[{type:"textord",text:"\\Vert",mode:"math"}],[]);default:return{type:"textord",text:" ",mode:"math"}}}ot({type:"cdlabel",names:["\\\\cdleft","\\\\cdright"],props:{numArgs:1},handler(e,t){var{parser:r,funcName:a}=e;return{type:"cdlabel",mode:r.mode,side:a.slice(4),label:t[0]}},htmlBuilder(e,t){var r=t.havingStyle(t.style.sup()),a=Ke.wrapFragment(wt(e.label,r,t),t);return a.classes.push("cd-label-"+e.side),a.style.bottom=G(.8-a.depth),a.height=0,a.depth=0,a},mathmlBuilder(e,t){var r=new Tt.MathNode("mrow",[Rt(e.label,t)]);return(r=new Tt.MathNode("mpadded",[r])).setAttribute("width","0"),"left"===e.side&&r.setAttribute("lspace","-1width"),r.setAttribute("voffset","0.7em"),(r=new Tt.MathNode("mstyle",[r])).setAttribute("displaystyle","false"),r.setAttribute("scriptlevel","1"),r}}),ot({type:"cdlabelparent",names:["\\\\cdparent"],props:{numArgs:1},handler(e,t){var{parser:r}=e;return{type:"cdlabelparent",mode:r.mode,fragment:t[0]}},htmlBuilder(e,t){var r=Ke.wrapFragment(wt(e.fragment,t),t);return r.classes.push("cd-vert-arrow"),r},mathmlBuilder:(e,t)=>new Tt.MathNode("mrow",[Rt(e.fragment,t)])}),ot({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler(e,t){for(var{parser:r}=e,a=Gt(t[0],"ordgroup").body,n="",o=0;o=1114111)throw new i("\\@char with invalid code point "+n);return l<=65535?s=String.fromCharCode(l):(l-=65536,s=String.fromCharCode(55296+(l>>10),56320+(1023&l))),{type:"textord",mode:r.mode,text:s}}});var rr=(e,t)=>{var r=gt(e.body,t.withColor(e.color),!1);return Ke.makeFragment(r)},ar=(e,t)=>{var r=qt(e.body,t.withColor(e.color)),a=new Tt.MathNode("mstyle",r);return a.setAttribute("mathcolor",e.color),a};ot({type:"color",names:["\\textcolor"],props:{numArgs:2,allowedInText:!0,argTypes:["color","original"]},handler(e,t){var{parser:r}=e,a=Gt(t[0],"color-token").color,n=t[1];return{type:"color",mode:r.mode,color:a,body:ht(n)}},htmlBuilder:rr,mathmlBuilder:ar}),ot({type:"color",names:["\\color"],props:{numArgs:1,allowedInText:!0,argTypes:["color"]},handler(e,t){var{parser:r,breakOnTokenText:a}=e,n=Gt(t[0],"color-token").color;r.gullet.macros.set("\\current@color",n);var i=r.parseExpression(!0,a);return{type:"color",mode:r.mode,color:n,body:i}},htmlBuilder:rr,mathmlBuilder:ar}),ot({type:"cr",names:["\\\\"],props:{numArgs:0,numOptionalArgs:0,allowedInText:!0},handler(e,t,r){var{parser:a}=e,n="["===a.gullet.future().text?a.parseSizeGroup(!0):null,i=!a.settings.displayMode||!a.settings.useStrictBehavior("newLineInDisplayMode","In LaTeX, \\\\ or \\newline does nothing in display mode");return{type:"cr",mode:a.mode,newLine:i,size:n&&Gt(n,"size").value}},htmlBuilder(e,t){var r=Ke.makeSpan(["mspace"],[],t);return e.newLine&&(r.classes.push("newline"),e.size&&(r.style.marginTop=G(F(e.size,t)))),r},mathmlBuilder(e,t){var r=new Tt.MathNode("mspace");return e.newLine&&(r.setAttribute("linebreak","newline"),e.size&&r.setAttribute("height",G(F(e.size,t)))),r}});var nr={"\\global":"\\global","\\long":"\\\\globallong","\\\\globallong":"\\\\globallong","\\def":"\\gdef","\\gdef":"\\gdef","\\edef":"\\xdef","\\xdef":"\\xdef","\\let":"\\\\globallet","\\futurelet":"\\\\globalfuture"},ir=e=>{var t=e.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(t))throw new i("Expected a control sequence",e);return t},or=(e,t,r,a)=>{var n=e.gullet.macros.get(r.text);null==n&&(r.noexpand=!0,n={tokens:[r],numArgs:0,unexpandable:!e.gullet.isExpandable(r.text)}),e.gullet.macros.set(t,n,a)};ot({type:"internal",names:["\\global","\\long","\\\\globallong"],props:{numArgs:0,allowedInText:!0},handler(e){var{parser:t,funcName:r}=e;t.consumeSpaces();var a=t.fetch();if(nr[a.text])return"\\global"!==r&&"\\\\globallong"!==r||(a.text=nr[a.text]),Gt(t.parseFunction(),"internal");throw new i("Invalid token after macro prefix",a)}}),ot({type:"internal",names:["\\def","\\gdef","\\edef","\\xdef"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(e){var{parser:t,funcName:r}=e,a=t.gullet.popToken(),n=a.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(n))throw new i("Expected a control sequence",a);for(var o,s=0,l=[[]];"{"!==t.gullet.future().text;)if("#"===(a=t.gullet.popToken()).text){if("{"===t.gullet.future().text){o=t.gullet.future(),l[s].push("{");break}if(a=t.gullet.popToken(),!/^[1-9]$/.test(a.text))throw new i('Invalid argument number "'+a.text+'"');if(parseInt(a.text)!==s+1)throw new i('Argument number "'+a.text+'" out of order');s++,l.push([])}else{if("EOF"===a.text)throw new i("Expected a macro definition");l[s].push(a.text)}var{tokens:h}=t.gullet.consumeArg();return o&&h.unshift(o),"\\edef"!==r&&"\\xdef"!==r||(h=t.gullet.expandTokens(h)).reverse(),t.gullet.macros.set(n,{tokens:h,numArgs:s,delimiters:l},r===nr[r]),{type:"internal",mode:t.mode}}}),ot({type:"internal",names:["\\let","\\\\globallet"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(e){var{parser:t,funcName:r}=e,a=ir(t.gullet.popToken());t.gullet.consumeSpaces();var n=(e=>{var t=e.gullet.popToken();return"="===t.text&&" "===(t=e.gullet.popToken()).text&&(t=e.gullet.popToken()),t})(t);return or(t,a,n,"\\\\globallet"===r),{type:"internal",mode:t.mode}}}),ot({type:"internal",names:["\\futurelet","\\\\globalfuture"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(e){var{parser:t,funcName:r}=e,a=ir(t.gullet.popToken()),n=t.gullet.popToken(),i=t.gullet.popToken();return or(t,a,i,"\\\\globalfuture"===r),t.gullet.pushToken(i),t.gullet.pushToken(n),{type:"internal",mode:t.mode}}});var sr=function(e,t,r){var a=I(ne.math[e]&&ne.math[e].replace||e,t,r);if(!a)throw new Error("Unsupported symbol "+e+" and font size "+t+".");return a},lr=function(e,t,r,a){var n=r.havingBaseStyle(t),i=Ke.makeSpan(a.concat(n.sizingClasses(r)),[e],r),o=n.sizeMultiplier/r.sizeMultiplier;return i.height*=o,i.depth*=o,i.maxFontSize=n.sizeMultiplier,i},hr=function(e,t,r){var a=t.havingBaseStyle(r),n=(1-t.sizeMultiplier/a.sizeMultiplier)*t.fontMetrics().axisHeight;e.classes.push("delimcenter"),e.style.top=G(n),e.height-=n,e.depth+=n},mr=function(e,t,r,a,n,i){var o=function(e,t,r,a){return Ke.makeSymbol(e,"Size"+t+"-Regular",r,a)}(e,t,n,a),s=lr(Ke.makeSpan(["delimsizing","size"+t],[o],a),k.TEXT,a,i);return r&&hr(s,a,k.TEXT),s},cr=function(e,t,r){var a;return a="Size1-Regular"===t?"delim-size1":"delim-size4",{type:"elem",elem:Ke.makeSpan(["delimsizinginner",a],[Ke.makeSpan([],[Ke.makeSymbol(e,t,r)])])}},pr=function(e,t,r){var a=C["Size4-Regular"][e.charCodeAt(0)]?C["Size4-Regular"][e.charCodeAt(0)][4]:C["Size1-Regular"][e.charCodeAt(0)][4],n=new Q("inner",function(e,t){switch(e){case"\u239c":return"M291 0 H417 V"+t+" H291z M291 0 H417 V"+t+" H291z";case"\u2223":return"M145 0 H188 V"+t+" H145z M145 0 H188 V"+t+" H145z";case"\u2225":return"M145 0 H188 V"+t+" H145z M145 0 H188 V"+t+" H145zM367 0 H410 V"+t+" H367z M367 0 H410 V"+t+" H367z";case"\u239f":return"M457 0 H583 V"+t+" H457z M457 0 H583 V"+t+" H457z";case"\u23a2":return"M319 0 H403 V"+t+" H319z M319 0 H403 V"+t+" H319z";case"\u23a5":return"M263 0 H347 V"+t+" H263z M263 0 H347 V"+t+" H263z";case"\u23aa":return"M384 0 H504 V"+t+" H384z M384 0 H504 V"+t+" H384z";case"\u23d0":return"M312 0 H355 V"+t+" H312z M312 0 H355 V"+t+" H312z";case"\u2016":return"M257 0 H300 V"+t+" H257z M257 0 H300 V"+t+" H257zM478 0 H521 V"+t+" H478z M478 0 H521 V"+t+" H478z";default:return""}}(e,Math.round(1e3*t))),i=new J([n],{width:G(a),height:G(t),style:"width:"+G(a),viewBox:"0 0 "+1e3*a+" "+Math.round(1e3*t),preserveAspectRatio:"xMinYMin"}),o=Ke.makeSvgSpan([],[i],r);return o.height=t,o.style.height=G(t),o.style.width=G(a),{type:"elem",elem:o}},ur={type:"kern",size:-.008},dr=["|","\\lvert","\\rvert","\\vert"],gr=["\\|","\\lVert","\\rVert","\\Vert"],fr=function(e,t,r,a,n,i){var o,s,l,h,c="",p=0;o=l=h=e,s=null;var u="Size1-Regular";"\\uparrow"===e?l=h="\u23d0":"\\Uparrow"===e?l=h="\u2016":"\\downarrow"===e?o=l="\u23d0":"\\Downarrow"===e?o=l="\u2016":"\\updownarrow"===e?(o="\\uparrow",l="\u23d0",h="\\downarrow"):"\\Updownarrow"===e?(o="\\Uparrow",l="\u2016",h="\\Downarrow"):m.contains(dr,e)?(l="\u2223",c="vert",p=333):m.contains(gr,e)?(l="\u2225",c="doublevert",p=556):"["===e||"\\lbrack"===e?(o="\u23a1",l="\u23a2",h="\u23a3",u="Size4-Regular",c="lbrack",p=667):"]"===e||"\\rbrack"===e?(o="\u23a4",l="\u23a5",h="\u23a6",u="Size4-Regular",c="rbrack",p=667):"\\lfloor"===e||"\u230a"===e?(l=o="\u23a2",h="\u23a3",u="Size4-Regular",c="lfloor",p=667):"\\lceil"===e||"\u2308"===e?(o="\u23a1",l=h="\u23a2",u="Size4-Regular",c="lceil",p=667):"\\rfloor"===e||"\u230b"===e?(l=o="\u23a5",h="\u23a6",u="Size4-Regular",c="rfloor",p=667):"\\rceil"===e||"\u2309"===e?(o="\u23a4",l=h="\u23a5",u="Size4-Regular",c="rceil",p=667):"("===e||"\\lparen"===e?(o="\u239b",l="\u239c",h="\u239d",u="Size4-Regular",c="lparen",p=875):")"===e||"\\rparen"===e?(o="\u239e",l="\u239f",h="\u23a0",u="Size4-Regular",c="rparen",p=875):"\\{"===e||"\\lbrace"===e?(o="\u23a7",s="\u23a8",h="\u23a9",l="\u23aa",u="Size4-Regular"):"\\}"===e||"\\rbrace"===e?(o="\u23ab",s="\u23ac",h="\u23ad",l="\u23aa",u="Size4-Regular"):"\\lgroup"===e||"\u27ee"===e?(o="\u23a7",h="\u23a9",l="\u23aa",u="Size4-Regular"):"\\rgroup"===e||"\u27ef"===e?(o="\u23ab",h="\u23ad",l="\u23aa",u="Size4-Regular"):"\\lmoustache"===e||"\u23b0"===e?(o="\u23a7",h="\u23ad",l="\u23aa",u="Size4-Regular"):"\\rmoustache"!==e&&"\u23b1"!==e||(o="\u23ab",h="\u23a9",l="\u23aa",u="Size4-Regular");var d=sr(o,u,n),g=d.height+d.depth,f=sr(l,u,n),v=f.height+f.depth,b=sr(h,u,n),y=b.height+b.depth,x=0,w=1;if(null!==s){var S=sr(s,u,n);x=S.height+S.depth,w=2}var M=g+y+x,z=M+Math.max(0,Math.ceil((t-M)/(w*v)))*w*v,A=a.fontMetrics().axisHeight;r&&(A*=a.sizeMultiplier);var T=z/2-A,B=[];if(c.length>0){var C=z-g-y,N=Math.round(1e3*z),q=function(e,t){switch(e){case"lbrack":return"M403 1759 V84 H666 V0 H319 V1759 v"+t+" v1759 h347 v-84\nH403z M403 1759 V0 H319 V1759 v"+t+" v1759 h84z";case"rbrack":return"M347 1759 V0 H0 V84 H263 V1759 v"+t+" v1759 H0 v84 H347z\nM347 1759 V0 H263 V1759 v"+t+" v1759 h84z";case"vert":return"M145 15 v585 v"+t+" v585 c2.667,10,9.667,15,21,15\nc10,0,16.667,-5,20,-15 v-585 v"+-t+" v-585 c-2.667,-10,-9.667,-15,-21,-15\nc-10,0,-16.667,5,-20,15z M188 15 H145 v585 v"+t+" v585 h43z";case"doublevert":return"M145 15 v585 v"+t+" v585 c2.667,10,9.667,15,21,15\nc10,0,16.667,-5,20,-15 v-585 v"+-t+" v-585 c-2.667,-10,-9.667,-15,-21,-15\nc-10,0,-16.667,5,-20,15z M188 15 H145 v585 v"+t+" v585 h43z\nM367 15 v585 v"+t+" v585 c2.667,10,9.667,15,21,15\nc10,0,16.667,-5,20,-15 v-585 v"+-t+" v-585 c-2.667,-10,-9.667,-15,-21,-15\nc-10,0,-16.667,5,-20,15z M410 15 H367 v585 v"+t+" v585 h43z";case"lfloor":return"M319 602 V0 H403 V602 v"+t+" v1715 h263 v84 H319z\nMM319 602 V0 H403 V602 v"+t+" v1715 H319z";case"rfloor":return"M319 602 V0 H403 V602 v"+t+" v1799 H0 v-84 H319z\nMM319 602 V0 H403 V602 v"+t+" v1715 H319z";case"lceil":return"M403 1759 V84 H666 V0 H319 V1759 v"+t+" v602 h84z\nM403 1759 V0 H319 V1759 v"+t+" v602 h84z";case"rceil":return"M347 1759 V0 H0 V84 H263 V1759 v"+t+" v602 h84z\nM347 1759 V0 h-84 V1759 v"+t+" v602 h84z";case"lparen":return"M863,9c0,-2,-2,-5,-6,-9c0,0,-17,0,-17,0c-12.7,0,-19.3,0.3,-20,1\nc-5.3,5.3,-10.3,11,-15,17c-242.7,294.7,-395.3,682,-458,1162c-21.3,163.3,-33.3,349,\n-36,557 l0,"+(t+84)+"c0.2,6,0,26,0,60c2,159.3,10,310.7,24,454c53.3,528,210,\n949.7,470,1265c4.7,6,9.7,11.7,15,17c0.7,0.7,7,1,19,1c0,0,18,0,18,0c4,-4,6,-7,6,-9\nc0,-2.7,-3.3,-8.7,-10,-18c-135.3,-192.7,-235.5,-414.3,-300.5,-665c-65,-250.7,-102.5,\n-544.7,-112.5,-882c-2,-104,-3,-167,-3,-189\nl0,-"+(t+92)+"c0,-162.7,5.7,-314,17,-454c20.7,-272,63.7,-513,129,-723c65.3,\n-210,155.3,-396.3,270,-559c6.7,-9.3,10,-15.3,10,-18z";case"rparen":return"M76,0c-16.7,0,-25,3,-25,9c0,2,2,6.3,6,13c21.3,28.7,42.3,60.3,\n63,95c96.7,156.7,172.8,332.5,228.5,527.5c55.7,195,92.8,416.5,111.5,664.5\nc11.3,139.3,17,290.7,17,454c0,28,1.7,43,3.3,45l0,"+(t+9)+"\nc-3,4,-3.3,16.7,-3.3,38c0,162,-5.7,313.7,-17,455c-18.7,248,-55.8,469.3,-111.5,664\nc-55.7,194.7,-131.8,370.3,-228.5,527c-20.7,34.7,-41.7,66.3,-63,95c-2,3.3,-4,7,-6,11\nc0,7.3,5.7,11,17,11c0,0,11,0,11,0c9.3,0,14.3,-0.3,15,-1c5.3,-5.3,10.3,-11,15,-17\nc242.7,-294.7,395.3,-681.7,458,-1161c21.3,-164.7,33.3,-350.7,36,-558\nl0,-"+(t+144)+"c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7,\n-470,-1265c-4.7,-6,-9.7,-11.7,-15,-17c-0.7,-0.7,-6.7,-1,-18,-1z";default:throw new Error("Unknown stretchy delimiter.")}}(c,Math.round(1e3*C)),I=new Q(c,q),R=(p/1e3).toFixed(3)+"em",H=(N/1e3).toFixed(3)+"em",O=new J([I],{width:R,height:H,viewBox:"0 0 "+p+" "+N}),E=Ke.makeSvgSpan([],[O],a);E.height=N/1e3,E.style.width=R,E.style.height=H,B.push({type:"elem",elem:E})}else{if(B.push(cr(h,u,n)),B.push(ur),null===s){var L=z-g-y+.016;B.push(pr(l,L,a))}else{var D=(z-g-y-x)/2+.016;B.push(pr(l,D,a)),B.push(ur),B.push(cr(s,u,n)),B.push(ur),B.push(pr(l,D,a))}B.push(ur),B.push(cr(o,u,n))}var V=a.havingBaseStyle(k.TEXT),P=Ke.makeVList({positionType:"bottom",positionData:T,children:B},V);return lr(Ke.makeSpan(["delimsizing","mult"],[P],V),k.TEXT,a,i)},vr=.08,br=function(e,t,r,a,n){var i=function(e,t,r){t*=1e3;var a="";switch(e){case"sqrtMain":a=function(e,t){return"M95,"+(622+e+t)+"\nc-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14\nc0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54\nc44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10\ns173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429\nc69,-144,104.5,-217.7,106.5,-221\nl"+e/2.075+" -"+e+"\nc5.3,-9.3,12,-14,20,-14\nH400000v"+(40+e)+"H845.2724\ns-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7\nc-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z\nM"+(834+e)+" "+t+"h400000v"+(40+e)+"h-400000z"}(t,A);break;case"sqrtSize1":a=function(e,t){return"M263,"+(601+e+t)+"c0.7,0,18,39.7,52,119\nc34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120\nc340,-704.7,510.7,-1060.3,512,-1067\nl"+e/2.084+" -"+e+"\nc4.7,-7.3,11,-11,19,-11\nH40000v"+(40+e)+"H1012.3\ns-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232\nc-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1\ns-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26\nc-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z\nM"+(1001+e)+" "+t+"h400000v"+(40+e)+"h-400000z"}(t,A);break;case"sqrtSize2":a=function(e,t){return"M983 "+(10+e+t)+"\nl"+e/3.13+" -"+e+"\nc4,-6.7,10,-10,18,-10 H400000v"+(40+e)+"\nH1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7\ns-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744\nc-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30\nc26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722\nc56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5\nc53.7,-170.3,84.5,-266.8,92.5,-289.5z\nM"+(1001+e)+" "+t+"h400000v"+(40+e)+"h-400000z"}(t,A);break;case"sqrtSize3":a=function(e,t){return"M424,"+(2398+e+t)+"\nc-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514\nc0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20\ns-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121\ns209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081\nl"+e/4.223+" -"+e+"c4,-6.7,10,-10,18,-10 H400000\nv"+(40+e)+"H1014.6\ns-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185\nc-2,6,-10,9,-24,9\nc-8,0,-12,-0.7,-12,-2z M"+(1001+e)+" "+t+"\nh400000v"+(40+e)+"h-400000z"}(t,A);break;case"sqrtSize4":a=function(e,t){return"M473,"+(2713+e+t)+"\nc339.3,-1799.3,509.3,-2700,510,-2702 l"+e/5.298+" -"+e+"\nc3.3,-7.3,9.3,-11,18,-11 H400000v"+(40+e)+"H1017.7\ns-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9\nc-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200\nc0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26\ns76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,\n606zM"+(1001+e)+" "+t+"h400000v"+(40+e)+"H1017.7z"}(t,A);break;case"sqrtTall":a=function(e,t,r){return"M702 "+(e+t)+"H400000"+(40+e)+"\nH742v"+(r-54-t-e)+"l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1\nh-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170\nc-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667\n219 661 l218 661zM702 "+t+"H400000v"+(40+e)+"H742z"}(t,A,r)}return a}(e,a,r),o=new Q(e,i),s=new J([o],{width:"400em",height:G(t),viewBox:"0 0 400000 "+r,preserveAspectRatio:"xMinYMin slice"});return Ke.makeSvgSpan(["hide-tail"],[s],n)},yr=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\u230a","\u230b","\\lceil","\\rceil","\u2308","\u2309","\\surd"],xr=["\\uparrow","\\downarrow","\\updownarrow","\\Uparrow","\\Downarrow","\\Updownarrow","|","\\|","\\vert","\\Vert","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\u27ee","\u27ef","\\lmoustache","\\rmoustache","\u23b0","\u23b1"],wr=["<",">","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"],kr=[0,1.2,1.8,2.4,3],Sr=[{type:"small",style:k.SCRIPTSCRIPT},{type:"small",style:k.SCRIPT},{type:"small",style:k.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],Mr=[{type:"small",style:k.SCRIPTSCRIPT},{type:"small",style:k.SCRIPT},{type:"small",style:k.TEXT},{type:"stack"}],zr=[{type:"small",style:k.SCRIPTSCRIPT},{type:"small",style:k.SCRIPT},{type:"small",style:k.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],Ar=function(e){if("small"===e.type)return"Main-Regular";if("large"===e.type)return"Size"+e.size+"-Regular";if("stack"===e.type)return"Size4-Regular";throw new Error("Add support for delim type '"+e.type+"' here.")},Tr=function(e,t,r,a){for(var n=Math.min(2,3-a.style.size);nt)return r[n]}return r[r.length-1]},Br=function(e,t,r,a,n,i){var o;"<"===e||"\\lt"===e||"\u27e8"===e?e="\\langle":">"!==e&&"\\gt"!==e&&"\u27e9"!==e||(e="\\rangle"),o=m.contains(wr,e)?Sr:m.contains(yr,e)?zr:Mr;var s=Tr(e,t,o,a);return"small"===s.type?function(e,t,r,a,n,i){var o=Ke.makeSymbol(e,"Main-Regular",n,a),s=lr(o,t,a,i);return r&&hr(s,a,t),s}(e,s.style,r,a,n,i):"large"===s.type?mr(e,s.size,r,a,n,i):fr(e,t,r,a,n,i)},Cr={sqrtImage:function(e,t){var r,a,n=t.havingBaseSizing(),i=Tr("\\surd",e*n.sizeMultiplier,zr,n),o=n.sizeMultiplier,s=Math.max(0,t.minRuleThickness-t.fontMetrics().sqrtRuleThickness),l=0,h=0,m=0;return"small"===i.type?(e<1?o=1:e<1.4&&(o=.7),h=(1+s)/o,(r=br("sqrtMain",l=(1+s+vr)/o,m=1e3+1e3*s+80,s,t)).style.minWidth="0.853em",a=.833/o):"large"===i.type?(m=1080*kr[i.size],h=(kr[i.size]+s)/o,l=(kr[i.size]+s+vr)/o,(r=br("sqrtSize"+i.size,l,m,s,t)).style.minWidth="1.02em",a=1/o):(l=e+s+vr,h=e+s,m=Math.floor(1e3*e+s)+80,(r=br("sqrtTall",l,m,s,t)).style.minWidth="0.742em",a=1.056),r.height=h,r.style.height=G(l),{span:r,advanceWidth:a,ruleWidth:(t.fontMetrics().sqrtRuleThickness+s)*o}},sizedDelim:function(e,t,r,a,n){if("<"===e||"\\lt"===e||"\u27e8"===e?e="\\langle":">"!==e&&"\\gt"!==e&&"\u27e9"!==e||(e="\\rangle"),m.contains(yr,e)||m.contains(wr,e))return mr(e,t,!1,r,a,n);if(m.contains(xr,e))return fr(e,kr[t],!1,r,a,n);throw new i("Illegal delimiter: '"+e+"'")},sizeToMaxHeight:kr,customSizedDelim:Br,leftRightDelim:function(e,t,r,a,n,i){var o=a.fontMetrics().axisHeight*a.sizeMultiplier,s=5/a.fontMetrics().ptPerEm,l=Math.max(t-o,r+o),h=Math.max(l/500*901,2*l-s);return Br(e,h,!0,a,n,i)}},Nr={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},qr=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\u230a","\u230b","\\lceil","\\rceil","\u2308","\u2309","<",">","\\langle","\u27e8","\\rangle","\u27e9","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\u27ee","\u27ef","\\lmoustache","\\rmoustache","\u23b0","\u23b1","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];function Ir(e,t){var r=Yt(e);if(r&&m.contains(qr,r.text))return r;throw new i(r?"Invalid delimiter '"+r.text+"' after '"+t.funcName+"'":"Invalid delimiter type '"+e.type+"'",e)}function Rr(e){if(!e.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}ot({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1,argTypes:["primitive"]},handler:(e,t)=>{var r=Ir(t[0],e);return{type:"delimsizing",mode:e.parser.mode,size:Nr[e.funcName].size,mclass:Nr[e.funcName].mclass,delim:r.text}},htmlBuilder:(e,t)=>"."===e.delim?Ke.makeSpan([e.mclass]):Cr.sizedDelim(e.delim,e.size,t,e.mode,[e.mclass]),mathmlBuilder:e=>{var t=[];"."!==e.delim&&t.push(Bt(e.delim,e.mode));var r=new Tt.MathNode("mo",t);"mopen"===e.mclass||"mclose"===e.mclass?r.setAttribute("fence","true"):r.setAttribute("fence","false"),r.setAttribute("stretchy","true");var a=G(Cr.sizeToMaxHeight[e.size]);return r.setAttribute("minsize",a),r.setAttribute("maxsize",a),r}}),ot({type:"leftright-right",names:["\\right"],props:{numArgs:1,primitive:!0},handler:(e,t)=>{var r=e.parser.gullet.macros.get("\\current@color");if(r&&"string"!=typeof r)throw new i("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:e.parser.mode,delim:Ir(t[0],e).text,color:r}}}),ot({type:"leftright",names:["\\left"],props:{numArgs:1,primitive:!0},handler:(e,t)=>{var r=Ir(t[0],e),a=e.parser;++a.leftrightDepth;var n=a.parseExpression(!1);--a.leftrightDepth,a.expect("\\right",!1);var i=Gt(a.parseFunction(),"leftright-right");return{type:"leftright",mode:a.mode,body:n,left:r.text,right:i.delim,rightColor:i.color}},htmlBuilder:(e,t)=>{Rr(e);for(var r,a,n=gt(e.body,t,!0,["mopen","mclose"]),i=0,o=0,s=!1,l=0;l{Rr(e);var r=qt(e.body,t);if("."!==e.left){var a=new Tt.MathNode("mo",[Bt(e.left,e.mode)]);a.setAttribute("fence","true"),r.unshift(a)}if("."!==e.right){var n=new Tt.MathNode("mo",[Bt(e.right,e.mode)]);n.setAttribute("fence","true"),e.rightColor&&n.setAttribute("mathcolor",e.rightColor),r.push(n)}return Ct(r)}}),ot({type:"middle",names:["\\middle"],props:{numArgs:1,primitive:!0},handler:(e,t)=>{var r=Ir(t[0],e);if(!e.parser.leftrightDepth)throw new i("\\middle without preceding \\left",r);return{type:"middle",mode:e.parser.mode,delim:r.text}},htmlBuilder:(e,t)=>{var r;if("."===e.delim)r=xt(t,[]);else{r=Cr.sizedDelim(e.delim,1,t,e.mode,[]);var a={delim:e.delim,options:t};r.isMiddle=a}return r},mathmlBuilder:(e,t)=>{var r="\\vert"===e.delim||"|"===e.delim?Bt("|","text"):Bt(e.delim,e.mode),a=new Tt.MathNode("mo",[r]);return a.setAttribute("fence","true"),a.setAttribute("lspace","0.05em"),a.setAttribute("rspace","0.05em"),a}});var Hr=(e,t)=>{var r,a,n,i=Ke.wrapFragment(wt(e.body,t),t),o=e.label.slice(1),s=t.sizeMultiplier,l=0,h=m.isCharacterBox(e.body);if("sout"===o)(r=Ke.makeSpan(["stretchy","sout"])).height=t.fontMetrics().defaultRuleThickness/s,l=-.5*t.fontMetrics().xHeight;else if("phase"===o){var c=F({number:.6,unit:"pt"},t),p=F({number:.35,unit:"ex"},t);s/=t.havingBaseSizing().sizeMultiplier;var u=i.height+i.depth+c+p;i.style.paddingLeft=G(u/2+c);var d=Math.floor(1e3*u*s),g="M400000 "+(a=d)+" H0 L"+a/2+" 0 l65 45 L145 "+(a-80)+" H400000z",f=new J([new Q("phase",g)],{width:"400em",height:G(d/1e3),viewBox:"0 0 400000 "+d,preserveAspectRatio:"xMinYMin slice"});(r=Ke.makeSvgSpan(["hide-tail"],[f],t)).style.height=G(u),l=i.depth+c+p}else{/cancel/.test(o)?h||i.classes.push("cancel-pad"):"angl"===o?i.classes.push("anglpad"):i.classes.push("boxpad");var v=0,b=0,y=0;/box/.test(o)?(y=Math.max(t.fontMetrics().fboxrule,t.minRuleThickness),b=v=t.fontMetrics().fboxsep+("colorbox"===o?0:y)):"angl"===o?(v=4*(y=Math.max(t.fontMetrics().defaultRuleThickness,t.minRuleThickness)),b=Math.max(0,.25-i.depth)):b=v=h?.2:0,r=Vt(i,o,v,b,t),/fbox|boxed|fcolorbox/.test(o)?(r.style.borderStyle="solid",r.style.borderWidth=G(y)):"angl"===o&&.049!==y&&(r.style.borderTopWidth=G(y),r.style.borderRightWidth=G(y)),l=i.depth+b,e.backgroundColor&&(r.style.backgroundColor=e.backgroundColor,e.borderColor&&(r.style.borderColor=e.borderColor))}if(e.backgroundColor)n=Ke.makeVList({positionType:"individualShift",children:[{type:"elem",elem:r,shift:l},{type:"elem",elem:i,shift:0}]},t);else{var x=/cancel|phase/.test(o)?["svg-align"]:[];n=Ke.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:0},{type:"elem",elem:r,shift:l,wrapperClasses:x}]},t)}return/cancel/.test(o)&&(n.height=i.height,n.depth=i.depth),/cancel/.test(o)&&!h?Ke.makeSpan(["mord","cancel-lap"],[n],t):Ke.makeSpan(["mord"],[n],t)},Or=(e,t)=>{var r=0,a=new Tt.MathNode(e.label.indexOf("colorbox")>-1?"mpadded":"menclose",[Rt(e.body,t)]);switch(e.label){case"\\cancel":a.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":a.setAttribute("notation","downdiagonalstrike");break;case"\\phase":a.setAttribute("notation","phasorangle");break;case"\\sout":a.setAttribute("notation","horizontalstrike");break;case"\\fbox":a.setAttribute("notation","box");break;case"\\angl":a.setAttribute("notation","actuarial");break;case"\\fcolorbox":case"\\colorbox":if(r=t.fontMetrics().fboxsep*t.fontMetrics().ptPerEm,a.setAttribute("width","+"+2*r+"pt"),a.setAttribute("height","+"+2*r+"pt"),a.setAttribute("lspace",r+"pt"),a.setAttribute("voffset",r+"pt"),"\\fcolorbox"===e.label){var n=Math.max(t.fontMetrics().fboxrule,t.minRuleThickness);a.setAttribute("style","border: "+n+"em solid "+String(e.borderColor))}break;case"\\xcancel":a.setAttribute("notation","updiagonalstrike downdiagonalstrike")}return e.backgroundColor&&a.setAttribute("mathbackground",e.backgroundColor),a};ot({type:"enclose",names:["\\colorbox"],props:{numArgs:2,allowedInText:!0,argTypes:["color","text"]},handler(e,t,r){var{parser:a,funcName:n}=e,i=Gt(t[0],"color-token").color,o=t[1];return{type:"enclose",mode:a.mode,label:n,backgroundColor:i,body:o}},htmlBuilder:Hr,mathmlBuilder:Or}),ot({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,allowedInText:!0,argTypes:["color","color","text"]},handler(e,t,r){var{parser:a,funcName:n}=e,i=Gt(t[0],"color-token").color,o=Gt(t[1],"color-token").color,s=t[2];return{type:"enclose",mode:a.mode,label:n,backgroundColor:o,borderColor:i,body:s}},htmlBuilder:Hr,mathmlBuilder:Or}),ot({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler(e,t){var{parser:r}=e;return{type:"enclose",mode:r.mode,label:"\\fbox",body:t[0]}}}),ot({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\sout","\\phase"],props:{numArgs:1},handler(e,t){var{parser:r,funcName:a}=e,n=t[0];return{type:"enclose",mode:r.mode,label:a,body:n}},htmlBuilder:Hr,mathmlBuilder:Or}),ot({type:"enclose",names:["\\angl"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!1},handler(e,t){var{parser:r}=e;return{type:"enclose",mode:r.mode,label:"\\angl",body:t[0]}}});var Er={};function Lr(e){for(var{type:t,names:r,props:a,handler:n,htmlBuilder:i,mathmlBuilder:o}=e,s={type:t,numArgs:a.numArgs||0,allowedInText:!1,numOptionalArgs:0,handler:n},l=0;l{if(!e.parser.settings.displayMode)throw new i("{"+e.envName+"} can be used only in display mode.")};function Gr(e){if(-1===e.indexOf("ed"))return-1===e.indexOf("*")}function Ur(e,t,r){var{hskipBeforeAndAfter:a,addJot:o,cols:s,arraystretch:l,colSeparationType:h,autoTag:m,singleRow:c,emptySingleRow:p,maxNumCols:u,leqno:d}=t;if(e.gullet.beginGroup(),c||e.gullet.macros.set("\\cr","\\\\\\relax"),!l){var g=e.gullet.expandMacroAsText("\\arraystretch");if(null==g)l=1;else if(!(l=parseFloat(g))||l<0)throw new i("Invalid \\arraystretch: "+g)}e.gullet.beginGroup();var f=[],v=[f],b=[],y=[],x=null!=m?[]:void 0;function w(){m&&e.gullet.macros.set("\\@eqnsw","1",!0)}function k(){x&&(e.gullet.macros.get("\\df@tag")?(x.push(e.subparse([new n("\\df@tag")])),e.gullet.macros.set("\\df@tag",void 0,!0)):x.push(Boolean(m)&&"1"===e.gullet.macros.get("\\@eqnsw")))}for(w(),y.push(Pr(e));;){var S=e.parseExpression(!1,c?"\\end":"\\\\");e.gullet.endGroup(),e.gullet.beginGroup(),S={type:"ordgroup",mode:e.mode,body:S},r&&(S={type:"styling",mode:e.mode,style:r,body:[S]}),f.push(S);var M=e.fetch().text;if("&"===M){if(u&&f.length===u){if(c||h)throw new i("Too many tab characters: &",e.nextToken);e.settings.reportNonstrict("textEnv","Too few columns specified in the {array} column argument.")}e.consume()}else{if("\\end"===M){k(),1===f.length&&"styling"===S.type&&0===S.body[0].body.length&&(v.length>1||!p)&&v.pop(),y.length0&&(y+=.25),h.push({pos:y,isDashed:e[t]})}for(x(o[0]),r=0;r0&&(M<(B+=b)&&(M=B),B=0),e.addJot&&(M+=g),z.height=S,z.depth=M,y+=S,z.pos=y,y+=M+B,l[r]=z,x(o[r+1])}var C,N,q=y/2+t.fontMetrics().axisHeight,I=e.cols||[],R=[],H=[];if(e.tags&&e.tags.some((e=>e)))for(r=0;r=s)){var W=void 0;(a>0||e.hskipBeforeAndAfter)&&0!==(W=m.deflt(V.pregap,u))&&((C=Ke.makeSpan(["arraycolsep"],[])).style.width=G(W),R.push(C));var _=[];for(r=0;r0){for(var K=Ke.makeLineSpan("hline",t,c),J=Ke.makeLineSpan("hdashline",t,c),Q=[{type:"elem",elem:l,shift:0}];h.length>0;){var ee=h.pop(),te=ee.pos-q;ee.isDashed?Q.push({type:"elem",elem:J,shift:te}):Q.push({type:"elem",elem:K,shift:te})}l=Ke.makeVList({positionType:"individualShift",children:Q},t)}if(0===H.length)return Ke.makeSpan(["mord"],[l],t);var re=Ke.makeVList({positionType:"individualShift",children:H},t);return re=Ke.makeSpan(["tag"],[re],t),Ke.makeFragment([l,re])},Wr={c:"center ",l:"left ",r:"right "},_r=function(e,t){for(var r=[],a=new Tt.MathNode("mtd",[],["mtr-glue"]),n=new Tt.MathNode("mtd",[],["mml-eqn-num"]),i=0;i0){var u=e.cols,d="",g=!1,f=0,v=u.length;"separator"===u[0].type&&(c+="top ",f=1),"separator"===u[u.length-1].type&&(c+="bottom ",v-=1);for(var b=f;b0?"left ":"",c+=S[S.length-1].length>0?"right ":"";for(var M=1;M-1?"alignat":"align",o="split"===e.envName,s=Ur(e.parser,{cols:a,addJot:!0,autoTag:o?void 0:Gr(e.envName),emptySingleRow:!0,colSeparationType:n,maxNumCols:o?2:void 0,leqno:e.parser.settings.leqno},"display"),l=0,h={type:"ordgroup",mode:e.mode,body:[]};if(t[0]&&"ordgroup"===t[0].type){for(var m="",c=0;c0&&p&&(g=1),a[u]={type:"align",align:d,pregap:g,postgap:0}}return s.colSeparationType=p?"align":"alignat",s};Lr({type:"array",names:["array","darray"],props:{numArgs:1},handler(e,t){var r=(Yt(t[0])?[t[0]]:Gt(t[0],"ordgroup").body).map((function(e){var t=Ut(e).text;if(-1!=="lcr".indexOf(t))return{type:"align",align:t};if("|"===t)return{type:"separator",separator:"|"};if(":"===t)return{type:"separator",separator:":"};throw new i("Unknown column alignment: "+t,e)})),a={cols:r,hskipBeforeAndAfter:!0,maxNumCols:r.length};return Ur(e.parser,a,Yr(e.envName))},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix","matrix*","pmatrix*","bmatrix*","Bmatrix*","vmatrix*","Vmatrix*"],props:{numArgs:0},handler(e){var t={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[e.envName.replace("*","")],r="c",a={hskipBeforeAndAfter:!1,cols:[{type:"align",align:r}]};if("*"===e.envName.charAt(e.envName.length-1)){var n=e.parser;if(n.consumeSpaces(),"["===n.fetch().text){if(n.consume(),n.consumeSpaces(),r=n.fetch().text,-1==="lcr".indexOf(r))throw new i("Expected l or c or r",n.nextToken);n.consume(),n.consumeSpaces(),n.expect("]"),n.consume(),a.cols=[{type:"align",align:r}]}}var o=Ur(e.parser,a,Yr(e.envName)),s=Math.max(0,...o.body.map((e=>e.length)));return o.cols=new Array(s).fill({type:"align",align:r}),t?{type:"leftright",mode:e.mode,body:[o],left:t[0],right:t[1],rightColor:void 0}:o},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["smallmatrix"],props:{numArgs:0},handler(e){var t=Ur(e.parser,{arraystretch:.5},"script");return t.colSeparationType="small",t},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["subarray"],props:{numArgs:1},handler(e,t){var r=(Yt(t[0])?[t[0]]:Gt(t[0],"ordgroup").body).map((function(e){var t=Ut(e).text;if(-1!=="lc".indexOf(t))return{type:"align",align:t};throw new i("Unknown column alignment: "+t,e)}));if(r.length>1)throw new i("{subarray} can contain only one column");var a={cols:r,hskipBeforeAndAfter:!1,arraystretch:.5};if((a=Ur(e.parser,a,"script")).body.length>0&&a.body[0].length>1)throw new i("{subarray} can contain only one column");return a},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler(e){var t=Ur(e.parser,{arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},Yr(e.envName));return{type:"leftright",mode:e.mode,body:[t],left:e.envName.indexOf("r")>-1?".":"\\{",right:e.envName.indexOf("r")>-1?"\\}":".",rightColor:void 0}},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:jr,htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler(e){m.contains(["gather","gather*"],e.envName)&&Fr(e);var t={cols:[{type:"align",align:"c"}],addJot:!0,colSeparationType:"gather",autoTag:Gr(e.envName),emptySingleRow:!0,leqno:e.parser.settings.leqno};return Ur(e.parser,t,"display")},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:jr,htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["equation","equation*"],props:{numArgs:0},handler(e){Fr(e);var t={autoTag:Gr(e.envName),emptySingleRow:!0,singleRow:!0,maxNumCols:1,leqno:e.parser.settings.leqno};return Ur(e.parser,t,"display")},htmlBuilder:Xr,mathmlBuilder:_r}),Lr({type:"array",names:["CD"],props:{numArgs:0},handler:e=>(Fr(e),function(e){var t=[];for(e.gullet.beginGroup(),e.gullet.macros.set("\\cr","\\\\\\relax"),e.gullet.beginGroup();;){t.push(e.parseExpression(!1,"\\\\")),e.gullet.endGroup(),e.gullet.beginGroup();var r=e.fetch().text;if("&"!==r&&"\\\\"!==r){if("\\end"===r){0===t[t.length-1].length&&t.pop();break}throw new i("Expected \\\\ or \\cr or \\end",e.nextToken)}e.consume()}for(var a,n,o=[],s=[o],l=0;l-1);else{if(!("<>AV".indexOf(p)>-1))throw new i('Expected one of "<>AV=|." after @',h[c]);for(var d=0;d<2;d++){for(var g=!0,f=c+1;f{var r=e.font,a=t.withFont(r);return wt(e.body,a)},Kr=(e,t)=>{var r=e.font,a=t.withFont(r);return Rt(e.body,a)},Jr={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak","\\bm":"\\boldsymbol"};ot({type:"font",names:["\\mathrm","\\mathit","\\mathbf","\\mathnormal","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],props:{numArgs:1,allowedInArgument:!0},handler:(e,t)=>{var{parser:r,funcName:a}=e,n=lt(t[0]),i=a;return i in Jr&&(i=Jr[i]),{type:"font",mode:r.mode,font:i.slice(1),body:n}},htmlBuilder:Zr,mathmlBuilder:Kr}),ot({type:"mclass",names:["\\boldsymbol","\\bm"],props:{numArgs:1},handler:(e,t)=>{var{parser:r}=e,a=t[0],n=m.isCharacterBox(a);return{type:"mclass",mode:r.mode,mclass:Jt(a),body:[{type:"font",mode:r.mode,font:"boldsymbol",body:a}],isCharacterBox:n}}}),ot({type:"font",names:["\\rm","\\sf","\\tt","\\bf","\\it","\\cal"],props:{numArgs:0,allowedInText:!0},handler:(e,t)=>{var{parser:r,funcName:a,breakOnTokenText:n}=e,{mode:i}=r,o=r.parseExpression(!0,n);return{type:"font",mode:i,font:"math"+a.slice(1),body:{type:"ordgroup",mode:r.mode,body:o}}},htmlBuilder:Zr,mathmlBuilder:Kr});var Qr=(e,t)=>{var r=t;return"display"===e?r=r.id>=k.SCRIPT.id?r.text():k.DISPLAY:"text"===e&&r.size===k.DISPLAY.size?r=k.TEXT:"script"===e?r=k.SCRIPT:"scriptscript"===e&&(r=k.SCRIPTSCRIPT),r},ea=(e,t)=>{var r,a=Qr(e.size,t.style),n=a.fracNum(),i=a.fracDen();r=t.havingStyle(n);var o=wt(e.numer,r,t);if(e.continued){var s=8.5/t.fontMetrics().ptPerEm,l=3.5/t.fontMetrics().ptPerEm;o.height=o.height0?3*c:7*c,d=t.fontMetrics().denom1):(m>0?(p=t.fontMetrics().num2,u=c):(p=t.fontMetrics().num3,u=3*c),d=t.fontMetrics().denom2),h){var x=t.fontMetrics().axisHeight;p-o.depth-(x+.5*m){var r=new Tt.MathNode("mfrac",[Rt(e.numer,t),Rt(e.denom,t)]);if(e.hasBarLine){if(e.barSize){var a=F(e.barSize,t);r.setAttribute("linethickness",G(a))}}else r.setAttribute("linethickness","0px");var n=Qr(e.size,t.style);if(n.size!==t.style.size){r=new Tt.MathNode("mstyle",[r]);var i=n.size===k.DISPLAY.size?"true":"false";r.setAttribute("displaystyle",i),r.setAttribute("scriptlevel","0")}if(null!=e.leftDelim||null!=e.rightDelim){var o=[];if(null!=e.leftDelim){var s=new Tt.MathNode("mo",[new Tt.TextNode(e.leftDelim.replace("\\",""))]);s.setAttribute("fence","true"),o.push(s)}if(o.push(r),null!=e.rightDelim){var l=new Tt.MathNode("mo",[new Tt.TextNode(e.rightDelim.replace("\\",""))]);l.setAttribute("fence","true"),o.push(l)}return Ct(o)}return r};ot({type:"genfrac",names:["\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac","\\\\bracefrac","\\\\brackfrac"],props:{numArgs:2,allowedInArgument:!0},handler:(e,t)=>{var r,{parser:a,funcName:n}=e,i=t[0],o=t[1],s=null,l=null,h="auto";switch(n){case"\\dfrac":case"\\frac":case"\\tfrac":r=!0;break;case"\\\\atopfrac":r=!1;break;case"\\dbinom":case"\\binom":case"\\tbinom":r=!1,s="(",l=")";break;case"\\\\bracefrac":r=!1,s="\\{",l="\\}";break;case"\\\\brackfrac":r=!1,s="[",l="]";break;default:throw new Error("Unrecognized genfrac command")}switch(n){case"\\dfrac":case"\\dbinom":h="display";break;case"\\tfrac":case"\\tbinom":h="text"}return{type:"genfrac",mode:a.mode,continued:!1,numer:i,denom:o,hasBarLine:r,leftDelim:s,rightDelim:l,size:h,barSize:null}},htmlBuilder:ea,mathmlBuilder:ta}),ot({type:"genfrac",names:["\\cfrac"],props:{numArgs:2},handler:(e,t)=>{var{parser:r,funcName:a}=e,n=t[0],i=t[1];return{type:"genfrac",mode:r.mode,continued:!0,numer:n,denom:i,hasBarLine:!0,leftDelim:null,rightDelim:null,size:"display",barSize:null}}}),ot({type:"infix",names:["\\over","\\choose","\\atop","\\brace","\\brack"],props:{numArgs:0,infix:!0},handler(e){var t,{parser:r,funcName:a,token:n}=e;switch(a){case"\\over":t="\\frac";break;case"\\choose":t="\\binom";break;case"\\atop":t="\\\\atopfrac";break;case"\\brace":t="\\\\bracefrac";break;case"\\brack":t="\\\\brackfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",mode:r.mode,replaceWith:t,token:n}}});var ra=["display","text","script","scriptscript"],aa=function(e){var t=null;return e.length>0&&(t="."===(t=e)?null:t),t};ot({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,allowedInArgument:!0,argTypes:["math","math","size","text","math","math"]},handler(e,t){var r,{parser:a}=e,n=t[4],i=t[5],o=lt(t[0]),s="atom"===o.type&&"open"===o.family?aa(o.text):null,l=lt(t[1]),h="atom"===l.type&&"close"===l.family?aa(l.text):null,m=Gt(t[2],"size"),c=null;r=!!m.isBlank||(c=m.value).number>0;var p="auto",u=t[3];if("ordgroup"===u.type){if(u.body.length>0){var d=Gt(u.body[0],"textord");p=ra[Number(d.text)]}}else u=Gt(u,"textord"),p=ra[Number(u.text)];return{type:"genfrac",mode:a.mode,numer:n,denom:i,continued:!1,hasBarLine:r,barSize:c,leftDelim:s,rightDelim:h,size:p}},htmlBuilder:ea,mathmlBuilder:ta}),ot({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler(e,t){var{parser:r,funcName:a,token:n}=e;return{type:"infix",mode:r.mode,replaceWith:"\\\\abovefrac",size:Gt(t[0],"size").value,token:n}}}),ot({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:(e,t)=>{var{parser:r,funcName:a}=e,n=t[0],i=function(e){if(!e)throw new Error("Expected non-null, but got "+String(e));return e}(Gt(t[1],"infix").size),o=t[2],s=i.number>0;return{type:"genfrac",mode:r.mode,numer:n,denom:o,continued:!1,hasBarLine:s,barSize:i,leftDelim:null,rightDelim:null,size:"auto"}},htmlBuilder:ea,mathmlBuilder:ta});var na=(e,t)=>{var r,a,n=t.style;"supsub"===e.type?(r=e.sup?wt(e.sup,t.havingStyle(n.sup()),t):wt(e.sub,t.havingStyle(n.sub()),t),a=Gt(e.base,"horizBrace")):a=Gt(e,"horizBrace");var i,o=wt(a.base,t.havingBaseStyle(k.DISPLAY)),s=Ft(a,t);if(a.isOver?(i=Ke.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:o},{type:"kern",size:.1},{type:"elem",elem:s}]},t)).children[0].children[0].children[1].classes.push("svg-align"):(i=Ke.makeVList({positionType:"bottom",positionData:o.depth+.1+s.height,children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:o}]},t)).children[0].children[0].children[0].classes.push("svg-align"),r){var l=Ke.makeSpan(["mord",a.isOver?"mover":"munder"],[i],t);i=a.isOver?Ke.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:l},{type:"kern",size:.2},{type:"elem",elem:r}]},t):Ke.makeVList({positionType:"bottom",positionData:l.depth+.2+r.height+r.depth,children:[{type:"elem",elem:r},{type:"kern",size:.2},{type:"elem",elem:l}]},t)}return Ke.makeSpan(["mord",a.isOver?"mover":"munder"],[i],t)};ot({type:"horizBrace",names:["\\overbrace","\\underbrace"],props:{numArgs:1},handler(e,t){var{parser:r,funcName:a}=e;return{type:"horizBrace",mode:r.mode,label:a,isOver:/^\\over/.test(a),base:t[0]}},htmlBuilder:na,mathmlBuilder:(e,t)=>{var r=Pt(e.label);return new Tt.MathNode(e.isOver?"mover":"munder",[Rt(e.base,t),r])}}),ot({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:(e,t)=>{var{parser:r}=e,a=t[1],n=Gt(t[0],"url").url;return r.settings.isTrusted({command:"\\href",url:n})?{type:"href",mode:r.mode,href:n,body:ht(a)}:r.formatUnsupportedCmd("\\href")},htmlBuilder:(e,t)=>{var r=gt(e.body,t,!1);return Ke.makeAnchor(e.href,[],r,t)},mathmlBuilder:(e,t)=>{var r=It(e.body,t);return r instanceof zt||(r=new zt("mrow",[r])),r.setAttribute("href",e.href),r}}),ot({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:(e,t)=>{var{parser:r}=e,a=Gt(t[0],"url").url;if(!r.settings.isTrusted({command:"\\url",url:a}))return r.formatUnsupportedCmd("\\url");for(var n=[],i=0;inew Tt.MathNode("mrow",qt(e.body,t))}),ot({type:"html",names:["\\htmlClass","\\htmlId","\\htmlStyle","\\htmlData"],props:{numArgs:2,argTypes:["raw","original"],allowedInText:!0},handler:(e,t)=>{var r,{parser:a,funcName:n,token:o}=e,s=Gt(t[0],"raw").string,l=t[1];a.settings.strict&&a.settings.reportNonstrict("htmlExtension","HTML extension is disabled on strict mode");var h={};switch(n){case"\\htmlClass":h.class=s,r={command:"\\htmlClass",class:s};break;case"\\htmlId":h.id=s,r={command:"\\htmlId",id:s};break;case"\\htmlStyle":h.style=s,r={command:"\\htmlStyle",style:s};break;case"\\htmlData":for(var m=s.split(","),c=0;c{var r=gt(e.body,t,!1),a=["enclosing"];e.attributes.class&&a.push(...e.attributes.class.trim().split(/\s+/));var n=Ke.makeSpan(a,r,t);for(var i in e.attributes)"class"!==i&&e.attributes.hasOwnProperty(i)&&n.setAttribute(i,e.attributes[i]);return n},mathmlBuilder:(e,t)=>It(e.body,t)}),ot({type:"htmlmathml",names:["\\html@mathml"],props:{numArgs:2,allowedInText:!0},handler:(e,t)=>{var{parser:r}=e;return{type:"htmlmathml",mode:r.mode,html:ht(t[0]),mathml:ht(t[1])}},htmlBuilder:(e,t)=>{var r=gt(e.html,t,!1);return Ke.makeFragment(r)},mathmlBuilder:(e,t)=>It(e.mathml,t)});var ia=function(e){if(/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(e))return{number:+e,unit:"bp"};var t=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(e);if(!t)throw new i("Invalid size: '"+e+"' in \\includegraphics");var r={number:+(t[1]+t[2]),unit:t[3]};if(!P(r))throw new i("Invalid unit: '"+r.unit+"' in \\includegraphics.");return r};ot({type:"includegraphics",names:["\\includegraphics"],props:{numArgs:1,numOptionalArgs:1,argTypes:["raw","url"],allowedInText:!1},handler:(e,t,r)=>{var{parser:a}=e,n={number:0,unit:"em"},o={number:.9,unit:"em"},s={number:0,unit:"em"},l="";if(r[0])for(var h=Gt(r[0],"raw").string.split(","),m=0;m{var r=F(e.height,t),a=0;e.totalheight.number>0&&(a=F(e.totalheight,t)-r);var n=0;e.width.number>0&&(n=F(e.width,t));var i={height:G(r+a)};n>0&&(i.width=G(n)),a>0&&(i.verticalAlign=G(-a));var o=new $(e.src,e.alt,i);return o.height=r,o.depth=a,o},mathmlBuilder:(e,t)=>{var r=new Tt.MathNode("mglyph",[]);r.setAttribute("alt",e.alt);var a=F(e.height,t),n=0;if(e.totalheight.number>0&&(n=F(e.totalheight,t)-a,r.setAttribute("valign",G(-n))),r.setAttribute("height",G(a+n)),e.width.number>0){var i=F(e.width,t);r.setAttribute("width",G(i))}return r.setAttribute("src",e.src),r}}),ot({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],primitive:!0,allowedInText:!0},handler(e,t){var{parser:r,funcName:a}=e,n=Gt(t[0],"size");if(r.settings.strict){var i="m"===a[1],o="mu"===n.value.unit;i?(o||r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" supports only mu units, not "+n.value.unit+" units"),"math"!==r.mode&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" works only in math mode")):o&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" doesn't support mu units")}return{type:"kern",mode:r.mode,dimension:n.value}},htmlBuilder:(e,t)=>Ke.makeGlue(e.dimension,t),mathmlBuilder(e,t){var r=F(e.dimension,t);return new Tt.SpaceNode(r)}}),ot({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],props:{numArgs:1,allowedInText:!0},handler:(e,t)=>{var{parser:r,funcName:a}=e,n=t[0];return{type:"lap",mode:r.mode,alignment:a.slice(5),body:n}},htmlBuilder:(e,t)=>{var r;"clap"===e.alignment?(r=Ke.makeSpan([],[wt(e.body,t)]),r=Ke.makeSpan(["inner"],[r],t)):r=Ke.makeSpan(["inner"],[wt(e.body,t)]);var a=Ke.makeSpan(["fix"],[]),n=Ke.makeSpan([e.alignment],[r,a],t),i=Ke.makeSpan(["strut"]);return i.style.height=G(n.height+n.depth),n.depth&&(i.style.verticalAlign=G(-n.depth)),n.children.unshift(i),n=Ke.makeSpan(["thinbox"],[n],t),Ke.makeSpan(["mord","vbox"],[n],t)},mathmlBuilder:(e,t)=>{var r=new Tt.MathNode("mpadded",[Rt(e.body,t)]);if("rlap"!==e.alignment){var a="llap"===e.alignment?"-1":"-0.5";r.setAttribute("lspace",a+"width")}return r.setAttribute("width","0px"),r}}),ot({type:"styling",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(e,t){var{funcName:r,parser:a}=e,n=a.mode;a.switchMode("math");var i="\\("===r?"\\)":"$",o=a.parseExpression(!1,i);return a.expect(i),a.switchMode(n),{type:"styling",mode:a.mode,style:"text",body:o}}}),ot({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(e,t){throw new i("Mismatched "+e.funcName)}});var oa=(e,t)=>{switch(t.style.size){case k.DISPLAY.size:return e.display;case k.TEXT.size:return e.text;case k.SCRIPT.size:return e.script;case k.SCRIPTSCRIPT.size:return e.scriptscript;default:return e.text}};ot({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4,primitive:!0},handler:(e,t)=>{var{parser:r}=e;return{type:"mathchoice",mode:r.mode,display:ht(t[0]),text:ht(t[1]),script:ht(t[2]),scriptscript:ht(t[3])}},htmlBuilder:(e,t)=>{var r=oa(e,t),a=gt(r,t,!1);return Ke.makeFragment(a)},mathmlBuilder:(e,t)=>{var r=oa(e,t);return It(r,t)}});var sa=(e,t,r,a,n,i,o)=>{e=Ke.makeSpan([],[e]);var s,l,h,c=r&&m.isCharacterBox(r);if(t){var p=wt(t,a.havingStyle(n.sup()),a);l={elem:p,kern:Math.max(a.fontMetrics().bigOpSpacing1,a.fontMetrics().bigOpSpacing3-p.depth)}}if(r){var u=wt(r,a.havingStyle(n.sub()),a);s={elem:u,kern:Math.max(a.fontMetrics().bigOpSpacing2,a.fontMetrics().bigOpSpacing4-u.height)}}if(l&&s){var d=a.fontMetrics().bigOpSpacing5+s.elem.height+s.elem.depth+s.kern+e.depth+o;h=Ke.makeVList({positionType:"bottom",positionData:d,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:G(-i)},{type:"kern",size:s.kern},{type:"elem",elem:e},{type:"kern",size:l.kern},{type:"elem",elem:l.elem,marginLeft:G(i)},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]},a)}else if(s){var g=e.height-o;h=Ke.makeVList({positionType:"top",positionData:g,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:G(-i)},{type:"kern",size:s.kern},{type:"elem",elem:e}]},a)}else{if(!l)return e;var f=e.depth+o;h=Ke.makeVList({positionType:"bottom",positionData:f,children:[{type:"elem",elem:e},{type:"kern",size:l.kern},{type:"elem",elem:l.elem,marginLeft:G(i)},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]},a)}var v=[h];if(s&&0!==i&&!c){var b=Ke.makeSpan(["mspace"],[],a);b.style.marginRight=G(i),v.unshift(b)}return Ke.makeSpan(["mop","op-limits"],v,a)},la=["\\smallint"],ha=(e,t)=>{var r,a,n,i=!1;"supsub"===e.type?(r=e.sup,a=e.sub,n=Gt(e.base,"op"),i=!0):n=Gt(e,"op");var o,s=t.style,l=!1;if(s.size===k.DISPLAY.size&&n.symbol&&!m.contains(la,n.name)&&(l=!0),n.symbol){var h=l?"Size2-Regular":"Size1-Regular",c="";if("\\oiint"!==n.name&&"\\oiiint"!==n.name||(c=n.name.slice(1),n.name="oiint"===c?"\\iint":"\\iiint"),o=Ke.makeSymbol(n.name,h,"math",t,["mop","op-symbol",l?"large-op":"small-op"]),c.length>0){var p=o.italic,u=Ke.staticSvg(c+"Size"+(l?"2":"1"),t);o=Ke.makeVList({positionType:"individualShift",children:[{type:"elem",elem:o,shift:0},{type:"elem",elem:u,shift:l?.08:0}]},t),n.name="\\"+c,o.classes.unshift("mop"),o.italic=p}}else if(n.body){var d=gt(n.body,t,!0);1===d.length&&d[0]instanceof K?(o=d[0]).classes[0]="mop":o=Ke.makeSpan(["mop"],d,t)}else{for(var g=[],f=1;f{var r;if(e.symbol)r=new zt("mo",[Bt(e.name,e.mode)]),m.contains(la,e.name)&&r.setAttribute("largeop","false");else if(e.body)r=new zt("mo",qt(e.body,t));else{r=new zt("mi",[new At(e.name.slice(1))]);var a=new zt("mo",[Bt("\u2061","text")]);r=e.parentIsSupSub?new zt("mrow",[r,a]):Mt([r,a])}return r},ca={"\u220f":"\\prod","\u2210":"\\coprod","\u2211":"\\sum","\u22c0":"\\bigwedge","\u22c1":"\\bigvee","\u22c2":"\\bigcap","\u22c3":"\\bigcup","\u2a00":"\\bigodot","\u2a01":"\\bigoplus","\u2a02":"\\bigotimes","\u2a04":"\\biguplus","\u2a06":"\\bigsqcup"};ot({type:"op",names:["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint","\u220f","\u2210","\u2211","\u22c0","\u22c1","\u22c2","\u22c3","\u2a00","\u2a01","\u2a02","\u2a04","\u2a06"],props:{numArgs:0},handler:(e,t)=>{var{parser:r,funcName:a}=e,n=a;return 1===n.length&&(n=ca[n]),{type:"op",mode:r.mode,limits:!0,parentIsSupSub:!1,symbol:!0,name:n}},htmlBuilder:ha,mathmlBuilder:ma}),ot({type:"op",names:["\\mathop"],props:{numArgs:1,primitive:!0},handler:(e,t)=>{var{parser:r}=e,a=t[0];return{type:"op",mode:r.mode,limits:!1,parentIsSupSub:!1,symbol:!1,body:ht(a)}},htmlBuilder:ha,mathmlBuilder:ma});var pa={"\u222b":"\\int","\u222c":"\\iint","\u222d":"\\iiint","\u222e":"\\oint","\u222f":"\\oiint","\u2230":"\\oiiint"};ot({type:"op",names:["\\arcsin","\\arccos","\\arctan","\\arctg","\\arcctg","\\arg","\\ch","\\cos","\\cosec","\\cosh","\\cot","\\cotg","\\coth","\\csc","\\ctg","\\cth","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\sh","\\tan","\\tanh","\\tg","\\th"],props:{numArgs:0},handler(e){var{parser:t,funcName:r}=e;return{type:"op",mode:t.mode,limits:!1,parentIsSupSub:!1,symbol:!1,name:r}},htmlBuilder:ha,mathmlBuilder:ma}),ot({type:"op",names:["\\det","\\gcd","\\inf","\\lim","\\max","\\min","\\Pr","\\sup"],props:{numArgs:0},handler(e){var{parser:t,funcName:r}=e;return{type:"op",mode:t.mode,limits:!0,parentIsSupSub:!1,symbol:!1,name:r}},htmlBuilder:ha,mathmlBuilder:ma}),ot({type:"op",names:["\\int","\\iint","\\iiint","\\oint","\\oiint","\\oiiint","\u222b","\u222c","\u222d","\u222e","\u222f","\u2230"],props:{numArgs:0},handler(e){var{parser:t,funcName:r}=e,a=r;return 1===a.length&&(a=pa[a]),{type:"op",mode:t.mode,limits:!1,parentIsSupSub:!1,symbol:!0,name:a}},htmlBuilder:ha,mathmlBuilder:ma});var ua=(e,t)=>{var r,a,n,i,o=!1;if("supsub"===e.type?(r=e.sup,a=e.sub,n=Gt(e.base,"operatorname"),o=!0):n=Gt(e,"operatorname"),n.body.length>0){for(var s=n.body.map((e=>{var t=e.text;return"string"==typeof t?{type:"textord",mode:e.mode,text:t}:e})),l=gt(s,t.withFont("mathrm"),!0),h=0;h{var{parser:r,funcName:a}=e,n=t[0];return{type:"operatorname",mode:r.mode,body:ht(n),alwaysHandleSupSub:"\\operatornamewithlimits"===a,limits:!1,parentIsSupSub:!1}},htmlBuilder:ua,mathmlBuilder:(e,t)=>{for(var r=qt(e.body,t.withFont("mathrm")),a=!0,n=0;ne.toText())).join("");r=[new Tt.TextNode(s)]}var l=new Tt.MathNode("mi",r);l.setAttribute("mathvariant","normal");var h=new Tt.MathNode("mo",[Bt("\u2061","text")]);return e.parentIsSupSub?new Tt.MathNode("mrow",[l,h]):Tt.newDocumentFragment([l,h])}}),Vr("\\operatorname","\\@ifstar\\operatornamewithlimits\\operatorname@"),st({type:"ordgroup",htmlBuilder:(e,t)=>e.semisimple?Ke.makeFragment(gt(e.body,t,!1)):Ke.makeSpan(["mord"],gt(e.body,t,!0),t),mathmlBuilder:(e,t)=>It(e.body,t,!0)}),ot({type:"overline",names:["\\overline"],props:{numArgs:1},handler(e,t){var{parser:r}=e,a=t[0];return{type:"overline",mode:r.mode,body:a}},htmlBuilder(e,t){var r=wt(e.body,t.havingCrampedStyle()),a=Ke.makeLineSpan("overline-line",t),n=t.fontMetrics().defaultRuleThickness,i=Ke.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r},{type:"kern",size:3*n},{type:"elem",elem:a},{type:"kern",size:n}]},t);return Ke.makeSpan(["mord","overline"],[i],t)},mathmlBuilder(e,t){var r=new Tt.MathNode("mo",[new Tt.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new Tt.MathNode("mover",[Rt(e.body,t),r]);return a.setAttribute("accent","true"),a}}),ot({type:"phantom",names:["\\phantom"],props:{numArgs:1,allowedInText:!0},handler:(e,t)=>{var{parser:r}=e,a=t[0];return{type:"phantom",mode:r.mode,body:ht(a)}},htmlBuilder:(e,t)=>{var r=gt(e.body,t.withPhantom(),!1);return Ke.makeFragment(r)},mathmlBuilder:(e,t)=>{var r=qt(e.body,t);return new Tt.MathNode("mphantom",r)}}),ot({type:"hphantom",names:["\\hphantom"],props:{numArgs:1,allowedInText:!0},handler:(e,t)=>{var{parser:r}=e,a=t[0];return{type:"hphantom",mode:r.mode,body:a}},htmlBuilder:(e,t)=>{var r=Ke.makeSpan([],[wt(e.body,t.withPhantom())]);if(r.height=0,r.depth=0,r.children)for(var a=0;a{var r=qt(ht(e.body),t),a=new Tt.MathNode("mphantom",r),n=new Tt.MathNode("mpadded",[a]);return n.setAttribute("height","0px"),n.setAttribute("depth","0px"),n}}),ot({type:"vphantom",names:["\\vphantom"],props:{numArgs:1,allowedInText:!0},handler:(e,t)=>{var{parser:r}=e,a=t[0];return{type:"vphantom",mode:r.mode,body:a}},htmlBuilder:(e,t)=>{var r=Ke.makeSpan(["inner"],[wt(e.body,t.withPhantom())]),a=Ke.makeSpan(["fix"],[]);return Ke.makeSpan(["mord","rlap"],[r,a],t)},mathmlBuilder:(e,t)=>{var r=qt(ht(e.body),t),a=new Tt.MathNode("mphantom",r),n=new Tt.MathNode("mpadded",[a]);return n.setAttribute("width","0px"),n}}),ot({type:"raisebox",names:["\\raisebox"],props:{numArgs:2,argTypes:["size","hbox"],allowedInText:!0},handler(e,t){var{parser:r}=e,a=Gt(t[0],"size").value,n=t[1];return{type:"raisebox",mode:r.mode,dy:a,body:n}},htmlBuilder(e,t){var r=wt(e.body,t),a=F(e.dy,t);return Ke.makeVList({positionType:"shift",positionData:-a,children:[{type:"elem",elem:r}]},t)},mathmlBuilder(e,t){var r=new Tt.MathNode("mpadded",[Rt(e.body,t)]),a=e.dy.number+e.dy.unit;return r.setAttribute("voffset",a),r}}),ot({type:"internal",names:["\\relax"],props:{numArgs:0,allowedInText:!0},handler(e){var{parser:t}=e;return{type:"internal",mode:t.mode}}}),ot({type:"rule",names:["\\rule"],props:{numArgs:2,numOptionalArgs:1,argTypes:["size","size","size"]},handler(e,t,r){var{parser:a}=e,n=r[0],i=Gt(t[0],"size"),o=Gt(t[1],"size");return{type:"rule",mode:a.mode,shift:n&&Gt(n,"size").value,width:i.value,height:o.value}},htmlBuilder(e,t){var r=Ke.makeSpan(["mord","rule"],[],t),a=F(e.width,t),n=F(e.height,t),i=e.shift?F(e.shift,t):0;return r.style.borderRightWidth=G(a),r.style.borderTopWidth=G(n),r.style.bottom=G(i),r.width=a,r.height=n+i,r.depth=-i,r.maxFontSize=1.125*n*t.sizeMultiplier,r},mathmlBuilder(e,t){var r=F(e.width,t),a=F(e.height,t),n=e.shift?F(e.shift,t):0,i=t.color&&t.getColor()||"black",o=new Tt.MathNode("mspace");o.setAttribute("mathbackground",i),o.setAttribute("width",G(r)),o.setAttribute("height",G(a));var s=new Tt.MathNode("mpadded",[o]);return n>=0?s.setAttribute("height",G(n)):(s.setAttribute("height",G(n)),s.setAttribute("depth",G(-n))),s.setAttribute("voffset",G(n)),s}});var ga=["\\tiny","\\sixptsize","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"];ot({type:"sizing",names:ga,props:{numArgs:0,allowedInText:!0},handler:(e,t)=>{var{breakOnTokenText:r,funcName:a,parser:n}=e,i=n.parseExpression(!1,r);return{type:"sizing",mode:n.mode,size:ga.indexOf(a)+1,body:i}},htmlBuilder:(e,t)=>{var r=t.havingSize(e.size);return da(e.body,r,t)},mathmlBuilder:(e,t)=>{var r=t.havingSize(e.size),a=qt(e.body,r),n=new Tt.MathNode("mstyle",a);return n.setAttribute("mathsize",G(r.sizeMultiplier)),n}}),ot({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:(e,t,r)=>{var{parser:a}=e,n=!1,i=!1,o=r[0]&&Gt(r[0],"ordgroup");if(o)for(var s="",l=0;l{var r=Ke.makeSpan([],[wt(e.body,t)]);if(!e.smashHeight&&!e.smashDepth)return r;if(e.smashHeight&&(r.height=0,r.children))for(var a=0;a{var r=new Tt.MathNode("mpadded",[Rt(e.body,t)]);return e.smashHeight&&r.setAttribute("height","0px"),e.smashDepth&&r.setAttribute("depth","0px"),r}}),ot({type:"sqrt",names:["\\sqrt"],props:{numArgs:1,numOptionalArgs:1},handler(e,t,r){var{parser:a}=e,n=r[0],i=t[0];return{type:"sqrt",mode:a.mode,body:i,index:n}},htmlBuilder(e,t){var r=wt(e.body,t.havingCrampedStyle());0===r.height&&(r.height=t.fontMetrics().xHeight),r=Ke.wrapFragment(r,t);var a=t.fontMetrics().defaultRuleThickness,n=a;t.style.idr.height+r.depth+i&&(i=(i+m-r.height-r.depth)/2);var c=s.height-r.height-i-l;r.style.paddingLeft=G(h);var p=Ke.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r,wrapperClasses:["svg-align"]},{type:"kern",size:-(r.height+c)},{type:"elem",elem:s},{type:"kern",size:l}]},t);if(e.index){var u=t.havingStyle(k.SCRIPTSCRIPT),d=wt(e.index,u,t),g=.6*(p.height-p.depth),f=Ke.makeVList({positionType:"shift",positionData:-g,children:[{type:"elem",elem:d}]},t),v=Ke.makeSpan(["root"],[f]);return Ke.makeSpan(["mord","sqrt"],[v,p],t)}return Ke.makeSpan(["mord","sqrt"],[p],t)},mathmlBuilder(e,t){var{body:r,index:a}=e;return a?new Tt.MathNode("mroot",[Rt(r,t),Rt(a,t)]):new Tt.MathNode("msqrt",[Rt(r,t)])}});var fa={display:k.DISPLAY,text:k.TEXT,script:k.SCRIPT,scriptscript:k.SCRIPTSCRIPT};ot({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(e,t){var{breakOnTokenText:r,funcName:a,parser:n}=e,i=n.parseExpression(!0,r),o=a.slice(1,a.length-5);return{type:"styling",mode:n.mode,style:o,body:i}},htmlBuilder(e,t){var r=fa[e.style],a=t.havingStyle(r).withFont("");return da(e.body,a,t)},mathmlBuilder(e,t){var r=fa[e.style],a=t.havingStyle(r),n=qt(e.body,a),i=new Tt.MathNode("mstyle",n),o={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]}[e.style];return i.setAttribute("scriptlevel",o[0]),i.setAttribute("displaystyle",o[1]),i}});st({type:"supsub",htmlBuilder(e,t){var r=function(e,t){var r=e.base;return r?"op"===r.type?r.limits&&(t.style.size===k.DISPLAY.size||r.alwaysHandleSupSub)?ha:null:"operatorname"===r.type?r.alwaysHandleSupSub&&(t.style.size===k.DISPLAY.size||r.limits)?ua:null:"accent"===r.type?m.isCharacterBox(r.base)?Xt:null:"horizBrace"===r.type&&!e.sub===r.isOver?na:null:null}(e,t);if(r)return r(e,t);var a,n,i,{base:o,sup:s,sub:l}=e,h=wt(o,t),c=t.fontMetrics(),p=0,u=0,d=o&&m.isCharacterBox(o);if(s){var g=t.havingStyle(t.style.sup());a=wt(s,g,t),d||(p=h.height-g.fontMetrics().supDrop*g.sizeMultiplier/t.sizeMultiplier)}if(l){var f=t.havingStyle(t.style.sub());n=wt(l,f,t),d||(u=h.depth+f.fontMetrics().subDrop*f.sizeMultiplier/t.sizeMultiplier)}i=t.style===k.DISPLAY?c.sup1:t.style.cramped?c.sup3:c.sup2;var v,b=t.sizeMultiplier,y=G(.5/c.ptPerEm/b),x=null;if(n){var w=e.base&&"op"===e.base.type&&e.base.name&&("\\oiint"===e.base.name||"\\oiiint"===e.base.name);(h instanceof K||w)&&(x=G(-h.italic))}if(a&&n){p=Math.max(p,i,a.depth+.25*c.xHeight),u=Math.max(u,c.sub2);var S=4*c.defaultRuleThickness;if(p-a.depth-(n.height-u)0&&(p+=M,u-=M)}var z=[{type:"elem",elem:n,shift:u,marginRight:y,marginLeft:x},{type:"elem",elem:a,shift:-p,marginRight:y}];v=Ke.makeVList({positionType:"individualShift",children:z},t)}else if(n){u=Math.max(u,c.sub1,n.height-.8*c.xHeight);var A=[{type:"elem",elem:n,marginLeft:x,marginRight:y}];v=Ke.makeVList({positionType:"shift",positionData:u,children:A},t)}else{if(!a)throw new Error("supsub must have either sup or sub.");p=Math.max(p,i,a.depth+.25*c.xHeight),v=Ke.makeVList({positionType:"shift",positionData:-p,children:[{type:"elem",elem:a,marginRight:y}]},t)}var T=yt(h,"right")||"mord";return Ke.makeSpan([T],[h,Ke.makeSpan(["msupsub"],[v])],t)},mathmlBuilder(e,t){var r,a=!1;e.base&&"horizBrace"===e.base.type&&!!e.sup===e.base.isOver&&(a=!0,r=e.base.isOver),!e.base||"op"!==e.base.type&&"operatorname"!==e.base.type||(e.base.parentIsSupSub=!0);var n,i=[Rt(e.base,t)];if(e.sub&&i.push(Rt(e.sub,t)),e.sup&&i.push(Rt(e.sup,t)),a)n=r?"mover":"munder";else if(e.sub)if(e.sup){var o=e.base;n=o&&"op"===o.type&&o.limits&&t.style===k.DISPLAY||o&&"operatorname"===o.type&&o.alwaysHandleSupSub&&(t.style===k.DISPLAY||o.limits)?"munderover":"msubsup"}else{var s=e.base;n=s&&"op"===s.type&&s.limits&&(t.style===k.DISPLAY||s.alwaysHandleSupSub)||s&&"operatorname"===s.type&&s.alwaysHandleSupSub&&(s.limits||t.style===k.DISPLAY)?"munder":"msub"}else{var l=e.base;n=l&&"op"===l.type&&l.limits&&(t.style===k.DISPLAY||l.alwaysHandleSupSub)||l&&"operatorname"===l.type&&l.alwaysHandleSupSub&&(l.limits||t.style===k.DISPLAY)?"mover":"msup"}return new Tt.MathNode(n,i)}}),st({type:"atom",htmlBuilder:(e,t)=>Ke.mathsym(e.text,e.mode,t,["m"+e.family]),mathmlBuilder(e,t){var r=new Tt.MathNode("mo",[Bt(e.text,e.mode)]);if("bin"===e.family){var a=Nt(e,t);"bold-italic"===a&&r.setAttribute("mathvariant",a)}else"punct"===e.family?r.setAttribute("separator","true"):"open"!==e.family&&"close"!==e.family||r.setAttribute("stretchy","false");return r}});var va={mi:"italic",mn:"normal",mtext:"normal"};st({type:"mathord",htmlBuilder:(e,t)=>Ke.makeOrd(e,t,"mathord"),mathmlBuilder(e,t){var r=new Tt.MathNode("mi",[Bt(e.text,e.mode,t)]),a=Nt(e,t)||"italic";return a!==va[r.type]&&r.setAttribute("mathvariant",a),r}}),st({type:"textord",htmlBuilder:(e,t)=>Ke.makeOrd(e,t,"textord"),mathmlBuilder(e,t){var r,a=Bt(e.text,e.mode,t),n=Nt(e,t)||"normal";return r="text"===e.mode?new Tt.MathNode("mtext",[a]):/[0-9]/.test(e.text)?new Tt.MathNode("mn",[a]):"\\prime"===e.text?new Tt.MathNode("mo",[a]):new Tt.MathNode("mi",[a]),n!==va[r.type]&&r.setAttribute("mathvariant",n),r}});var ba={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},ya={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};st({type:"spacing",htmlBuilder(e,t){if(ya.hasOwnProperty(e.text)){var r=ya[e.text].className||"";if("text"===e.mode){var a=Ke.makeOrd(e,t,"textord");return a.classes.push(r),a}return Ke.makeSpan(["mspace",r],[Ke.mathsym(e.text,e.mode,t)],t)}if(ba.hasOwnProperty(e.text))return Ke.makeSpan(["mspace",ba[e.text]],[],t);throw new i('Unknown type of space "'+e.text+'"')},mathmlBuilder(e,t){if(!ya.hasOwnProperty(e.text)){if(ba.hasOwnProperty(e.text))return new Tt.MathNode("mspace");throw new i('Unknown type of space "'+e.text+'"')}return new Tt.MathNode("mtext",[new Tt.TextNode("\xa0")])}});var xa=()=>{var e=new Tt.MathNode("mtd",[]);return e.setAttribute("width","50%"),e};st({type:"tag",mathmlBuilder(e,t){var r=new Tt.MathNode("mtable",[new Tt.MathNode("mtr",[xa(),new Tt.MathNode("mtd",[It(e.body,t)]),xa(),new Tt.MathNode("mtd",[It(e.tag,t)])])]);return r.setAttribute("width","100%"),r}});var wa={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},ka={"\\textbf":"textbf","\\textmd":"textmd"},Sa={"\\textit":"textit","\\textup":"textup"},Ma=(e,t)=>{var r=e.font;return r?wa[r]?t.withTextFontFamily(wa[r]):ka[r]?t.withTextFontWeight(ka[r]):"\\emph"===r?"textit"===t.fontShape?t.withTextFontShape("textup"):t.withTextFontShape("textit"):t.withTextFontShape(Sa[r]):t};ot({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup","\\emph"],props:{numArgs:1,argTypes:["text"],allowedInArgument:!0,allowedInText:!0},handler(e,t){var{parser:r,funcName:a}=e,n=t[0];return{type:"text",mode:r.mode,body:ht(n),font:a}},htmlBuilder(e,t){var r=Ma(e,t),a=gt(e.body,r,!0);return Ke.makeSpan(["mord","text"],a,r)},mathmlBuilder(e,t){var r=Ma(e,t);return It(e.body,r)}}),ot({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler(e,t){var{parser:r}=e;return{type:"underline",mode:r.mode,body:t[0]}},htmlBuilder(e,t){var r=wt(e.body,t),a=Ke.makeLineSpan("underline-line",t),n=t.fontMetrics().defaultRuleThickness,i=Ke.makeVList({positionType:"top",positionData:r.height,children:[{type:"kern",size:n},{type:"elem",elem:a},{type:"kern",size:3*n},{type:"elem",elem:r}]},t);return Ke.makeSpan(["mord","underline"],[i],t)},mathmlBuilder(e,t){var r=new Tt.MathNode("mo",[new Tt.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new Tt.MathNode("munder",[Rt(e.body,t),r]);return a.setAttribute("accentunder","true"),a}}),ot({type:"vcenter",names:["\\vcenter"],props:{numArgs:1,argTypes:["original"],allowedInText:!1},handler(e,t){var{parser:r}=e;return{type:"vcenter",mode:r.mode,body:t[0]}},htmlBuilder(e,t){var r=wt(e.body,t),a=t.fontMetrics().axisHeight,n=.5*(r.height-a-(r.depth+a));return Ke.makeVList({positionType:"shift",positionData:n,children:[{type:"elem",elem:r}]},t)},mathmlBuilder:(e,t)=>new Tt.MathNode("mpadded",[Rt(e.body,t)],["vcenter"])}),ot({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler(e,t,r){throw new i("\\verb ended by end of line instead of matching delimiter")},htmlBuilder(e,t){for(var r=za(e),a=[],n=t.havingStyle(t.style.text()),i=0;ie.body.replace(/ /g,e.star?"\u2423":"\xa0"),Aa=at,Ta="[ \r\n\t]",Ba="(\\\\[a-zA-Z@]+)"+Ta+"*",Ca="[\u0300-\u036f]",Na=new RegExp(Ca+"+$"),qa="("+Ta+"+)|\\\\(\n|[ \r\t]+\n?)[ \r\t]*|([!-\\[\\]-\u2027\u202a-\ud7ff\uf900-\uffff]"+Ca+"*|[\ud800-\udbff][\udc00-\udfff]"+Ca+"*|\\\\verb\\*([^]).*?\\4|\\\\verb([^*a-zA-Z]).*?\\5|"+Ba+"|\\\\[^\ud800-\udfff])";class Ia{constructor(e,t){this.input=void 0,this.settings=void 0,this.tokenRegex=void 0,this.catcodes=void 0,this.input=e,this.settings=t,this.tokenRegex=new RegExp(qa,"g"),this.catcodes={"%":14,"~":13}}setCatcode(e,t){this.catcodes[e]=t}lex(){var e=this.input,t=this.tokenRegex.lastIndex;if(t===e.length)return new n("EOF",new a(this,t,t));var r=this.tokenRegex.exec(e);if(null===r||r.index!==t)throw new i("Unexpected character: '"+e[t]+"'",new n(e[t],new a(this,t,t+1)));var o=r[6]||r[3]||(r[2]?"\\ ":" ");if(14===this.catcodes[o]){var s=e.indexOf("\n",this.tokenRegex.lastIndex);return-1===s?(this.tokenRegex.lastIndex=e.length,this.settings.reportNonstrict("commentAtEnd","% comment has no terminating newline; LaTeX would fail because of commenting the end of math mode (e.g. $)")):this.tokenRegex.lastIndex=s+1,this.lex()}return new n(o,new a(this,t,this.tokenRegex.lastIndex))}}class Ra{constructor(e,t){void 0===e&&(e={}),void 0===t&&(t={}),this.current=void 0,this.builtins=void 0,this.undefStack=void 0,this.current=t,this.builtins=e,this.undefStack=[]}beginGroup(){this.undefStack.push({})}endGroup(){if(0===this.undefStack.length)throw new i("Unbalanced namespace destruction: attempt to pop global namespace; please report this as a bug");var e=this.undefStack.pop();for(var t in e)e.hasOwnProperty(t)&&(null==e[t]?delete this.current[t]:this.current[t]=e[t])}endGroups(){for(;this.undefStack.length>0;)this.endGroup()}has(e){return this.current.hasOwnProperty(e)||this.builtins.hasOwnProperty(e)}get(e){return this.current.hasOwnProperty(e)?this.current[e]:this.builtins[e]}set(e,t,r){if(void 0===r&&(r=!1),r){for(var a=0;a0&&(this.undefStack[this.undefStack.length-1][e]=t)}else{var n=this.undefStack[this.undefStack.length-1];n&&!n.hasOwnProperty(e)&&(n[e]=this.current[e])}null==t?delete this.current[e]:this.current[e]=t}}var Ha=Dr;Vr("\\noexpand",(function(e){var t=e.popToken();return e.isExpandable(t.text)&&(t.noexpand=!0,t.treatAsRelax=!0),{tokens:[t],numArgs:0}})),Vr("\\expandafter",(function(e){var t=e.popToken();return e.expandOnce(!0),{tokens:[t],numArgs:0}})),Vr("\\@firstoftwo",(function(e){return{tokens:e.consumeArgs(2)[0],numArgs:0}})),Vr("\\@secondoftwo",(function(e){return{tokens:e.consumeArgs(2)[1],numArgs:0}})),Vr("\\@ifnextchar",(function(e){var t=e.consumeArgs(3);e.consumeSpaces();var r=e.future();return 1===t[0].length&&t[0][0].text===r.text?{tokens:t[1],numArgs:0}:{tokens:t[2],numArgs:0}})),Vr("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}"),Vr("\\TextOrMath",(function(e){var t=e.consumeArgs(2);return"text"===e.mode?{tokens:t[0],numArgs:0}:{tokens:t[1],numArgs:0}}));var Oa={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15};Vr("\\char",(function(e){var t,r=e.popToken(),a="";if("'"===r.text)t=8,r=e.popToken();else if('"'===r.text)t=16,r=e.popToken();else if("`"===r.text)if("\\"===(r=e.popToken()).text[0])a=r.text.charCodeAt(1);else{if("EOF"===r.text)throw new i("\\char` missing argument");a=r.text.charCodeAt(0)}else t=10;if(t){if(null==(a=Oa[r.text])||a>=t)throw new i("Invalid base-"+t+" digit "+r.text);for(var n;null!=(n=Oa[e.future().text])&&n{var a=e.consumeArg().tokens;if(1!==a.length)throw new i("\\newcommand's first argument must be a macro name");var n=a[0].text,o=e.isDefined(n);if(o&&!t)throw new i("\\newcommand{"+n+"} attempting to redefine "+n+"; use \\renewcommand");if(!o&&!r)throw new i("\\renewcommand{"+n+"} when command "+n+" does not yet exist; use \\newcommand");var s=0;if(1===(a=e.consumeArg().tokens).length&&"["===a[0].text){for(var l="",h=e.expandNextToken();"]"!==h.text&&"EOF"!==h.text;)l+=h.text,h=e.expandNextToken();if(!l.match(/^\s*[0-9]+\s*$/))throw new i("Invalid number of arguments: "+l);s=parseInt(l),a=e.consumeArg().tokens}return e.macros.set(n,{tokens:a,numArgs:s}),""};Vr("\\newcommand",(e=>Ea(e,!1,!0))),Vr("\\renewcommand",(e=>Ea(e,!0,!1))),Vr("\\providecommand",(e=>Ea(e,!0,!0))),Vr("\\message",(e=>{var t=e.consumeArgs(1)[0];return console.log(t.reverse().map((e=>e.text)).join("")),""})),Vr("\\errmessage",(e=>{var t=e.consumeArgs(1)[0];return console.error(t.reverse().map((e=>e.text)).join("")),""})),Vr("\\show",(e=>{var t=e.popToken(),r=t.text;return console.log(t,e.macros.get(r),Aa[r],ne.math[r],ne.text[r]),""})),Vr("\\bgroup","{"),Vr("\\egroup","}"),Vr("~","\\nobreakspace"),Vr("\\lq","`"),Vr("\\rq","'"),Vr("\\aa","\\r a"),Vr("\\AA","\\r A"),Vr("\\textcopyright","\\html@mathml{\\textcircled{c}}{\\char`\xa9}"),Vr("\\copyright","\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}"),Vr("\\textregistered","\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`\xae}"),Vr("\u212c","\\mathscr{B}"),Vr("\u2130","\\mathscr{E}"),Vr("\u2131","\\mathscr{F}"),Vr("\u210b","\\mathscr{H}"),Vr("\u2110","\\mathscr{I}"),Vr("\u2112","\\mathscr{L}"),Vr("\u2133","\\mathscr{M}"),Vr("\u211b","\\mathscr{R}"),Vr("\u212d","\\mathfrak{C}"),Vr("\u210c","\\mathfrak{H}"),Vr("\u2128","\\mathfrak{Z}"),Vr("\\Bbbk","\\Bbb{k}"),Vr("\xb7","\\cdotp"),Vr("\\llap","\\mathllap{\\textrm{#1}}"),Vr("\\rlap","\\mathrlap{\\textrm{#1}}"),Vr("\\clap","\\mathclap{\\textrm{#1}}"),Vr("\\mathstrut","\\vphantom{(}"),Vr("\\underbar","\\underline{\\text{#1}}"),Vr("\\not",'\\html@mathml{\\mathrel{\\mathrlap\\@not}}{\\char"338}'),Vr("\\neq","\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`\u2260}}"),Vr("\\ne","\\neq"),Vr("\u2260","\\neq"),Vr("\\notin","\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}{\\mathrel{\\char`\u2209}}"),Vr("\u2209","\\notin"),Vr("\u2258","\\html@mathml{\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}}{\\mathrel{\\char`\u2258}}"),Vr("\u2259","\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`\u2258}}"),Vr("\u225a","\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`\u225a}}"),Vr("\u225b","\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}{\\mathrel{\\char`\u225b}}"),Vr("\u225d","\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}{\\mathrel{\\char`\u225d}}"),Vr("\u225e","\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}{\\mathrel{\\char`\u225e}}"),Vr("\u225f","\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`\u225f}}"),Vr("\u27c2","\\perp"),Vr("\u203c","\\mathclose{!\\mkern-0.8mu!}"),Vr("\u220c","\\notni"),Vr("\u231c","\\ulcorner"),Vr("\u231d","\\urcorner"),Vr("\u231e","\\llcorner"),Vr("\u231f","\\lrcorner"),Vr("\xa9","\\copyright"),Vr("\xae","\\textregistered"),Vr("\ufe0f","\\textregistered"),Vr("\\ulcorner",'\\html@mathml{\\@ulcorner}{\\mathop{\\char"231c}}'),Vr("\\urcorner",'\\html@mathml{\\@urcorner}{\\mathop{\\char"231d}}'),Vr("\\llcorner",'\\html@mathml{\\@llcorner}{\\mathop{\\char"231e}}'),Vr("\\lrcorner",'\\html@mathml{\\@lrcorner}{\\mathop{\\char"231f}}'),Vr("\\vdots","\\mathord{\\varvdots\\rule{0pt}{15pt}}"),Vr("\u22ee","\\vdots"),Vr("\\varGamma","\\mathit{\\Gamma}"),Vr("\\varDelta","\\mathit{\\Delta}"),Vr("\\varTheta","\\mathit{\\Theta}"),Vr("\\varLambda","\\mathit{\\Lambda}"),Vr("\\varXi","\\mathit{\\Xi}"),Vr("\\varPi","\\mathit{\\Pi}"),Vr("\\varSigma","\\mathit{\\Sigma}"),Vr("\\varUpsilon","\\mathit{\\Upsilon}"),Vr("\\varPhi","\\mathit{\\Phi}"),Vr("\\varPsi","\\mathit{\\Psi}"),Vr("\\varOmega","\\mathit{\\Omega}"),Vr("\\substack","\\begin{subarray}{c}#1\\end{subarray}"),Vr("\\colon","\\nobreak\\mskip2mu\\mathpunct{}\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu\\relax"),Vr("\\boxed","\\fbox{$\\displaystyle{#1}$}"),Vr("\\iff","\\DOTSB\\;\\Longleftrightarrow\\;"),Vr("\\implies","\\DOTSB\\;\\Longrightarrow\\;"),Vr("\\impliedby","\\DOTSB\\;\\Longleftarrow\\;");var La={",":"\\dotsc","\\not":"\\dotsb","+":"\\dotsb","=":"\\dotsb","<":"\\dotsb",">":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"};Vr("\\dots",(function(e){var t="\\dotso",r=e.expandAfterFuture().text;return r in La?t=La[r]:("\\not"===r.slice(0,4)||r in ne.math&&m.contains(["bin","rel"],ne.math[r].group))&&(t="\\dotsb"),t}));var Da={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};Vr("\\dotso",(function(e){return e.future().text in Da?"\\ldots\\,":"\\ldots"})),Vr("\\dotsc",(function(e){var t=e.future().text;return t in Da&&","!==t?"\\ldots\\,":"\\ldots"})),Vr("\\cdots",(function(e){return e.future().text in Da?"\\@cdots\\,":"\\@cdots"})),Vr("\\dotsb","\\cdots"),Vr("\\dotsm","\\cdots"),Vr("\\dotsi","\\!\\cdots"),Vr("\\dotsx","\\ldots\\,"),Vr("\\DOTSI","\\relax"),Vr("\\DOTSB","\\relax"),Vr("\\DOTSX","\\relax"),Vr("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),Vr("\\,","\\tmspace+{3mu}{.1667em}"),Vr("\\thinspace","\\,"),Vr("\\>","\\mskip{4mu}"),Vr("\\:","\\tmspace+{4mu}{.2222em}"),Vr("\\medspace","\\:"),Vr("\\;","\\tmspace+{5mu}{.2777em}"),Vr("\\thickspace","\\;"),Vr("\\!","\\tmspace-{3mu}{.1667em}"),Vr("\\negthinspace","\\!"),Vr("\\negmedspace","\\tmspace-{4mu}{.2222em}"),Vr("\\negthickspace","\\tmspace-{5mu}{.277em}"),Vr("\\enspace","\\kern.5em "),Vr("\\enskip","\\hskip.5em\\relax"),Vr("\\quad","\\hskip1em\\relax"),Vr("\\qquad","\\hskip2em\\relax"),Vr("\\tag","\\@ifstar\\tag@literal\\tag@paren"),Vr("\\tag@paren","\\tag@literal{({#1})}"),Vr("\\tag@literal",(e=>{if(e.macros.get("\\df@tag"))throw new i("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"})),Vr("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"),Vr("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),Vr("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}"),Vr("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),Vr("\\newline","\\\\\\relax"),Vr("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");var Va=G(C["Main-Regular"]["T".charCodeAt(0)][1]-.7*C["Main-Regular"]["A".charCodeAt(0)][1]);Vr("\\LaTeX","\\textrm{\\html@mathml{L\\kern-.36em\\raisebox{"+Va+"}{\\scriptstyle A}\\kern-.15em\\TeX}{LaTeX}}"),Vr("\\KaTeX","\\textrm{\\html@mathml{K\\kern-.17em\\raisebox{"+Va+"}{\\scriptstyle A}\\kern-.15em\\TeX}{KaTeX}}"),Vr("\\hspace","\\@ifstar\\@hspacer\\@hspace"),Vr("\\@hspace","\\hskip #1\\relax"),Vr("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax"),Vr("\\ordinarycolon",":"),Vr("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}"),Vr("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}'),Vr("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}'),Vr("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}'),Vr("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}'),Vr("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}'),Vr("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}'),Vr("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}'),Vr("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}'),Vr("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}'),Vr("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}'),Vr("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}'),Vr("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}'),Vr("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}'),Vr("\u2237","\\dblcolon"),Vr("\u2239","\\eqcolon"),Vr("\u2254","\\coloneqq"),Vr("\u2255","\\eqqcolon"),Vr("\u2a74","\\Coloneqq"),Vr("\\ratio","\\vcentcolon"),Vr("\\coloncolon","\\dblcolon"),Vr("\\colonequals","\\coloneqq"),Vr("\\coloncolonequals","\\Coloneqq"),Vr("\\equalscolon","\\eqqcolon"),Vr("\\equalscoloncolon","\\Eqqcolon"),Vr("\\colonminus","\\coloneq"),Vr("\\coloncolonminus","\\Coloneq"),Vr("\\minuscolon","\\eqcolon"),Vr("\\minuscoloncolon","\\Eqcolon"),Vr("\\coloncolonapprox","\\Colonapprox"),Vr("\\coloncolonsim","\\Colonsim"),Vr("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),Vr("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"),Vr("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),Vr("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"),Vr("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220c}}"),Vr("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}"),Vr("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}"),Vr("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}"),Vr("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}"),Vr("\\varlimsup","\\DOTSB\\operatorname*{\\overline{lim}}"),Vr("\\varliminf","\\DOTSB\\operatorname*{\\underline{lim}}"),Vr("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{lim}}"),Vr("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{lim}}"),Vr("\\gvertneqq","\\html@mathml{\\@gvertneqq}{\u2269}"),Vr("\\lvertneqq","\\html@mathml{\\@lvertneqq}{\u2268}"),Vr("\\ngeqq","\\html@mathml{\\@ngeqq}{\u2271}"),Vr("\\ngeqslant","\\html@mathml{\\@ngeqslant}{\u2271}"),Vr("\\nleqq","\\html@mathml{\\@nleqq}{\u2270}"),Vr("\\nleqslant","\\html@mathml{\\@nleqslant}{\u2270}"),Vr("\\nshortmid","\\html@mathml{\\@nshortmid}{\u2224}"),Vr("\\nshortparallel","\\html@mathml{\\@nshortparallel}{\u2226}"),Vr("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{\u2288}"),Vr("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{\u2289}"),Vr("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{\u228a}"),Vr("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{\u2acb}"),Vr("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{\u228b}"),Vr("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{\u2acc}"),Vr("\\imath","\\html@mathml{\\@imath}{\u0131}"),Vr("\\jmath","\\html@mathml{\\@jmath}{\u0237}"),Vr("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`\u27e6}}"),Vr("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`\u27e7}}"),Vr("\u27e6","\\llbracket"),Vr("\u27e7","\\rrbracket"),Vr("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`\u2983}}"),Vr("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`\u2984}}"),Vr("\u2983","\\lBrace"),Vr("\u2984","\\rBrace"),Vr("\\minuso","\\mathbin{\\html@mathml{{\\mathrlap{\\mathchoice{\\kern{0.145em}}{\\kern{0.145em}}{\\kern{0.1015em}}{\\kern{0.0725em}}\\circ}{-}}}{\\char`\u29b5}}"),Vr("\u29b5","\\minuso"),Vr("\\darr","\\downarrow"),Vr("\\dArr","\\Downarrow"),Vr("\\Darr","\\Downarrow"),Vr("\\lang","\\langle"),Vr("\\rang","\\rangle"),Vr("\\uarr","\\uparrow"),Vr("\\uArr","\\Uparrow"),Vr("\\Uarr","\\Uparrow"),Vr("\\N","\\mathbb{N}"),Vr("\\R","\\mathbb{R}"),Vr("\\Z","\\mathbb{Z}"),Vr("\\alef","\\aleph"),Vr("\\alefsym","\\aleph"),Vr("\\Alpha","\\mathrm{A}"),Vr("\\Beta","\\mathrm{B}"),Vr("\\bull","\\bullet"),Vr("\\Chi","\\mathrm{X}"),Vr("\\clubs","\\clubsuit"),Vr("\\cnums","\\mathbb{C}"),Vr("\\Complex","\\mathbb{C}"),Vr("\\Dagger","\\ddagger"),Vr("\\diamonds","\\diamondsuit"),Vr("\\empty","\\emptyset"),Vr("\\Epsilon","\\mathrm{E}"),Vr("\\Eta","\\mathrm{H}"),Vr("\\exist","\\exists"),Vr("\\harr","\\leftrightarrow"),Vr("\\hArr","\\Leftrightarrow"),Vr("\\Harr","\\Leftrightarrow"),Vr("\\hearts","\\heartsuit"),Vr("\\image","\\Im"),Vr("\\infin","\\infty"),Vr("\\Iota","\\mathrm{I}"),Vr("\\isin","\\in"),Vr("\\Kappa","\\mathrm{K}"),Vr("\\larr","\\leftarrow"),Vr("\\lArr","\\Leftarrow"),Vr("\\Larr","\\Leftarrow"),Vr("\\lrarr","\\leftrightarrow"),Vr("\\lrArr","\\Leftrightarrow"),Vr("\\Lrarr","\\Leftrightarrow"),Vr("\\Mu","\\mathrm{M}"),Vr("\\natnums","\\mathbb{N}"),Vr("\\Nu","\\mathrm{N}"),Vr("\\Omicron","\\mathrm{O}"),Vr("\\plusmn","\\pm"),Vr("\\rarr","\\rightarrow"),Vr("\\rArr","\\Rightarrow"),Vr("\\Rarr","\\Rightarrow"),Vr("\\real","\\Re"),Vr("\\reals","\\mathbb{R}"),Vr("\\Reals","\\mathbb{R}"),Vr("\\Rho","\\mathrm{P}"),Vr("\\sdot","\\cdot"),Vr("\\sect","\\S"),Vr("\\spades","\\spadesuit"),Vr("\\sub","\\subset"),Vr("\\sube","\\subseteq"),Vr("\\supe","\\supseteq"),Vr("\\Tau","\\mathrm{T}"),Vr("\\thetasym","\\vartheta"),Vr("\\weierp","\\wp"),Vr("\\Zeta","\\mathrm{Z}"),Vr("\\argmin","\\DOTSB\\operatorname*{arg\\,min}"),Vr("\\argmax","\\DOTSB\\operatorname*{arg\\,max}"),Vr("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits"),Vr("\\bra","\\mathinner{\\langle{#1}|}"),Vr("\\ket","\\mathinner{|{#1}\\rangle}"),Vr("\\braket","\\mathinner{\\langle{#1}\\rangle}"),Vr("\\Bra","\\left\\langle#1\\right|"),Vr("\\Ket","\\left|#1\\right\\rangle");var Pa=e=>t=>{var r=t.consumeArg().tokens,a=t.consumeArg().tokens,n=t.consumeArg().tokens,i=t.consumeArg().tokens,o=t.macros.get("|"),s=t.macros.get("\\|");t.macros.beginGroup();var l=t=>r=>{e&&(r.macros.set("|",o),n.length&&r.macros.set("\\|",s));var i=t;!t&&n.length&&("|"===r.future().text&&(r.popToken(),i=!0));return{tokens:i?n:a,numArgs:0}};t.macros.set("|",l(!1)),n.length&&t.macros.set("\\|",l(!0));var h=t.consumeArg().tokens,m=t.expandTokens([...i,...h,...r]);return t.macros.endGroup(),{tokens:m.reverse(),numArgs:0}};Vr("\\bra@ket",Pa(!1)),Vr("\\bra@set",Pa(!0)),Vr("\\Braket","\\bra@ket{\\left\\langle}{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"),Vr("\\Set","\\bra@set{\\left\\{\\:}{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"),Vr("\\set","\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"),Vr("\\angln","{\\angl n}"),Vr("\\blue","\\textcolor{##6495ed}{#1}"),Vr("\\orange","\\textcolor{##ffa500}{#1}"),Vr("\\pink","\\textcolor{##ff00af}{#1}"),Vr("\\red","\\textcolor{##df0030}{#1}"),Vr("\\green","\\textcolor{##28ae7b}{#1}"),Vr("\\gray","\\textcolor{gray}{#1}"),Vr("\\purple","\\textcolor{##9d38bd}{#1}"),Vr("\\blueA","\\textcolor{##ccfaff}{#1}"),Vr("\\blueB","\\textcolor{##80f6ff}{#1}"),Vr("\\blueC","\\textcolor{##63d9ea}{#1}"),Vr("\\blueD","\\textcolor{##11accd}{#1}"),Vr("\\blueE","\\textcolor{##0c7f99}{#1}"),Vr("\\tealA","\\textcolor{##94fff5}{#1}"),Vr("\\tealB","\\textcolor{##26edd5}{#1}"),Vr("\\tealC","\\textcolor{##01d1c1}{#1}"),Vr("\\tealD","\\textcolor{##01a995}{#1}"),Vr("\\tealE","\\textcolor{##208170}{#1}"),Vr("\\greenA","\\textcolor{##b6ffb0}{#1}"),Vr("\\greenB","\\textcolor{##8af281}{#1}"),Vr("\\greenC","\\textcolor{##74cf70}{#1}"),Vr("\\greenD","\\textcolor{##1fab54}{#1}"),Vr("\\greenE","\\textcolor{##0d923f}{#1}"),Vr("\\goldA","\\textcolor{##ffd0a9}{#1}"),Vr("\\goldB","\\textcolor{##ffbb71}{#1}"),Vr("\\goldC","\\textcolor{##ff9c39}{#1}"),Vr("\\goldD","\\textcolor{##e07d10}{#1}"),Vr("\\goldE","\\textcolor{##a75a05}{#1}"),Vr("\\redA","\\textcolor{##fca9a9}{#1}"),Vr("\\redB","\\textcolor{##ff8482}{#1}"),Vr("\\redC","\\textcolor{##f9685d}{#1}"),Vr("\\redD","\\textcolor{##e84d39}{#1}"),Vr("\\redE","\\textcolor{##bc2612}{#1}"),Vr("\\maroonA","\\textcolor{##ffbde0}{#1}"),Vr("\\maroonB","\\textcolor{##ff92c6}{#1}"),Vr("\\maroonC","\\textcolor{##ed5fa6}{#1}"),Vr("\\maroonD","\\textcolor{##ca337c}{#1}"),Vr("\\maroonE","\\textcolor{##9e034e}{#1}"),Vr("\\purpleA","\\textcolor{##ddd7ff}{#1}"),Vr("\\purpleB","\\textcolor{##c6b9fc}{#1}"),Vr("\\purpleC","\\textcolor{##aa87ff}{#1}"),Vr("\\purpleD","\\textcolor{##7854ab}{#1}"),Vr("\\purpleE","\\textcolor{##543b78}{#1}"),Vr("\\mintA","\\textcolor{##f5f9e8}{#1}"),Vr("\\mintB","\\textcolor{##edf2df}{#1}"),Vr("\\mintC","\\textcolor{##e0e5cc}{#1}"),Vr("\\grayA","\\textcolor{##f6f7f7}{#1}"),Vr("\\grayB","\\textcolor{##f0f1f2}{#1}"),Vr("\\grayC","\\textcolor{##e3e5e6}{#1}"),Vr("\\grayD","\\textcolor{##d6d8da}{#1}"),Vr("\\grayE","\\textcolor{##babec2}{#1}"),Vr("\\grayF","\\textcolor{##888d93}{#1}"),Vr("\\grayG","\\textcolor{##626569}{#1}"),Vr("\\grayH","\\textcolor{##3b3e40}{#1}"),Vr("\\grayI","\\textcolor{##21242c}{#1}"),Vr("\\kaBlue","\\textcolor{##314453}{#1}"),Vr("\\kaGreen","\\textcolor{##71B307}{#1}");var Fa={"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0};class Ga{constructor(e,t,r){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=t,this.expansionCount=0,this.feed(e),this.macros=new Ra(Ha,t.macros),this.mode=r,this.stack=[]}feed(e){this.lexer=new Ia(e,this.settings)}switchMode(e){this.mode=e}beginGroup(){this.macros.beginGroup()}endGroup(){this.macros.endGroup()}endGroups(){this.macros.endGroups()}future(){return 0===this.stack.length&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]}popToken(){return this.future(),this.stack.pop()}pushToken(e){this.stack.push(e)}pushTokens(e){this.stack.push(...e)}scanArgument(e){var t,r,a;if(e){if(this.consumeSpaces(),"["!==this.future().text)return null;t=this.popToken(),({tokens:a,end:r}=this.consumeArg(["]"]))}else({tokens:a,start:t,end:r}=this.consumeArg());return this.pushToken(new n("EOF",r.loc)),this.pushTokens(a),t.range(r,"")}consumeSpaces(){for(;;){if(" "!==this.future().text)break;this.stack.pop()}}consumeArg(e){var t=[],r=e&&e.length>0;r||this.consumeSpaces();var a,n=this.future(),o=0,s=0;do{if(a=this.popToken(),t.push(a),"{"===a.text)++o;else if("}"===a.text){if(-1===--o)throw new i("Extra }",a)}else if("EOF"===a.text)throw new i("Unexpected end of input in a macro argument, expected '"+(e&&r?e[s]:"}")+"'",a);if(e&&r)if((0===o||1===o&&"{"===e[s])&&a.text===e[s]){if(++s===e.length){t.splice(-s,s);break}}else s=0}while(0!==o||r);return"{"===n.text&&"}"===t[t.length-1].text&&(t.pop(),t.shift()),t.reverse(),{tokens:t,start:n,end:a}}consumeArgs(e,t){if(t){if(t.length!==e+1)throw new i("The length of delimiters doesn't match the number of args!");for(var r=t[0],a=0;athis.settings.maxExpand)throw new i("Too many expansions: infinite loop or need to increase maxExpand setting")}expandOnce(e){var t=this.popToken(),r=t.text,a=t.noexpand?null:this._getExpansion(r);if(null==a||e&&a.unexpandable){if(e&&null==a&&"\\"===r[0]&&!this.isDefined(r))throw new i("Undefined control sequence: "+r);return this.pushToken(t),!1}this.countExpansion(1);var n=a.tokens,o=this.consumeArgs(a.numArgs,a.delimiters);if(a.numArgs)for(var s=(n=n.slice()).length-1;s>=0;--s){var l=n[s];if("#"===l.text){if(0===s)throw new i("Incomplete placeholder at end of macro body",l);if("#"===(l=n[--s]).text)n.splice(s+1,1);else{if(!/^[1-9]$/.test(l.text))throw new i("Not a valid argument number",l);n.splice(s,2,...o[+l.text-1])}}}return this.pushTokens(n),n.length}expandAfterFuture(){return this.expandOnce(),this.future()}expandNextToken(){for(;;)if(!1===this.expandOnce()){var e=this.stack.pop();return e.treatAsRelax&&(e.text="\\relax"),e}throw new Error}expandMacro(e){return this.macros.has(e)?this.expandTokens([new n(e)]):void 0}expandTokens(e){var t=[],r=this.stack.length;for(this.pushTokens(e);this.stack.length>r;)if(!1===this.expandOnce(!0)){var a=this.stack.pop();a.treatAsRelax&&(a.noexpand=!1,a.treatAsRelax=!1),t.push(a)}return this.countExpansion(t.length),t}expandMacroAsText(e){var t=this.expandMacro(e);return t?t.map((e=>e.text)).join(""):t}_getExpansion(e){var t=this.macros.get(e);if(null==t)return t;if(1===e.length){var r=this.lexer.catcodes[e];if(null!=r&&13!==r)return}var a="function"==typeof t?t(this):t;if("string"==typeof a){var n=0;if(-1!==a.indexOf("#"))for(var i=a.replace(/##/g,"");-1!==i.indexOf("#"+(n+1));)++n;for(var o=new Ia(a,this.settings),s=[],l=o.lex();"EOF"!==l.text;)s.push(l),l=o.lex();return s.reverse(),{tokens:s,numArgs:n}}return a}isDefined(e){return this.macros.has(e)||Aa.hasOwnProperty(e)||ne.math.hasOwnProperty(e)||ne.text.hasOwnProperty(e)||Fa.hasOwnProperty(e)}isExpandable(e){var t=this.macros.get(e);return null!=t?"string"==typeof t||"function"==typeof t||!t.unexpandable:Aa.hasOwnProperty(e)&&!Aa[e].primitive}}var Ua=/^[\u208a\u208b\u208c\u208d\u208e\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2090\u2091\u2095\u1d62\u2c7c\u2096\u2097\u2098\u2099\u2092\u209a\u1d63\u209b\u209c\u1d64\u1d65\u2093\u1d66\u1d67\u1d68\u1d69\u1d6a]/,Ya=Object.freeze({"\u208a":"+","\u208b":"-","\u208c":"=","\u208d":"(","\u208e":")","\u2080":"0","\u2081":"1","\u2082":"2","\u2083":"3","\u2084":"4","\u2085":"5","\u2086":"6","\u2087":"7","\u2088":"8","\u2089":"9","\u2090":"a","\u2091":"e","\u2095":"h","\u1d62":"i","\u2c7c":"j","\u2096":"k","\u2097":"l","\u2098":"m","\u2099":"n","\u2092":"o","\u209a":"p","\u1d63":"r","\u209b":"s","\u209c":"t","\u1d64":"u","\u1d65":"v","\u2093":"x","\u1d66":"\u03b2","\u1d67":"\u03b3","\u1d68":"\u03c1","\u1d69":"\u03d5","\u1d6a":"\u03c7","\u207a":"+","\u207b":"-","\u207c":"=","\u207d":"(","\u207e":")","\u2070":"0","\xb9":"1","\xb2":"2","\xb3":"3","\u2074":"4","\u2075":"5","\u2076":"6","\u2077":"7","\u2078":"8","\u2079":"9","\u1d2c":"A","\u1d2e":"B","\u1d30":"D","\u1d31":"E","\u1d33":"G","\u1d34":"H","\u1d35":"I","\u1d36":"J","\u1d37":"K","\u1d38":"L","\u1d39":"M","\u1d3a":"N","\u1d3c":"O","\u1d3e":"P","\u1d3f":"R","\u1d40":"T","\u1d41":"U","\u2c7d":"V","\u1d42":"W","\u1d43":"a","\u1d47":"b","\u1d9c":"c","\u1d48":"d","\u1d49":"e","\u1da0":"f","\u1d4d":"g","\u02b0":"h","\u2071":"i","\u02b2":"j","\u1d4f":"k","\u02e1":"l","\u1d50":"m","\u207f":"n","\u1d52":"o","\u1d56":"p","\u02b3":"r","\u02e2":"s","\u1d57":"t","\u1d58":"u","\u1d5b":"v","\u02b7":"w","\u02e3":"x","\u02b8":"y","\u1dbb":"z","\u1d5d":"\u03b2","\u1d5e":"\u03b3","\u1d5f":"\u03b4","\u1d60":"\u03d5","\u1d61":"\u03c7","\u1dbf":"\u03b8"}),Xa={"\u0301":{text:"\\'",math:"\\acute"},"\u0300":{text:"\\`",math:"\\grave"},"\u0308":{text:'\\"',math:"\\ddot"},"\u0303":{text:"\\~",math:"\\tilde"},"\u0304":{text:"\\=",math:"\\bar"},"\u0306":{text:"\\u",math:"\\breve"},"\u030c":{text:"\\v",math:"\\check"},"\u0302":{text:"\\^",math:"\\hat"},"\u0307":{text:"\\.",math:"\\dot"},"\u030a":{text:"\\r",math:"\\mathring"},"\u030b":{text:"\\H"},"\u0327":{text:"\\c"}},Wa={"\xe1":"a\u0301","\xe0":"a\u0300","\xe4":"a\u0308","\u01df":"a\u0308\u0304","\xe3":"a\u0303","\u0101":"a\u0304","\u0103":"a\u0306","\u1eaf":"a\u0306\u0301","\u1eb1":"a\u0306\u0300","\u1eb5":"a\u0306\u0303","\u01ce":"a\u030c","\xe2":"a\u0302","\u1ea5":"a\u0302\u0301","\u1ea7":"a\u0302\u0300","\u1eab":"a\u0302\u0303","\u0227":"a\u0307","\u01e1":"a\u0307\u0304","\xe5":"a\u030a","\u01fb":"a\u030a\u0301","\u1e03":"b\u0307","\u0107":"c\u0301","\u1e09":"c\u0327\u0301","\u010d":"c\u030c","\u0109":"c\u0302","\u010b":"c\u0307","\xe7":"c\u0327","\u010f":"d\u030c","\u1e0b":"d\u0307","\u1e11":"d\u0327","\xe9":"e\u0301","\xe8":"e\u0300","\xeb":"e\u0308","\u1ebd":"e\u0303","\u0113":"e\u0304","\u1e17":"e\u0304\u0301","\u1e15":"e\u0304\u0300","\u0115":"e\u0306","\u1e1d":"e\u0327\u0306","\u011b":"e\u030c","\xea":"e\u0302","\u1ebf":"e\u0302\u0301","\u1ec1":"e\u0302\u0300","\u1ec5":"e\u0302\u0303","\u0117":"e\u0307","\u0229":"e\u0327","\u1e1f":"f\u0307","\u01f5":"g\u0301","\u1e21":"g\u0304","\u011f":"g\u0306","\u01e7":"g\u030c","\u011d":"g\u0302","\u0121":"g\u0307","\u0123":"g\u0327","\u1e27":"h\u0308","\u021f":"h\u030c","\u0125":"h\u0302","\u1e23":"h\u0307","\u1e29":"h\u0327","\xed":"i\u0301","\xec":"i\u0300","\xef":"i\u0308","\u1e2f":"i\u0308\u0301","\u0129":"i\u0303","\u012b":"i\u0304","\u012d":"i\u0306","\u01d0":"i\u030c","\xee":"i\u0302","\u01f0":"j\u030c","\u0135":"j\u0302","\u1e31":"k\u0301","\u01e9":"k\u030c","\u0137":"k\u0327","\u013a":"l\u0301","\u013e":"l\u030c","\u013c":"l\u0327","\u1e3f":"m\u0301","\u1e41":"m\u0307","\u0144":"n\u0301","\u01f9":"n\u0300","\xf1":"n\u0303","\u0148":"n\u030c","\u1e45":"n\u0307","\u0146":"n\u0327","\xf3":"o\u0301","\xf2":"o\u0300","\xf6":"o\u0308","\u022b":"o\u0308\u0304","\xf5":"o\u0303","\u1e4d":"o\u0303\u0301","\u1e4f":"o\u0303\u0308","\u022d":"o\u0303\u0304","\u014d":"o\u0304","\u1e53":"o\u0304\u0301","\u1e51":"o\u0304\u0300","\u014f":"o\u0306","\u01d2":"o\u030c","\xf4":"o\u0302","\u1ed1":"o\u0302\u0301","\u1ed3":"o\u0302\u0300","\u1ed7":"o\u0302\u0303","\u022f":"o\u0307","\u0231":"o\u0307\u0304","\u0151":"o\u030b","\u1e55":"p\u0301","\u1e57":"p\u0307","\u0155":"r\u0301","\u0159":"r\u030c","\u1e59":"r\u0307","\u0157":"r\u0327","\u015b":"s\u0301","\u1e65":"s\u0301\u0307","\u0161":"s\u030c","\u1e67":"s\u030c\u0307","\u015d":"s\u0302","\u1e61":"s\u0307","\u015f":"s\u0327","\u1e97":"t\u0308","\u0165":"t\u030c","\u1e6b":"t\u0307","\u0163":"t\u0327","\xfa":"u\u0301","\xf9":"u\u0300","\xfc":"u\u0308","\u01d8":"u\u0308\u0301","\u01dc":"u\u0308\u0300","\u01d6":"u\u0308\u0304","\u01da":"u\u0308\u030c","\u0169":"u\u0303","\u1e79":"u\u0303\u0301","\u016b":"u\u0304","\u1e7b":"u\u0304\u0308","\u016d":"u\u0306","\u01d4":"u\u030c","\xfb":"u\u0302","\u016f":"u\u030a","\u0171":"u\u030b","\u1e7d":"v\u0303","\u1e83":"w\u0301","\u1e81":"w\u0300","\u1e85":"w\u0308","\u0175":"w\u0302","\u1e87":"w\u0307","\u1e98":"w\u030a","\u1e8d":"x\u0308","\u1e8b":"x\u0307","\xfd":"y\u0301","\u1ef3":"y\u0300","\xff":"y\u0308","\u1ef9":"y\u0303","\u0233":"y\u0304","\u0177":"y\u0302","\u1e8f":"y\u0307","\u1e99":"y\u030a","\u017a":"z\u0301","\u017e":"z\u030c","\u1e91":"z\u0302","\u017c":"z\u0307","\xc1":"A\u0301","\xc0":"A\u0300","\xc4":"A\u0308","\u01de":"A\u0308\u0304","\xc3":"A\u0303","\u0100":"A\u0304","\u0102":"A\u0306","\u1eae":"A\u0306\u0301","\u1eb0":"A\u0306\u0300","\u1eb4":"A\u0306\u0303","\u01cd":"A\u030c","\xc2":"A\u0302","\u1ea4":"A\u0302\u0301","\u1ea6":"A\u0302\u0300","\u1eaa":"A\u0302\u0303","\u0226":"A\u0307","\u01e0":"A\u0307\u0304","\xc5":"A\u030a","\u01fa":"A\u030a\u0301","\u1e02":"B\u0307","\u0106":"C\u0301","\u1e08":"C\u0327\u0301","\u010c":"C\u030c","\u0108":"C\u0302","\u010a":"C\u0307","\xc7":"C\u0327","\u010e":"D\u030c","\u1e0a":"D\u0307","\u1e10":"D\u0327","\xc9":"E\u0301","\xc8":"E\u0300","\xcb":"E\u0308","\u1ebc":"E\u0303","\u0112":"E\u0304","\u1e16":"E\u0304\u0301","\u1e14":"E\u0304\u0300","\u0114":"E\u0306","\u1e1c":"E\u0327\u0306","\u011a":"E\u030c","\xca":"E\u0302","\u1ebe":"E\u0302\u0301","\u1ec0":"E\u0302\u0300","\u1ec4":"E\u0302\u0303","\u0116":"E\u0307","\u0228":"E\u0327","\u1e1e":"F\u0307","\u01f4":"G\u0301","\u1e20":"G\u0304","\u011e":"G\u0306","\u01e6":"G\u030c","\u011c":"G\u0302","\u0120":"G\u0307","\u0122":"G\u0327","\u1e26":"H\u0308","\u021e":"H\u030c","\u0124":"H\u0302","\u1e22":"H\u0307","\u1e28":"H\u0327","\xcd":"I\u0301","\xcc":"I\u0300","\xcf":"I\u0308","\u1e2e":"I\u0308\u0301","\u0128":"I\u0303","\u012a":"I\u0304","\u012c":"I\u0306","\u01cf":"I\u030c","\xce":"I\u0302","\u0130":"I\u0307","\u0134":"J\u0302","\u1e30":"K\u0301","\u01e8":"K\u030c","\u0136":"K\u0327","\u0139":"L\u0301","\u013d":"L\u030c","\u013b":"L\u0327","\u1e3e":"M\u0301","\u1e40":"M\u0307","\u0143":"N\u0301","\u01f8":"N\u0300","\xd1":"N\u0303","\u0147":"N\u030c","\u1e44":"N\u0307","\u0145":"N\u0327","\xd3":"O\u0301","\xd2":"O\u0300","\xd6":"O\u0308","\u022a":"O\u0308\u0304","\xd5":"O\u0303","\u1e4c":"O\u0303\u0301","\u1e4e":"O\u0303\u0308","\u022c":"O\u0303\u0304","\u014c":"O\u0304","\u1e52":"O\u0304\u0301","\u1e50":"O\u0304\u0300","\u014e":"O\u0306","\u01d1":"O\u030c","\xd4":"O\u0302","\u1ed0":"O\u0302\u0301","\u1ed2":"O\u0302\u0300","\u1ed6":"O\u0302\u0303","\u022e":"O\u0307","\u0230":"O\u0307\u0304","\u0150":"O\u030b","\u1e54":"P\u0301","\u1e56":"P\u0307","\u0154":"R\u0301","\u0158":"R\u030c","\u1e58":"R\u0307","\u0156":"R\u0327","\u015a":"S\u0301","\u1e64":"S\u0301\u0307","\u0160":"S\u030c","\u1e66":"S\u030c\u0307","\u015c":"S\u0302","\u1e60":"S\u0307","\u015e":"S\u0327","\u0164":"T\u030c","\u1e6a":"T\u0307","\u0162":"T\u0327","\xda":"U\u0301","\xd9":"U\u0300","\xdc":"U\u0308","\u01d7":"U\u0308\u0301","\u01db":"U\u0308\u0300","\u01d5":"U\u0308\u0304","\u01d9":"U\u0308\u030c","\u0168":"U\u0303","\u1e78":"U\u0303\u0301","\u016a":"U\u0304","\u1e7a":"U\u0304\u0308","\u016c":"U\u0306","\u01d3":"U\u030c","\xdb":"U\u0302","\u016e":"U\u030a","\u0170":"U\u030b","\u1e7c":"V\u0303","\u1e82":"W\u0301","\u1e80":"W\u0300","\u1e84":"W\u0308","\u0174":"W\u0302","\u1e86":"W\u0307","\u1e8c":"X\u0308","\u1e8a":"X\u0307","\xdd":"Y\u0301","\u1ef2":"Y\u0300","\u0178":"Y\u0308","\u1ef8":"Y\u0303","\u0232":"Y\u0304","\u0176":"Y\u0302","\u1e8e":"Y\u0307","\u0179":"Z\u0301","\u017d":"Z\u030c","\u1e90":"Z\u0302","\u017b":"Z\u0307","\u03ac":"\u03b1\u0301","\u1f70":"\u03b1\u0300","\u1fb1":"\u03b1\u0304","\u1fb0":"\u03b1\u0306","\u03ad":"\u03b5\u0301","\u1f72":"\u03b5\u0300","\u03ae":"\u03b7\u0301","\u1f74":"\u03b7\u0300","\u03af":"\u03b9\u0301","\u1f76":"\u03b9\u0300","\u03ca":"\u03b9\u0308","\u0390":"\u03b9\u0308\u0301","\u1fd2":"\u03b9\u0308\u0300","\u1fd1":"\u03b9\u0304","\u1fd0":"\u03b9\u0306","\u03cc":"\u03bf\u0301","\u1f78":"\u03bf\u0300","\u03cd":"\u03c5\u0301","\u1f7a":"\u03c5\u0300","\u03cb":"\u03c5\u0308","\u03b0":"\u03c5\u0308\u0301","\u1fe2":"\u03c5\u0308\u0300","\u1fe1":"\u03c5\u0304","\u1fe0":"\u03c5\u0306","\u03ce":"\u03c9\u0301","\u1f7c":"\u03c9\u0300","\u038e":"\u03a5\u0301","\u1fea":"\u03a5\u0300","\u03ab":"\u03a5\u0308","\u1fe9":"\u03a5\u0304","\u1fe8":"\u03a5\u0306","\u038f":"\u03a9\u0301","\u1ffa":"\u03a9\u0300"};class _a{constructor(e,t){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new Ga(e,t,this.mode),this.settings=t,this.leftrightDepth=0}expect(e,t){if(void 0===t&&(t=!0),this.fetch().text!==e)throw new i("Expected '"+e+"', got '"+this.fetch().text+"'",this.fetch());t&&this.consume()}consume(){this.nextToken=null}fetch(){return null==this.nextToken&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken}switchMode(e){this.mode=e,this.gullet.switchMode(e)}parse(){this.settings.globalGroup||this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");try{var e=this.parseExpression(!1);return this.expect("EOF"),this.settings.globalGroup||this.gullet.endGroup(),e}finally{this.gullet.endGroups()}}subparse(e){var t=this.nextToken;this.consume(),this.gullet.pushToken(new n("}")),this.gullet.pushTokens(e);var r=this.parseExpression(!1);return this.expect("}"),this.nextToken=t,r}parseExpression(e,t){for(var r=[];;){"math"===this.mode&&this.consumeSpaces();var a=this.fetch();if(-1!==_a.endOfExpression.indexOf(a.text))break;if(t&&a.text===t)break;if(e&&Aa[a.text]&&Aa[a.text].infix)break;var n=this.parseAtom(t);if(!n)break;"internal"!==n.type&&r.push(n)}return"text"===this.mode&&this.formLigatures(r),this.handleInfixNodes(r)}handleInfixNodes(e){for(var t,r=-1,a=0;a=0&&this.settings.reportNonstrict("unicodeTextInMathMode",'Latin-1/Unicode text character "'+t[0]+'" used in math mode',e);var l,h=ne[this.mode][t].group,m=a.range(e);if(re.hasOwnProperty(h)){var c=h;l={type:"atom",mode:this.mode,family:c,loc:m,text:t}}else l={type:h,mode:this.mode,loc:m,text:t};o=l}else{if(!(t.charCodeAt(0)>=128))return null;this.settings.strict&&(z(t.charCodeAt(0))?"math"===this.mode&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+t[0]+'" used in math mode',e):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+t[0]+'" ('+t.charCodeAt(0)+")",e)),o={type:"textord",mode:"text",loc:a.range(e),text:t}}if(this.consume(),s)for(var p=0;p{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":"unreleased","badge":true,"noIndex":false,"className":"docs-version-current","isLast":false,"docsSidebars":{"docs":[{"type":"link","label":"What is Contrast?","href":"/contrast/pr-preview/pr-1071/next/","docId":"intro","unlisted":false},{"type":"category","label":"Basics","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/next/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/next/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/next/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/next/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false},{"type":"link","label":"Bare metal setup","href":"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal","docId":"getting-started/bare-metal","unlisted":false}],"collapsible":true},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/next/examples/emojivoto","docId":"examples/emojivoto","unlisted":false},{"type":"link","label":"Encrypted volume mount","href":"/contrast/pr-preview/pr-1071/next/examples/mysql","docId":"examples/mysql","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/next/deployment","docId":"deployment","unlisted":false},{"type":"link","label":"Troubleshooting","href":"/contrast/pr-preview/pr-1071/next/troubleshooting","docId":"troubleshooting","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Overview","href":"/contrast/pr-preview/pr-1071/next/components/overview","docId":"components/overview","unlisted":false},{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/next/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/next/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/next/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/next/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Secrets & recovery","href":"/contrast/pr-preview/pr-1071/next/architecture/secrets","docId":"architecture/secrets","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/next/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Security considerations","href":"/contrast/pr-preview/pr-1071/next/architecture/security-considerations","docId":"architecture/security-considerations","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/next/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/next/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/next/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"architecture/secrets":{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","sidebar":"docs"},"architecture/security-considerations":{"id":"architecture/security-considerations","title":"Security Considerations","description":"Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits).","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/overview":{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"examples/mysql":{"id":"examples/mysql","title":"Encrypted volume mount","description":"This tutorial guides you through deploying a simple application with an","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/bare-metal":{"id":"getting-started/bare-metal","title":"Prepare a bare-metal instance","description":"Hardware and firmware setup","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"troubleshooting":{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/21d7c4d4.70b063a4.js b/pr-preview/pr-1071/assets/js/21d7c4d4.70b063a4.js deleted file mode 100644 index 0a99ecc8d8..0000000000 --- a/pr-preview/pr-1071/assets/js/21d7c4d4.70b063a4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5390],{50728:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-0.6/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/examples/emojivoto.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Examples","permalink":"/contrast/pr-preview/pr-1071/0.6/examples/"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.6/deployment"}}');var i=n(74848),s=n(28453);const a={},r="Confidential emoji voting",d={},l=[{value:"Motivation",id:"motivation",level:3},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Downloading the deployment",id:"downloading-the-deployment",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Voter's perspective: Verifying the ballot",id:"voters-perspective-verifying-the-ballot",level:2},{value:"Attest the Coordinator",id:"attest-the-coordinator",level:3},{value:"Manifest history and artifact audit",id:"manifest-history-and-artifact-audit",level:3},{value:"Confidential connection to the attested workload",id:"confidential-connection-to-the-attested-workload",level:3},{value:"Certificate SAN and manifest update (optional)",id:"certificate-san-and-manifest-update-optional",level:2},{value:"Configure the service SAN in the manifest",id:"configure-the-service-san-in-the-manifest",level:3},{value:"Update the manifest",id:"update-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(69314).A+"",width:"1503",height:"732"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,i.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voters perspective."]})}),"\n",(0,i.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,i.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,i.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,i.jsx)(t.code,{children:"voting"}),"). The ",(0,i.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,i.jsx)(t.h3,{id:"motivation",children:"Motivation"}),"\n",(0,i.jsx)(t.p,{children:"Using a voting service, users' votes are considered highly sensitive data, as we require\na secret ballot. Also, users are likely interested in the fairness of the ballot. For\nboth requirements, we can use Confidential Computing and, specifically, workload attestation\nto prove to those interested in voting that the app is running in a protected environment\nwhere their votes are processed without leaking to the platform provider or workload owner."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Installed Contrast CLI."}),"\nSee the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/getting-started/install",children:"installation instructions"})," on how to get it."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Running cluster with Confidential Containers support."}),"\nPlease follow the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup",children:"cluster setup instructions"}),"\nto create a cluster."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,i.jsx)(t.h3,{id:"downloading-the-deployment",children:"Downloading the deployment"}),"\n",(0,i.jsx)(t.p,{children:"The emojivoto deployment files are part of a zip file in the Contrast release. You can download the\nlatest deployment by running:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/latest/download/emojivoto-demo.zip\n"})}),"\n",(0,i.jsxs)(t.p,{children:["After that, unzip the ",(0,i.jsx)(t.code,{children:"emojivoto-demo.zip"})," file to extract the ",(0,i.jsx)(t.code,{children:"deployment/"})," directory."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"unzip emojivoto-demo.zip\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,i.jsxs)(t.p,{children:["Contrast depends on a ",(0,i.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:["custom Kubernetes ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," (",(0,i.jsx)(t.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,i.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,i.jsxs)(t.p,{children:["Run the ",(0,i.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,i.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"contrast generate deployment/\n"})}),"\n",(0,i.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,i.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,i.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/components/runtime",children:"runtime class"})," ",(0,i.jsx)(t.code,{children:"contrast-cc-"}),"\nwas added to the pods to signal they should be run as Confidential Containers. In addition, the Contrast\n",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-initializer",children:"Initializer"})," was added as an init container to these workloads to\nfacilitate the attestation and certificate pulling before the actual workload is started."]}),(0,i.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,i.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsx)(t.p,{children:"The CLI will use the embedded reference values to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, we're ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,i.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,i.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,i.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,i.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,i.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,i.jsx)(t.h2,{id:"voters-perspective-verifying-the-ballot",children:"Voter's perspective: Verifying the ballot"}),"\n",(0,i.jsx)(t.p,{children:"As voters, we want to verify the fairness and confidentiality of the deployment before\ndeciding to vote. Regardless of the scale of our distributed deployment, Contrast only\nneeds a single remote attestation step to verify the deployment. By doing remote attestation\nof the Coordinator, we transitively verify those systems the Coordinator has already attested\nor will attest in the future. Successful verification of the Coordinator means that\nwe can be sure it will enforce the configured manifest."}),"\n",(0,i.jsx)(t.h3,{id:"attest-the-coordinator",children:"Attest the Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"A potential voter can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The CLI will attest the Coordinator using embedded reference values. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,i.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,i.jsx)(t.h3,{id:"manifest-history-and-artifact-audit",children:"Manifest history and artifact audit"}),"\n",(0,i.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,i.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,i.jsx)(t.h3,{id:"confidential-connection-to-the-attested-workload",children:"Confidential connection to the attested workload"}),"\n",(0,i.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, you can securely connect\nto the workloads using the Coordinator's ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,i.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,i.jsx)(t.h2,{id:"certificate-san-and-manifest-update-optional",children:"Certificate SAN and manifest update (optional)"}),"\n",(0,i.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,i.jsx)(t.h3,{id:"configure-the-service-san-in-the-manifest",children:"Configure the service SAN in the manifest"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,i.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,i.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n'})}),"\n",(0,i.jsx)(t.h3,{id:"update-the-manifest",children:"Update the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,i.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,i.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,i.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,i.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},69314:(e,t,n)=>{n.d(t,{A:()=>o});const o=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var o=n(96540);const i={},s=o.createContext(i);function a(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2334.a23ce334.js b/pr-preview/pr-1071/assets/js/2334.a23ce334.js deleted file mode 100644 index 7e65c1b8e9..0000000000 --- a/pr-preview/pr-1071/assets/js/2334.a23ce334.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2334],{62334:(e,n,t)=>{t.d(n,{Zp:()=>Rn});var r=t(8058),o=t(28894),i=0;const u=function(e){var n=++i;return(0,o.A)(e)+n};var a=t(39142),s=t(34098),d=t(74722),c=Math.ceil,h=Math.max;const f=function(e,n,t,r){for(var o=-1,i=h(c((n-e)/(t||1)),0),u=Array(i);i--;)u[r?i:++o]=e,e+=t;return u};var v=t(6832),l=t(74342);const g=function(e){return function(n,t,r){return r&&"number"!=typeof r&&(0,v.A)(n,t,r)&&(t=r=void 0),n=(0,l.A)(n),void 0===t?(t=n,n=0):t=(0,l.A)(t),r=void 0===r?n0;--a)if(r=n[a].dequeue()){o=o.concat(_(e,n,t,r,!0));break}}return o}(t.graph,t.buckets,t.zeroIdx);return s.A(d.A(o,(function(n){return e.outEdges(n.v,n.w)})))}function _(e,n,t,o,i){var u=i?[]:void 0;return r.A(e.inEdges(o.v),(function(r){var o=e.edge(r),a=e.node(r.v);i&&u.push({v:r.v,w:r.w}),a.out-=o,E(n,t,a)})),r.A(e.outEdges(o.v),(function(r){var o=e.edge(r),i=r.w,u=e.node(i);u.in-=o,E(n,t,u)})),e.removeNode(o.v),u}function E(e,n,t){t.out?t.in?e[t.out-t.in+n].enqueue(t):e[e.length-1].enqueue(t):e[0].enqueue(t)}function x(e){var n="greedy"===e.graph().acyclicer?y(e,function(e){return function(n){return e.edge(n).weight}}(e)):function(e){var n=[],t={},o={};function i(u){Object.prototype.hasOwnProperty.call(o,u)||(o[u]=!0,t[u]=!0,r.A(e.outEdges(u),(function(e){Object.prototype.hasOwnProperty.call(t,e.w)?n.push(e):i(e.w)})),delete t[u])}return r.A(e.nodes(),i),n}(e);r.A(n,(function(n){var t=e.edge(n);e.removeEdge(n),t.forwardName=n.name,t.reversed=!0,e.setEdge(n.w,n.v,t,u("rev"))}))}var O=t(42837),k=t(99354),N=t(39188);const P=function(e,n){return(0,k.A)(e,n,(function(n,t){return(0,N.A)(e,t)}))};var j=t(76875),C=t(67525);const I=function(e){return(0,C.A)((0,j.A)(e,void 0,s.A),e+"")}((function(e,n){return null==e?{}:P(e,n)}));var L=t(23068),T=t(72559);const M=function(e,n){return e>n};var R=t(29008);const F=function(e){return e&&e.length?(0,T.A)(e,R.A,M):void 0};var D=t(26666),S=t(52528),G=t(79841),V=t(23958);const B=function(e,n){var t={};return n=(0,V.A)(n,3),(0,G.A)(e,(function(e,r,o){(0,S.A)(t,r,n(e,r,o))})),t};var q=t(69592),Y=t(86452),z=t(48585),$=t(41917);const J=function(){return $.A.Date.now()};function Z(e,n,t,r){var o;do{o=u(r)}while(e.hasNode(o));return t.dummy=n,e.setNode(o,t),o}function H(e){var n=new p.T({multigraph:e.isMultigraph()}).setGraph(e.graph());return r.A(e.nodes(),(function(t){e.children(t).length||n.setNode(t,e.node(t))})),r.A(e.edges(),(function(t){n.setEdge(t,e.edge(t))})),n}function K(e,n){var t,r,o=e.x,i=e.y,u=n.x-o,a=n.y-i,s=e.width/2,d=e.height/2;if(!u&&!a)throw new Error("Not possible to find intersection inside of the rectangle");return Math.abs(a)*s>Math.abs(u)*d?(a<0&&(d=-d),t=d*u/a,r=d):(u<0&&(s=-s),t=s,r=s*a/u),{x:o+t,y:i+r}}function Q(e){var n=d.A(g(W(e)+1),(function(){return[]}));return r.A(e.nodes(),(function(t){var r=e.node(t),o=r.rank;q.A(o)||(n[o][r.order]=t)})),n}function U(e,n,t,r){var o={width:0,height:0};return arguments.length>=4&&(o.rank=t,o.order=r),Z(e,"border",o,n)}function W(e){return F(d.A(e.nodes(),(function(n){var t=e.node(n).rank;if(!q.A(t))return t})))}function X(e,n){var t=J();try{return n()}finally{console.log(e+" time: "+(J()-t)+"ms")}}function ee(e,n){return n()}function ne(e,n,t,r,o,i){var u={width:0,height:0,rank:i,borderType:n},a=o[n][i-1],s=Z(e,"border",u,t);o[n][i]=s,e.setParent(s,r),a&&e.setEdge(a,s,{weight:1})}function te(e){var n=e.graph().rankdir.toLowerCase();"bt"!==n&&"rl"!==n||function(e){r.A(e.nodes(),(function(n){ie(e.node(n))})),r.A(e.edges(),(function(n){var t=e.edge(n);r.A(t.points,ie),Object.prototype.hasOwnProperty.call(t,"y")&&ie(t)}))}(e),"lr"!==n&&"rl"!==n||(!function(e){r.A(e.nodes(),(function(n){ue(e.node(n))})),r.A(e.edges(),(function(n){var t=e.edge(n);r.A(t.points,ue),Object.prototype.hasOwnProperty.call(t,"x")&&ue(t)}))}(e),re(e))}function re(e){r.A(e.nodes(),(function(n){oe(e.node(n))})),r.A(e.edges(),(function(n){oe(e.edge(n))}))}function oe(e){var n=e.width;e.width=e.height,e.height=n}function ie(e){e.y=-e.y}function ue(e){var n=e.x;e.x=e.y,e.y=n}function ae(e){e.graph().dummyChains=[],r.A(e.edges(),(function(n){!function(e,n){var t=n.v,r=e.node(t).rank,o=n.w,i=e.node(o).rank,u=n.name,a=e.edge(n),s=a.labelRank;if(i===r+1)return;e.removeEdge(n);var d,c,h=void 0;for(c=0,++r;ru.lim&&(a=u,s=!0);var d=Ae.A(n.edges(),(function(n){return s===Be(e,e.node(n.v),a)&&s!==Be(e,e.node(n.w),a)}));return de(d,(function(e){return he(n,e)}))}function Ve(e,n,t,o){var i=t.v,u=t.w;e.removeEdge(i,u),e.setEdge(o.v,o.w,{}),Fe(e),Me(e,n),function(e,n){var t=pe.A(e.nodes(),(function(e){return!n.node(e).parent})),o=function(e,n){return Ie(e,n,"pre")}(e,t);o=o.slice(1),r.A(o,(function(t){var r=e.node(t).parent,o=n.edge(t,r),i=!1;o||(o=n.edge(r,t),i=!0),n.node(t).rank=n.node(r).rank+(i?o.minlen:-o.minlen)}))}(e,n)}function Be(e,n,t){return t.low<=n.lim&&n.lim<=t.lim}function qe(e){switch(e.graph().ranker){case"network-simplex":default:ze(e);break;case"tight-tree":!function(e){ce(e),fe(e)}(e);break;case"longest-path":Ye(e)}}Te.initLowLimValues=Fe,Te.initCutValues=Me,Te.calcCutValue=Re,Te.leaveEdge=Se,Te.enterEdge=Ge,Te.exchangeEdges=Ve;var Ye=ce;function ze(e){Te(e)}var $e=t(38207),Je=t(89463);function Ze(e){var n=Z(e,"root",{},"_root"),t=function(e){var n={};function t(o,i){var u=e.children(o);u&&u.length&&r.A(u,(function(e){t(e,i+1)})),n[o]=i}return r.A(e.children(),(function(e){t(e,1)})),n}(e),o=F($e.A(t))-1,i=2*o+1;e.graph().nestingRoot=n,r.A(e.edges(),(function(n){e.edge(n).minlen*=i}));var u=function(e){return Je.A(e.edges(),(function(n,t){return n+e.edge(t).weight}),0)}(e)+1;r.A(e.children(),(function(r){He(e,n,i,u,o,t,r)})),e.graph().nodeRankFactor=i}function He(e,n,t,o,i,u,a){var s=e.children(a);if(s.length){var d=U(e,"_bt"),c=U(e,"_bb"),h=e.node(a);e.setParent(d,a),h.borderTop=d,e.setParent(c,a),h.borderBottom=c,r.A(s,(function(r){He(e,n,t,o,i,u,r);var s=e.node(r),h=s.borderTop?s.borderTop:r,f=s.borderBottom?s.borderBottom:r,v=s.borderTop?o:2*o,l=h!==f?1:i-u[a]+1;e.setEdge(d,h,{weight:v,minlen:l,nestingEdge:!0}),e.setEdge(f,c,{weight:v,minlen:l,nestingEdge:!0})})),e.parent(a)||e.setEdge(n,d,{weight:0,minlen:i+u[a]})}else a!==n&&e.setEdge(n,a,{weight:0,minlen:t})}var Ke=t(68675);const Qe=function(e){return(0,Ke.A)(e,5)};function Ue(e,n,t){var o=function(e){var n;for(;e.hasNode(n=u("_root")););return n}(e),i=new p.T({compound:!0}).setGraph({root:o}).setDefaultNodeLabel((function(n){return e.node(n)}));return r.A(e.nodes(),(function(u){var a=e.node(u),s=e.parent(u);(a.rank===n||a.minRank<=n&&n<=a.maxRank)&&(i.setNode(u),i.setParent(u,s||o),r.A(e[t](u),(function(n){var t=n.v===u?n.w:n.v,r=i.edge(t,u),o=q.A(r)?0:r.weight;i.setEdge(t,u,{weight:e.edge(n).weight+o})})),Object.prototype.hasOwnProperty.call(a,"minRank")&&i.setNode(u,{borderLeft:a.borderLeft[n],borderRight:a.borderRight[n]}))})),i}var We=t(52851);const Xe=function(e,n,t){for(var r=-1,o=e.length,i=n.length,u={};++rn||i&&u&&s&&!a&&!d||r&&u&&s||!t&&s||!o)return 1;if(!r&&!i&&!d&&e=a?s:s*("desc"==t[r]?-1:1)}return e.index-n.index};const hn=function(e,n,t){n=n.length?(0,tn.A)(n,(function(e){return(0,Ce.A)(e)?function(n){return(0,rn.A)(n,1===e.length?e[0]:e)}:e})):[R.A];var r=-1;n=(0,tn.A)(n,(0,an.A)(V.A));var o=(0,on.A)(e,(function(e,t,o){return{criteria:(0,tn.A)(n,(function(n){return n(e)})),index:++r,value:e}}));return un(o,(function(e,n){return cn(e,n,t)}))};const fn=(0,t(24326).A)((function(e,n){if(null==e)return[];var t=n.length;return t>1&&(0,v.A)(e,n[0],n[1])?n=[]:t>2&&(0,v.A)(n[0],n[1],n[2])&&(n=[n[0]]),hn(e,(0,nn.A)(n,1),[])}));function vn(e,n){for(var t=0,r=1;r0;)n%2&&(t+=c[n+1]),c[n=n-1>>1]+=e.weight;h+=e.weight*t}))),h}function gn(e,n){var t={};return r.A(e,(function(e,n){var r=t[e.v]={indegree:0,in:[],out:[],vs:[e.v],i:n};q.A(e.barycenter)||(r.barycenter=e.barycenter,r.weight=e.weight)})),r.A(n.edges(),(function(e){var n=t[e.v],r=t[e.w];q.A(n)||q.A(r)||(r.indegree++,n.out.push(t[e.w]))})),function(e){var n=[];function t(e){return function(n){n.merged||(q.A(n.barycenter)||q.A(e.barycenter)||n.barycenter>=e.barycenter)&&function(e,n){var t=0,r=0;e.weight&&(t+=e.barycenter*e.weight,r+=e.weight);n.weight&&(t+=n.barycenter*n.weight,r+=n.weight);e.vs=n.vs.concat(e.vs),e.barycenter=t/r,e.weight=r,e.i=Math.min(n.i,e.i),n.merged=!0}(e,n)}}function o(n){return function(t){t.in.push(n),0==--t.indegree&&e.push(t)}}for(;e.length;){var i=e.pop();n.push(i),r.A(i.in.reverse(),t(i)),r.A(i.out,o(i))}return d.A(Ae.A(n,(function(e){return!e.merged})),(function(e){return I(e,["vs","i","barycenter","weight"])}))}(Ae.A(t,(function(e){return!e.indegree})))}function pn(e,n){var t,o=function(e,n){var t={lhs:[],rhs:[]};return r.A(e,(function(e){n(e)?t.lhs.push(e):t.rhs.push(e)})),t}(e,(function(e){return Object.prototype.hasOwnProperty.call(e,"barycenter")})),i=o.lhs,u=fn(o.rhs,(function(e){return-e.i})),a=[],d=0,c=0,h=0;i.sort((t=!!n,function(e,n){return e.barycentern.barycenter?1:t?n.i-e.i:e.i-n.i})),h=An(a,u,h),r.A(i,(function(e){h+=e.vs.length,a.push(e.vs),d+=e.barycenter*e.weight,c+=e.weight,h=An(a,u,h)}));var f={vs:s.A(a)};return c&&(f.barycenter=d/c,f.weight=c),f}function An(e,n,t){for(var r;n.length&&(r=D.A(n)).i<=t;)n.pop(),e.push(r.vs),t++;return t}function wn(e,n,t,o){var i=e.children(n),u=e.node(n),a=u?u.borderLeft:void 0,c=u?u.borderRight:void 0,h={};a&&(i=Ae.A(i,(function(e){return e!==a&&e!==c})));var f=function(e,n){return d.A(n,(function(n){var t=e.inEdges(n);if(t.length){var r=Je.A(t,(function(n,t){var r=e.edge(t),o=e.node(t.v);return{sum:n.sum+r.weight*o.order,weight:n.weight+r.weight}}),{sum:0,weight:0});return{v:n,barycenter:r.sum/r.weight,weight:r.weight}}return{v:n}}))}(e,i);r.A(f,(function(n){if(e.children(n.v).length){var r=wn(e,n.v,t,o);h[n.v]=r,Object.prototype.hasOwnProperty.call(r,"barycenter")&&(i=n,u=r,q.A(i.barycenter)?(i.barycenter=u.barycenter,i.weight=u.weight):(i.barycenter=(i.barycenter*i.weight+u.barycenter*u.weight)/(i.weight+u.weight),i.weight+=u.weight))}var i,u}));var v=gn(f,t);!function(e,n){r.A(e,(function(e){e.vs=s.A(e.vs.map((function(e){return n[e]?n[e].vs:e})))}))}(v,h);var l=pn(v,o);if(a&&(l.vs=s.A([a,l.vs,c]),e.predecessors(a).length)){var g=e.node(e.predecessors(a)[0]),p=e.node(e.predecessors(c)[0]);Object.prototype.hasOwnProperty.call(l,"barycenter")||(l.barycenter=0,l.weight=0),l.barycenter=(l.barycenter*l.weight+g.order+p.order)/(l.weight+2),l.weight+=2}return l}function bn(e){var n=W(e),t=mn(e,g(1,n+1),"inEdges"),o=mn(e,g(n-1,-1,-1),"outEdges"),i=function(e){var n={},t=Ae.A(e.nodes(),(function(n){return!e.children(n).length})),o=F(d.A(t,(function(n){return e.node(n).rank}))),i=d.A(g(o+1),(function(){return[]})),u=fn(t,(function(n){return e.node(n).rank}));return r.A(u,(function t(o){if(!z.A(n,o)){n[o]=!0;var u=e.node(o);i[u.rank].push(o),r.A(e.successors(o),t)}})),i}(e);_n(e,i);for(var u,a=Number.POSITIVE_INFINITY,s=0,c=0;c<4;++s,++c){yn(s%2?t:o,s%4>=2);var h=vn(e,i=Q(e));hs||d>n[o].lim));i=o,o=r;for(;(o=e.parent(o))!==i;)a.push(o);return{path:u.concat(a.reverse()),lca:i}}(e,n,o.v,o.w),u=i.path,a=i.lca,s=0,d=u[s],c=!0;t!==o.w;){if(r=e.node(t),c){for(;(d=u[s])!==a&&e.node(d).maxRankt){var r=n;n=t,t=r}var o=e[n];o||(e[n]=o={}),o[t]=!0}function In(e,n,t){if(n>t){var r=n;n=t,t=r}return!!e[n]&&Object.prototype.hasOwnProperty.call(e[n],t)}function Ln(e,n,t,o,i){var u={},a=function(e,n,t,o){var i=new p.T,u=e.graph(),a=function(e,n,t){return function(r,o,i){var u,a=r.node(o),s=r.node(i),d=0;if(d+=a.width/2,Object.prototype.hasOwnProperty.call(a,"labelpos"))switch(a.labelpos.toLowerCase()){case"l":u=-a.width/2;break;case"r":u=a.width/2}if(u&&(d+=t?u:-u),u=0,d+=(a.dummy?n:e)/2,d+=(s.dummy?n:e)/2,d+=s.width/2,Object.prototype.hasOwnProperty.call(s,"labelpos"))switch(s.labelpos.toLowerCase()){case"l":u=s.width/2;break;case"r":u=-s.width/2}return u&&(d+=t?u:-u),u=0,d}}(u.nodesep,u.edgesep,o);return r.A(n,(function(n){var o;r.A(n,(function(n){var r=t[n];if(i.setNode(r),o){var u=t[o],s=i.edge(u,r);i.setEdge(u,r,Math.max(a(e,n,o),s||0))}o=n}))})),i}(e,n,t,i),s=i?"borderLeft":"borderRight";function d(e,n){for(var t=a.nodes(),r=t.pop(),o={};r;)o[r]?e(r):(o[r]=!0,t.push(r),t=t.concat(n(r))),r=t.pop()}return d((function(e){u[e]=a.inEdges(e).reduce((function(e,n){return Math.max(e,u[n.v]+a.edge(n))}),0)}),a.predecessors.bind(a)),d((function(n){var t=a.outEdges(n).reduce((function(e,n){return Math.min(e,u[n.w]-a.edge(n))}),Number.POSITIVE_INFINITY),r=e.node(n);t!==Number.POSITIVE_INFINITY&&r.borderType!==s&&(u[n]=Math.max(u[n],t))}),a.successors.bind(a)),r.A(o,(function(e){u[e]=u[t[e]]})),u}function Tn(e){var n,t=Q(e),o=O.A(jn(e,t),function(e,n){var t={};function o(n,o,i,u,a){var s;r.A(g(o,i),(function(o){s=n[o],e.node(s).dummy&&r.A(e.predecessors(s),(function(n){var r=e.node(n);r.dummy&&(r.ordera)&&Cn(t,n,s)}))}))}return Je.A(n,(function(n,t){var i,u=-1,a=0;return r.A(t,(function(r,s){if("border"===e.node(r).dummy){var d=e.predecessors(r);d.length&&(i=e.node(d[0]).order,o(t,a,s,u,i),a=s,u=i)}o(t,a,t.length,i,n.length)})),t})),t}(e,t)),i={};r.A(["u","d"],(function(u){n="u"===u?t:$e.A(t).reverse(),r.A(["l","r"],(function(t){"r"===t&&(n=d.A(n,(function(e){return $e.A(e).reverse()})));var a=("u"===u?e.predecessors:e.successors).bind(e),s=function(e,n,t,o){var i={},u={},a={};return r.A(n,(function(e){r.A(e,(function(e,n){i[e]=e,u[e]=e,a[e]=n}))})),r.A(n,(function(e){var n=-1;r.A(e,(function(e){var r=o(e);if(r.length){r=fn(r,(function(e){return a[e]}));for(var s=(r.length-1)/2,d=Math.floor(s),c=Math.ceil(s);d<=c;++d){var h=r[d];u[e]===e&&n{var n=t(" buildLayoutGraph",(()=>function(e){var n=new p.T({multigraph:!0,compound:!0}),t=$n(e.graph());return n.setGraph(O.A({},Dn,zn(t,Fn),I(t,Sn))),r.A(e.nodes(),(function(t){var r=$n(e.node(t));n.setNode(t,L.A(zn(r,Gn),Vn)),n.setParent(t,e.parent(t))})),r.A(e.edges(),(function(t){var r=$n(e.edge(t));n.setEdge(t,O.A({},qn,zn(r,Bn),I(r,Yn)))})),n}(e)));t(" runLayout",(()=>function(e,n){n(" makeSpaceForEdgeLabels",(()=>function(e){var n=e.graph();n.ranksep/=2,r.A(e.edges(),(function(t){var r=e.edge(t);r.minlen*=2,"c"!==r.labelpos.toLowerCase()&&("TB"===n.rankdir||"BT"===n.rankdir?r.width+=r.labeloffset:r.height+=r.labeloffset)}))}(e))),n(" removeSelfEdges",(()=>function(e){r.A(e.edges(),(function(n){if(n.v===n.w){var t=e.node(n.v);t.selfEdges||(t.selfEdges=[]),t.selfEdges.push({e:n,label:e.edge(n)}),e.removeEdge(n)}}))}(e))),n(" acyclic",(()=>x(e))),n(" nestingGraph.run",(()=>Ze(e))),n(" rank",(()=>qe(H(e)))),n(" injectEdgeLabelProxies",(()=>function(e){r.A(e.edges(),(function(n){var t=e.edge(n);if(t.width&&t.height){var r=e.node(n.v),o={rank:(e.node(n.w).rank-r.rank)/2+r.rank,e:n};Z(e,"edge-proxy",o,"_ep")}}))}(e))),n(" removeEmptyRanks",(()=>function(e){var n=Y.A(d.A(e.nodes(),(function(n){return e.node(n).rank}))),t=[];r.A(e.nodes(),(function(r){var o=e.node(r).rank-n;t[o]||(t[o]=[]),t[o].push(r)}));var o=0,i=e.graph().nodeRankFactor;r.A(t,(function(n,t){q.A(n)&&t%i!=0?--o:o&&r.A(n,(function(n){e.node(n).rank+=o}))}))}(e))),n(" nestingGraph.cleanup",(()=>function(e){var n=e.graph();e.removeNode(n.nestingRoot),delete n.nestingRoot,r.A(e.edges(),(function(n){e.edge(n).nestingEdge&&e.removeEdge(n)}))}(e))),n(" normalizeRanks",(()=>function(e){var n=Y.A(d.A(e.nodes(),(function(n){return e.node(n).rank})));r.A(e.nodes(),(function(t){var r=e.node(t);z.A(r,"rank")&&(r.rank-=n)}))}(e))),n(" assignRankMinMax",(()=>function(e){var n=0;r.A(e.nodes(),(function(t){var r=e.node(t);r.borderTop&&(r.minRank=e.node(r.borderTop).rank,r.maxRank=e.node(r.borderBottom).rank,n=F(n,r.maxRank))})),e.graph().maxRank=n}(e))),n(" removeEdgeLabelProxies",(()=>function(e){r.A(e.nodes(),(function(n){var t=e.node(n);"edge-proxy"===t.dummy&&(e.edge(t.e).labelRank=t.rank,e.removeNode(n))}))}(e))),n(" normalize.run",(()=>ae(e))),n(" parentDummyChains",(()=>En(e))),n(" addBorderSegments",(()=>function(e){r.A(e.children(),(function n(t){var o=e.children(t),i=e.node(t);if(o.length&&r.A(o,n),Object.prototype.hasOwnProperty.call(i,"minRank")){i.borderLeft=[],i.borderRight=[];for(var u=i.minRank,a=i.maxRank+1;ubn(e))),n(" insertSelfEdges",(()=>function(e){var n=Q(e);r.A(n,(function(n){var t=0;r.A(n,(function(n,o){var i=e.node(n);i.order=o+t,r.A(i.selfEdges,(function(n){Z(e,"selfedge",{width:n.label.width,height:n.label.height,rank:i.rank,order:o+ ++t,e:n.e,label:n.label},"_se")})),delete i.selfEdges}))}))}(e))),n(" adjustCoordinateSystem",(()=>function(e){var n=e.graph().rankdir.toLowerCase();"lr"!==n&&"rl"!==n||re(e)}(e))),n(" position",(()=>Mn(e))),n(" positionSelfEdges",(()=>function(e){r.A(e.nodes(),(function(n){var t=e.node(n);if("selfedge"===t.dummy){var r=e.node(t.e.v),o=r.x+r.width/2,i=r.y,u=t.x-o,a=r.height/2;e.setEdge(t.e,t.label),e.removeNode(n),t.label.points=[{x:o+2*u/3,y:i-a},{x:o+5*u/6,y:i-a},{x:o+u,y:i},{x:o+5*u/6,y:i+a},{x:o+2*u/3,y:i+a}],t.label.x=t.x,t.label.y=t.y}}))}(e))),n(" removeBorderNodes",(()=>function(e){r.A(e.nodes(),(function(n){if(e.children(n).length){var t=e.node(n),r=e.node(t.borderTop),o=e.node(t.borderBottom),i=e.node(D.A(t.borderLeft)),u=e.node(D.A(t.borderRight));t.width=Math.abs(u.x-i.x),t.height=Math.abs(o.y-r.y),t.x=i.x+t.width/2,t.y=r.y+t.height/2}})),r.A(e.nodes(),(function(n){"border"===e.node(n).dummy&&e.removeNode(n)}))}(e))),n(" normalize.undo",(()=>function(e){r.A(e.graph().dummyChains,(function(n){var t,r=e.node(n),o=r.edgeLabel;for(e.setEdge(r.edgeObj,o);r.dummy;)t=e.successors(n)[0],e.removeNode(n),o.points.push({x:r.x,y:r.y}),"edge-label"===r.dummy&&(o.x=r.x,o.y=r.y,o.width=r.width,o.height=r.height),n=t,r=e.node(n)}))}(e))),n(" fixupEdgeLabelCoords",(()=>function(e){r.A(e.edges(),(function(n){var t=e.edge(n);if(Object.prototype.hasOwnProperty.call(t,"x"))switch("l"!==t.labelpos&&"r"!==t.labelpos||(t.width-=t.labeloffset),t.labelpos){case"l":t.x-=t.width/2+t.labeloffset;break;case"r":t.x+=t.width/2+t.labeloffset}}))}(e))),n(" undoCoordinateSystem",(()=>te(e))),n(" translateGraph",(()=>function(e){var n=Number.POSITIVE_INFINITY,t=0,o=Number.POSITIVE_INFINITY,i=0,u=e.graph(),a=u.marginx||0,s=u.marginy||0;function d(e){var r=e.x,u=e.y,a=e.width,s=e.height;n=Math.min(n,r-a/2),t=Math.max(t,r+a/2),o=Math.min(o,u-s/2),i=Math.max(i,u+s/2)}r.A(e.nodes(),(function(n){d(e.node(n))})),r.A(e.edges(),(function(n){var t=e.edge(n);Object.prototype.hasOwnProperty.call(t,"x")&&d(t)})),n-=a,o-=s,r.A(e.nodes(),(function(t){var r=e.node(t);r.x-=n,r.y-=o})),r.A(e.edges(),(function(t){var i=e.edge(t);r.A(i.points,(function(e){e.x-=n,e.y-=o})),Object.prototype.hasOwnProperty.call(i,"x")&&(i.x-=n),Object.prototype.hasOwnProperty.call(i,"y")&&(i.y-=o)})),u.width=t-n+a,u.height=i-o+s}(e))),n(" assignNodeIntersects",(()=>function(e){r.A(e.edges(),(function(n){var t,r,o=e.edge(n),i=e.node(n.v),u=e.node(n.w);o.points?(t=o.points[0],r=o.points[o.points.length-1]):(o.points=[],t=u,r=i),o.points.unshift(K(i,t)),o.points.push(K(u,r))}))}(e))),n(" reversePoints",(()=>function(e){r.A(e.edges(),(function(n){var t=e.edge(n);t.reversed&&t.points.reverse()}))}(e))),n(" acyclic.undo",(()=>function(e){r.A(e.edges(),(function(n){var t=e.edge(n);if(t.reversed){e.removeEdge(n);var r=t.forwardName;delete t.reversed,delete t.forwardName,e.setEdge(n.w,n.v,t,r)}}))}(e)))}(n,t))),t(" updateInputGraph",(()=>function(e,n){r.A(e.nodes(),(function(t){var r=e.node(t),o=n.node(t);r&&(r.x=o.x,r.y=o.y,n.children(t).length&&(r.width=o.width,r.height=o.height))})),r.A(e.edges(),(function(t){var r=e.edge(t),o=n.edge(t);r.points=o.points,Object.prototype.hasOwnProperty.call(o,"x")&&(r.x=o.x,r.y=o.y)})),e.graph().width=n.graph().width,e.graph().height=n.graph().height}(e,n)))}))}var Fn=["nodesep","edgesep","ranksep","marginx","marginy"],Dn={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},Sn=["acyclicer","ranker","rankdir","align"],Gn=["width","height"],Vn={width:0,height:0},Bn=["minlen","weight","width","height","labeloffset"],qn={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},Yn=["labelpos"];function zn(e,n){return B(I(e,n),Number)}function $n(e){var n={};return r.A(e,(function(e,t){n[t.toLowerCase()]=e})),n}},37981:(e,n,t)=>{t.d(n,{T:()=>w});var r=t(39142),o=t(89610),i=t(27422),u=t(94092),a=t(66401),s=t(8058),d=t(69592),c=t(13588),h=t(24326),f=t(99902),v=t(53533);const l=(0,h.A)((function(e){return(0,f.A)((0,c.A)(e,1,v.A,!0))}));var g=t(38207),p=t(89463),A="\0";class w{constructor(e={}){this._isDirected=!Object.prototype.hasOwnProperty.call(e,"directed")||e.directed,this._isMultigraph=!!Object.prototype.hasOwnProperty.call(e,"multigraph")&&e.multigraph,this._isCompound=!!Object.prototype.hasOwnProperty.call(e,"compound")&&e.compound,this._label=void 0,this._defaultNodeLabelFn=r.A(void 0),this._defaultEdgeLabelFn=r.A(void 0),this._nodes={},this._isCompound&&(this._parent={},this._children={},this._children[A]={}),this._in={},this._preds={},this._out={},this._sucs={},this._edgeObjs={},this._edgeLabels={}}isDirected(){return this._isDirected}isMultigraph(){return this._isMultigraph}isCompound(){return this._isCompound}setGraph(e){return this._label=e,this}graph(){return this._label}setDefaultNodeLabel(e){return o.A(e)||(e=r.A(e)),this._defaultNodeLabelFn=e,this}nodeCount(){return this._nodeCount}nodes(){return i.A(this._nodes)}sources(){var e=this;return u.A(this.nodes(),(function(n){return a.A(e._in[n])}))}sinks(){var e=this;return u.A(this.nodes(),(function(n){return a.A(e._out[n])}))}setNodes(e,n){var t=arguments,r=this;return s.A(e,(function(e){t.length>1?r.setNode(e,n):r.setNode(e)})),this}setNode(e,n){return Object.prototype.hasOwnProperty.call(this._nodes,e)?(arguments.length>1&&(this._nodes[e]=n),this):(this._nodes[e]=arguments.length>1?n:this._defaultNodeLabelFn(e),this._isCompound&&(this._parent[e]=A,this._children[e]={},this._children[A][e]=!0),this._in[e]={},this._preds[e]={},this._out[e]={},this._sucs[e]={},++this._nodeCount,this)}node(e){return this._nodes[e]}hasNode(e){return Object.prototype.hasOwnProperty.call(this._nodes,e)}removeNode(e){if(Object.prototype.hasOwnProperty.call(this._nodes,e)){var n=e=>this.removeEdge(this._edgeObjs[e]);delete this._nodes[e],this._isCompound&&(this._removeFromParentsChildList(e),delete this._parent[e],s.A(this.children(e),(e=>{this.setParent(e)})),delete this._children[e]),s.A(i.A(this._in[e]),n),delete this._in[e],delete this._preds[e],s.A(i.A(this._out[e]),n),delete this._out[e],delete this._sucs[e],--this._nodeCount}return this}setParent(e,n){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(d.A(n))n=A;else{for(var t=n+="";!d.A(t);t=this.parent(t))if(t===e)throw new Error("Setting "+n+" as parent of "+e+" would create a cycle");this.setNode(n)}return this.setNode(e),this._removeFromParentsChildList(e),this._parent[e]=n,this._children[n][e]=!0,this}_removeFromParentsChildList(e){delete this._children[this._parent[e]][e]}parent(e){if(this._isCompound){var n=this._parent[e];if(n!==A)return n}}children(e){if(d.A(e)&&(e=A),this._isCompound){var n=this._children[e];if(n)return i.A(n)}else{if(e===A)return this.nodes();if(this.hasNode(e))return[]}}predecessors(e){var n=this._preds[e];if(n)return i.A(n)}successors(e){var n=this._sucs[e];if(n)return i.A(n)}neighbors(e){var n=this.predecessors(e);if(n)return l(n,this.successors(e))}isLeaf(e){return 0===(this.isDirected()?this.successors(e):this.neighbors(e)).length}filterNodes(e){var n=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});n.setGraph(this.graph());var t=this;s.A(this._nodes,(function(t,r){e(r)&&n.setNode(r,t)})),s.A(this._edgeObjs,(function(e){n.hasNode(e.v)&&n.hasNode(e.w)&&n.setEdge(e,t.edge(e))}));var r={};function o(e){var i=t.parent(e);return void 0===i||n.hasNode(i)?(r[e]=i,i):i in r?r[i]:o(i)}return this._isCompound&&s.A(n.nodes(),(function(e){n.setParent(e,o(e))})),n}setDefaultEdgeLabel(e){return o.A(e)||(e=r.A(e)),this._defaultEdgeLabelFn=e,this}edgeCount(){return this._edgeCount}edges(){return g.A(this._edgeObjs)}setPath(e,n){var t=this,r=arguments;return p.A(e,(function(e,o){return r.length>1?t.setEdge(e,o,n):t.setEdge(e,o),o})),this}setEdge(){var e,n,t,r,o=!1,i=arguments[0];"object"==typeof i&&null!==i&&"v"in i?(e=i.v,n=i.w,t=i.name,2===arguments.length&&(r=arguments[1],o=!0)):(e=i,n=arguments[1],t=arguments[3],arguments.length>2&&(r=arguments[2],o=!0)),e=""+e,n=""+n,d.A(t)||(t=""+t);var u=y(this._isDirected,e,n,t);if(Object.prototype.hasOwnProperty.call(this._edgeLabels,u))return o&&(this._edgeLabels[u]=r),this;if(!d.A(t)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(e),this.setNode(n),this._edgeLabels[u]=o?r:this._defaultEdgeLabelFn(e,n,t);var a=function(e,n,t,r){var o=""+n,i=""+t;if(!e&&o>i){var u=o;o=i,i=u}var a={v:o,w:i};r&&(a.name=r);return a}(this._isDirected,e,n,t);return e=a.v,n=a.w,Object.freeze(a),this._edgeObjs[u]=a,b(this._preds[n],e),b(this._sucs[e],n),this._in[n][u]=a,this._out[e][u]=a,this._edgeCount++,this}edge(e,n,t){var r=1===arguments.length?_(this._isDirected,arguments[0]):y(this._isDirected,e,n,t);return this._edgeLabels[r]}hasEdge(e,n,t){var r=1===arguments.length?_(this._isDirected,arguments[0]):y(this._isDirected,e,n,t);return Object.prototype.hasOwnProperty.call(this._edgeLabels,r)}removeEdge(e,n,t){var r=1===arguments.length?_(this._isDirected,arguments[0]):y(this._isDirected,e,n,t),o=this._edgeObjs[r];return o&&(e=o.v,n=o.w,delete this._edgeLabels[r],delete this._edgeObjs[r],m(this._preds[n],e),m(this._sucs[e],n),delete this._in[n][r],delete this._out[e][r],this._edgeCount--),this}inEdges(e,n){var t=this._in[e];if(t){var r=g.A(t);return n?u.A(r,(function(e){return e.v===n})):r}}outEdges(e,n){var t=this._out[e];if(t){var r=g.A(t);return n?u.A(r,(function(e){return e.w===n})):r}}nodeEdges(e,n){var t=this.inEdges(e,n);if(t)return t.concat(this.outEdges(e,n))}}function b(e,n){e[n]?e[n]++:e[n]=1}function m(e,n){--e[n]||delete e[n]}function y(e,n,t,r){var o=""+n,i=""+t;if(!e&&o>i){var u=o;o=i,i=u}return o+"\x01"+i+"\x01"+(d.A(r)?"\0":r)}function _(e,n){return y(e,n.v,n.w,n.name)}w.prototype._nodeCount=0,w.prototype._edgeCount=0},697:(e,n,t)=>{t.d(n,{T:()=>r.T});var r=t(37981)},72559:(e,n,t)=>{t.d(n,{A:()=>o});var r=t(61882);const o=function(e,n,t){for(var o=-1,i=e.length;++o{t.d(n,{A:()=>r});const r=function(e,n){return e{t.d(n,{A:()=>i});var r=t(6240),o=t(38446);const i=function(e,n){var t=-1,i=(0,o.A)(e)?Array(e.length):[];return(0,r.A)(e,(function(e,r,o){i[++t]=n(e,r,o)})),i}},99354:(e,n,t)=>{t.d(n,{A:()=>c});var r=t(66318),o=t(52851),i=t(7819),u=t(25353),a=t(23149),s=t(30901);const d=function(e,n,t,r){if(!(0,a.A)(e))return e;for(var d=-1,c=(n=(0,i.A)(n,e)).length,h=c-1,f=e;null!=f&&++d{t.d(n,{A:()=>d});var r=t(24326),o=t(66984),i=t(6832),u=t(55615),a=Object.prototype,s=a.hasOwnProperty;const d=(0,r.A)((function(e,n){e=Object(e);var t=-1,r=n.length,d=r>2?n[2]:void 0;for(d&&(0,i.A)(n[0],n[1],d)&&(r=1);++t{t.d(n,{A:()=>c});var r=t(23958),o=t(38446),i=t(27422);const u=function(e){return function(n,t,u){var a=Object(n);if(!(0,o.A)(n)){var s=(0,r.A)(t,3);n=(0,i.A)(n),t=function(e){return s(a[e],e,a)}}var d=e(n,t,u);return d>-1?a[s?n[d]:d]:void 0}};var a=t(25707),s=t(18593),d=Math.max;const c=u((function(e,n,t){var o=null==e?0:e.length;if(!o)return-1;var i=null==t?0:(0,s.A)(t);return i<0&&(i=d(o+i,0)),(0,a.A)(e,(0,r.A)(n,3),i)}))},34098:(e,n,t)=>{t.d(n,{A:()=>o});var r=t(13588);const o=function(e){return(null==e?0:e.length)?(0,r.A)(e,1):[]}},48585:(e,n,t)=>{t.d(n,{A:()=>u});var r=Object.prototype.hasOwnProperty;const o=function(e,n){return null!=e&&r.call(e,n)};var i=t(85054);const u=function(e,n){return null!=e&&(0,i.A)(e,n,o)}},9703:(e,n,t)=>{t.d(n,{A:()=>u});var r=t(88496),o=t(92049),i=t(53098);const u=function(e){return"string"==typeof e||!(0,o.A)(e)&&(0,i.A)(e)&&"[object String]"==(0,r.A)(e)}},26666:(e,n,t)=>{t.d(n,{A:()=>r});const r=function(e){var n=null==e?0:e.length;return n?e[n-1]:void 0}},74722:(e,n,t)=>{t.d(n,{A:()=>a});var r=t(45572),o=t(23958),i=t(52568),u=t(92049);const a=function(e,n){return((0,u.A)(e)?r.A:i.A)(e,(0,o.A)(n,3))}},86452:(e,n,t)=>{t.d(n,{A:()=>u});var r=t(72559),o=t(36224),i=t(29008);const u=function(e){return e&&e.length?(0,r.A)(e,i.A,o.A):void 0}},74342:(e,n,t)=>{t.d(n,{A:()=>g});var r=/\s/;const o=function(e){for(var n=e.length;n--&&r.test(e.charAt(n)););return n};var i=/^\s+/;const u=function(e){return e?e.slice(0,o(e)+1).replace(i,""):e};var a=t(23149),s=t(61882),d=/^[-+]0x[0-9a-f]+$/i,c=/^0b[01]+$/i,h=/^0o[0-7]+$/i,f=parseInt;const v=function(e){if("number"==typeof e)return e;if((0,s.A)(e))return NaN;if((0,a.A)(e)){var n="function"==typeof e.valueOf?e.valueOf():e;e=(0,a.A)(n)?n+"":n}if("string"!=typeof e)return 0===e?e:+e;e=u(e);var t=c.test(e);return t||h.test(e)?f(e.slice(2),t?2:8):d.test(e)?NaN:+e};var l=1/0;const g=function(e){return e?(e=v(e))===l||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}},18593:(e,n,t)=>{t.d(n,{A:()=>o});var r=t(74342);const o=function(e){var n=(0,r.A)(e),t=n%1;return n==n?t?n-t:n:0}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2387.7f9ca256.js b/pr-preview/pr-1071/assets/js/2387.7f9ca256.js deleted file mode 100644 index 656ddac028..0000000000 --- a/pr-preview/pr-1071/assets/js/2387.7f9ca256.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2387],{82387:(s,c,e)=>{e.d(c,{createGitGraphServices:()=>t.b});var t=e(82785);e(19369)}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2496d21b.ee6432b9.js b/pr-preview/pr-1071/assets/js/2496d21b.ee6432b9.js deleted file mode 100644 index f60ce7040b..0000000000 --- a/pr-preview/pr-1071/assets/js/2496d21b.ee6432b9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[995],{83495:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/docs/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/next/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/about/telemetry.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/next/features-limitations"}}');var r=n(74848),o=n(28453);const a={},i="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>i});var s=n(96540);const r={},o=s.createContext(r);function a(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/250ffcdd.ae6e76ac.js b/pr-preview/pr-1071/assets/js/250ffcdd.ae6e76ac.js deleted file mode 100644 index e79c1009e3..0000000000 --- a/pr-preview/pr-1071/assets/js/250ffcdd.ae6e76ac.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2343],{30106:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>d});const o=JSON.parse('{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","source":"@site/versioned_docs/version-0.8/troubleshooting.md","sourceDirName":".","slug":"/troubleshooting","permalink":"/contrast/pr-preview/pr-1071/0.8/troubleshooting","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/troubleshooting.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.8/deployment"},"next":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/0.8/components/overview"}}');var i=t(74848),s=t(28453);const a={},r="Troubleshooting",c={},d=[{value:"Logging",id:"logging",level:2},{value:"CLI",id:"cli",level:3},{value:"Coordinator and Initializer",id:"coordinator-and-initializer",level:3},{value:"Pod fails to start",id:"pod-fails-to-start",level:2},{value:"Regenerating the policies",id:"regenerating-the-policies",level:3},{value:"Pin container images",id:"pin-container-images",level:3},{value:"Validate Contrast components match",id:"validate-contrast-components-match",level:3}];function l(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"troubleshooting",children:"Troubleshooting"})}),"\n",(0,i.jsx)(n.p,{children:"This section contains information on how to debug your Contrast deployment."}),"\n",(0,i.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,i.jsx)(n.p,{children:"Collecting logs can be a good first step to identify problems in your\ndeployment. Both the CLI and the Contrast Coordinator as well as the Initializer\ncan be configured to emit additional logs."}),"\n",(0,i.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,i.jsxs)(n.p,{children:["The CLI logs can be configured with the ",(0,i.jsx)(n.code,{children:"--log-level"})," command-line flag, which\ncan be set to either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"})," or ",(0,i.jsx)(n.code,{children:"error"}),". The default is ",(0,i.jsx)(n.code,{children:"info"}),".\nSetting this to ",(0,i.jsx)(n.code,{children:"debug"})," can get more fine-grained information as to where the\nproblem lies."]}),"\n",(0,i.jsx)(n.h3,{id:"coordinator-and-initializer",children:"Coordinator and Initializer"}),"\n",(0,i.jsxs)(n.p,{children:["The logs from the Coordinator and the Initializer can be configured via the\nenvironment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"}),", ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," and\n",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"})," can be set to one of either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"}),", or\n",(0,i.jsx)(n.code,{children:"error"}),", similar to the CLI (defaults to ",(0,i.jsx)(n.code,{children:"info"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," can be set to ",(0,i.jsx)(n.code,{children:"text"})," or ",(0,i.jsx)(n.code,{children:"json"}),", determining the output\nformat (defaults to ",(0,i.jsx)(n.code,{children:"text"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," is a comma-seperated list of subsystems that should\nbe enabled for logging, which are disabled by default. Subsystems include:\n",(0,i.jsx)(n.code,{children:"snp-issuer"}),", ",(0,i.jsx)(n.code,{children:"kds-getter"}),", and ",(0,i.jsx)(n.code,{children:"snp-validator"}),". To enable all subsystems, use\n",(0,i.jsx)(n.code,{children:"*"})," as the value for this environment variable.\nWarnings and error messages from subsystems get printed regardless of whether\nthe subsystem is listed in the ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," environment variable."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"To configure debug logging with all subsystems for your Coordinator, add the\nfollowing variables to your container definition."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n containers:\n image: "ghcr.io/edgelesssys/contrast/coordinator:v0.8.1@sha256:bcd08a03096d38b350853c1dc8a595e0e8dd18e6af651bad4afd6838d842e257"\n name: coordinator\n env:\n - name: CONTRAST_LOG_LEVEL\n value: debug\n - name: CONTRAST_LOG_SUBSYSTEMS\n value: "*"\n # ...\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["While the Contrast Coordinator has a policy that allows certain configurations,\nthe Initializer and service mesh don't. When changing environment variables of other\nparts than the Coordinator, ensure to rerun ",(0,i.jsx)(n.code,{children:"contrast generate"})," to update the policy."]})}),"\n",(0,i.jsxs)(n.p,{children:["To access the logs generated by the Coordinator, you can use ",(0,i.jsx)(n.code,{children:"kubectl"})," with the\nfollowing command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl logs \n"})}),"\n",(0,i.jsx)(n.h2,{id:"pod-fails-to-start",children:"Pod fails to start"}),"\n",(0,i.jsxs)(n.p,{children:["If the Coordinator or a workload pod fails to even start, it can be helpful to\nlook at the events of the pod during the startup process using the ",(0,i.jsx)(n.code,{children:"describe"}),"\ncommand."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n events --for pod/\n"})}),"\n",(0,i.jsx)(n.p,{children:"Example output:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'LAST SEEN TYPE REASON OBJECT MESSAGE\n32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...\n'})}),"\n",(0,i.jsx)(n.p,{children:"A common error, as in this example, is that the container creation was blocked by the\npolicy. Potential reasons are a modification of the deployment YAML without updating\nthe policies afterward, or a version mismatch between Contrast components."}),"\n",(0,i.jsx)(n.h3,{id:"regenerating-the-policies",children:"Regenerating the policies"}),"\n",(0,i.jsx)(n.p,{children:"To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated\npolicies, rerun"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast generate\n"})}),"\n",(0,i.jsx)(n.p,{children:"on your deployment. If any of the policy annotations change, re-deploy with the updated policies."}),"\n",(0,i.jsx)(n.h3,{id:"pin-container-images",children:"Pin container images"}),"\n",(0,i.jsx)(n.p,{children:"When generating the policies, Contrast will download the images specified in your deployment\nYAML and include their cryptographic identity. If the image tag is moved to another\ncontainer image after the policy has been generated, the image downloaded at deploy time\nwill differ from the one at generation time, and the policy enforcement won't allow the\ncontainer to be started in the pod VM."}),"\n",(0,i.jsxs)(n.p,{children:["To ensure the correct image is always used, pin the container image to a fixed ",(0,i.jsx)(n.code,{children:"sha256"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This way, the same image will still be pulled when the container tag (",(0,i.jsx)(n.code,{children:"22.04"}),") is moved\nto another image."]}),"\n",(0,i.jsx)(n.h3,{id:"validate-contrast-components-match",children:"Validate Contrast components match"}),"\n",(0,i.jsx)(n.p,{children:"A version mismatch between Contrast components can cause policy validation or attestation\nto fail. Each Contrast runtime is identifiable based on its (shortened) measurement value\nused to name the runtime class version."}),"\n",(0,i.jsx)(n.p,{children:"First, analyze which runtime class is currently installed in your cluster by running"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl get runtimeclasses\n"})}),"\n",(0,i.jsx)(n.p,{children:"This should give you output similar to the following one."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"NAME HANDLER AGE\ncontrast-cc-30bfa8706b542271ec9b7762bbb400af contrast-cc-30bfa8706b542271ec9b7762bbb400af 23d\ncontrast-cc-4d70a6e266cca46dfa8e41d92874e638 contrast-cc-4d70a6e266cca46dfa8e41d92874e638 7d\ncontrast-cc-b817659e094106f61bf6c178c27153ba contrast-cc-b817659e094106f61bf6c178c27153ba 2d19h\ncontrast-cc-beee79ca916b9e5dc59602788cbfb097 contrast-cc-beee79ca916b9e5dc59602788cbfb097 121m\nkata-cc-isolation kata-cc 45d\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided\nby the AKS CoCo preview, which isn't used by Contrast)."}),"\n",(0,i.jsx)(n.p,{children:"Next, check if the pod that won't start has the correct runtime class configured, and the\nCoordinator uses the exact same runtime:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n get -o=jsonpath='{.spec.runtimeClassName}' pod/\nkubectl -n get -o=jsonpath='{.spec.runtimeClassName}' pod/\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output should list the runtime class the pod is using:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast-cc-beee79ca916b9e5dc59602788cbfb097\ncontrast-cc-beee79ca916b9e5dc59602788cbfb097\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Version information about the currently used CLI can be obtained via the ",(0,i.jsx)(n.code,{children:"version"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast --version\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast version v0.X.0\n\n runtime handler: contrast-cc-beee79ca916b9e5dc59602788cbfb097\n launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35\n genpolicy version: 3.2.0.azl1.genpolicy0\n image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...\n ghcr.io/edgelesssys/contrast/initializer@sha256:...\n"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(96540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2560.c3661469.js b/pr-preview/pr-1071/assets/js/2560.c3661469.js deleted file mode 100644 index 87abbbe412..0000000000 --- a/pr-preview/pr-1071/assets/js/2560.c3661469.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2560],{83510:(e,t,n)=>{n.d(t,{A:()=>a});n(96540);var o=n(34164),s=n(23230),i=n(85225),r=n(74848);function a(e){let{className:t}=e;return(0,r.jsx)("main",{className:(0,o.A)("container margin-vert--xl",t),children:(0,r.jsx)("div",{className:"row",children:(0,r.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,r.jsx)(i.A,{as:"h1",className:"hero__title",children:(0,r.jsx)(s.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,r.jsx)("p",{children:(0,r.jsx)(s.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,r.jsx)("p",{children:(0,r.jsx)(s.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},72560:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});n(96540);var o=n(23230),s=n(69817),i=n(53022),r=n(83510),a=n(74848);function c(){const e=(0,o.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(s.be,{title:e}),(0,a.jsx)(i.A,{children:(0,a.jsx)(r.A,{})})]})}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2664.509e3099.js b/pr-preview/pr-1071/assets/js/2664.509e3099.js deleted file mode 100644 index 6f0cf05b80..0000000000 --- a/pr-preview/pr-1071/assets/js/2664.509e3099.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2664],{82664:(t,e,a)=>{a.d(e,{diagram:()=>Nt});var n=a(83814),i=a(8159),r=a(10009),s=a(20007),l=a(16750),o=function(){var t=(0,r.K2)((function(t,e,a,n){for(a=a||{},n=t.length;n--;a[t[n]]=e);return a}),"o"),e=[1,24],a=[1,25],n=[1,26],i=[1,27],s=[1,28],l=[1,63],o=[1,64],h=[1,65],d=[1,66],u=[1,67],p=[1,68],y=[1,69],g=[1,29],f=[1,30],b=[1,31],x=[1,32],_=[1,33],m=[1,34],E=[1,35],S=[1,36],A=[1,37],C=[1,38],w=[1,39],k=[1,40],O=[1,41],T=[1,42],v=[1,43],R=[1,44],D=[1,45],N=[1,46],P=[1,47],B=[1,48],I=[1,50],M=[1,51],j=[1,52],K=[1,53],L=[1,54],Y=[1,55],U=[1,56],F=[1,57],X=[1,58],z=[1,59],W=[1,60],Q=[14,42],$=[14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],H=[12,14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],q=[1,82],V=[1,83],G=[1,84],J=[1,85],Z=[12,14,42],tt=[12,14,33,42],et=[12,14,33,42,76,77,79,80],at=[12,33],nt=[34,36,37,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],it={trace:(0,r.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,direction_tb:6,direction_bt:7,direction_rl:8,direction_lr:9,graphConfig:10,C4_CONTEXT:11,NEWLINE:12,statements:13,EOF:14,C4_CONTAINER:15,C4_COMPONENT:16,C4_DYNAMIC:17,C4_DEPLOYMENT:18,otherStatements:19,diagramStatements:20,otherStatement:21,title:22,accDescription:23,acc_title:24,acc_title_value:25,acc_descr:26,acc_descr_value:27,acc_descr_multiline_value:28,boundaryStatement:29,boundaryStartStatement:30,boundaryStopStatement:31,boundaryStart:32,LBRACE:33,ENTERPRISE_BOUNDARY:34,attributes:35,SYSTEM_BOUNDARY:36,BOUNDARY:37,CONTAINER_BOUNDARY:38,NODE:39,NODE_L:40,NODE_R:41,RBRACE:42,diagramStatement:43,PERSON:44,PERSON_EXT:45,SYSTEM:46,SYSTEM_DB:47,SYSTEM_QUEUE:48,SYSTEM_EXT:49,SYSTEM_EXT_DB:50,SYSTEM_EXT_QUEUE:51,CONTAINER:52,CONTAINER_DB:53,CONTAINER_QUEUE:54,CONTAINER_EXT:55,CONTAINER_EXT_DB:56,CONTAINER_EXT_QUEUE:57,COMPONENT:58,COMPONENT_DB:59,COMPONENT_QUEUE:60,COMPONENT_EXT:61,COMPONENT_EXT_DB:62,COMPONENT_EXT_QUEUE:63,REL:64,BIREL:65,REL_U:66,REL_D:67,REL_L:68,REL_R:69,REL_B:70,REL_INDEX:71,UPDATE_EL_STYLE:72,UPDATE_REL_STYLE:73,UPDATE_LAYOUT_CONFIG:74,attribute:75,STR:76,STR_KEY:77,STR_VALUE:78,ATTRIBUTE:79,ATTRIBUTE_EMPTY:80,$accept:0,$end:1},terminals_:{2:"error",6:"direction_tb",7:"direction_bt",8:"direction_rl",9:"direction_lr",11:"C4_CONTEXT",12:"NEWLINE",14:"EOF",15:"C4_CONTAINER",16:"C4_COMPONENT",17:"C4_DYNAMIC",18:"C4_DEPLOYMENT",22:"title",23:"accDescription",24:"acc_title",25:"acc_title_value",26:"acc_descr",27:"acc_descr_value",28:"acc_descr_multiline_value",33:"LBRACE",34:"ENTERPRISE_BOUNDARY",36:"SYSTEM_BOUNDARY",37:"BOUNDARY",38:"CONTAINER_BOUNDARY",39:"NODE",40:"NODE_L",41:"NODE_R",42:"RBRACE",44:"PERSON",45:"PERSON_EXT",46:"SYSTEM",47:"SYSTEM_DB",48:"SYSTEM_QUEUE",49:"SYSTEM_EXT",50:"SYSTEM_EXT_DB",51:"SYSTEM_EXT_QUEUE",52:"CONTAINER",53:"CONTAINER_DB",54:"CONTAINER_QUEUE",55:"CONTAINER_EXT",56:"CONTAINER_EXT_DB",57:"CONTAINER_EXT_QUEUE",58:"COMPONENT",59:"COMPONENT_DB",60:"COMPONENT_QUEUE",61:"COMPONENT_EXT",62:"COMPONENT_EXT_DB",63:"COMPONENT_EXT_QUEUE",64:"REL",65:"BIREL",66:"REL_U",67:"REL_D",68:"REL_L",69:"REL_R",70:"REL_B",71:"REL_INDEX",72:"UPDATE_EL_STYLE",73:"UPDATE_REL_STYLE",74:"UPDATE_LAYOUT_CONFIG",76:"STR",77:"STR_KEY",78:"STR_VALUE",79:"ATTRIBUTE",80:"ATTRIBUTE_EMPTY"},productions_:[0,[3,1],[3,1],[5,1],[5,1],[5,1],[5,1],[4,1],[10,4],[10,4],[10,4],[10,4],[10,4],[13,1],[13,1],[13,2],[19,1],[19,2],[19,3],[21,1],[21,1],[21,2],[21,2],[21,1],[29,3],[30,3],[30,3],[30,4],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[31,1],[20,1],[20,2],[20,3],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,1],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[35,1],[35,2],[75,1],[75,2],[75,1],[75,1]],performAction:(0,r.K2)((function(t,e,a,n,i,r,s){var l=r.length-1;switch(i){case 3:n.setDirection("TB");break;case 4:n.setDirection("BT");break;case 5:n.setDirection("RL");break;case 6:n.setDirection("LR");break;case 8:case 9:case 10:case 11:case 12:n.setC4Type(r[l-3]);break;case 19:n.setTitle(r[l].substring(6)),this.$=r[l].substring(6);break;case 20:n.setAccDescription(r[l].substring(15)),this.$=r[l].substring(15);break;case 21:this.$=r[l].trim(),n.setTitle(this.$);break;case 22:case 23:this.$=r[l].trim(),n.setAccDescription(this.$);break;case 28:r[l].splice(2,0,"ENTERPRISE"),n.addPersonOrSystemBoundary(...r[l]),this.$=r[l];break;case 29:r[l].splice(2,0,"SYSTEM"),n.addPersonOrSystemBoundary(...r[l]),this.$=r[l];break;case 30:n.addPersonOrSystemBoundary(...r[l]),this.$=r[l];break;case 31:r[l].splice(2,0,"CONTAINER"),n.addContainerBoundary(...r[l]),this.$=r[l];break;case 32:n.addDeploymentNode("node",...r[l]),this.$=r[l];break;case 33:n.addDeploymentNode("nodeL",...r[l]),this.$=r[l];break;case 34:n.addDeploymentNode("nodeR",...r[l]),this.$=r[l];break;case 35:n.popBoundaryParseStack();break;case 39:n.addPersonOrSystem("person",...r[l]),this.$=r[l];break;case 40:n.addPersonOrSystem("external_person",...r[l]),this.$=r[l];break;case 41:n.addPersonOrSystem("system",...r[l]),this.$=r[l];break;case 42:n.addPersonOrSystem("system_db",...r[l]),this.$=r[l];break;case 43:n.addPersonOrSystem("system_queue",...r[l]),this.$=r[l];break;case 44:n.addPersonOrSystem("external_system",...r[l]),this.$=r[l];break;case 45:n.addPersonOrSystem("external_system_db",...r[l]),this.$=r[l];break;case 46:n.addPersonOrSystem("external_system_queue",...r[l]),this.$=r[l];break;case 47:n.addContainer("container",...r[l]),this.$=r[l];break;case 48:n.addContainer("container_db",...r[l]),this.$=r[l];break;case 49:n.addContainer("container_queue",...r[l]),this.$=r[l];break;case 50:n.addContainer("external_container",...r[l]),this.$=r[l];break;case 51:n.addContainer("external_container_db",...r[l]),this.$=r[l];break;case 52:n.addContainer("external_container_queue",...r[l]),this.$=r[l];break;case 53:n.addComponent("component",...r[l]),this.$=r[l];break;case 54:n.addComponent("component_db",...r[l]),this.$=r[l];break;case 55:n.addComponent("component_queue",...r[l]),this.$=r[l];break;case 56:n.addComponent("external_component",...r[l]),this.$=r[l];break;case 57:n.addComponent("external_component_db",...r[l]),this.$=r[l];break;case 58:n.addComponent("external_component_queue",...r[l]),this.$=r[l];break;case 60:n.addRel("rel",...r[l]),this.$=r[l];break;case 61:n.addRel("birel",...r[l]),this.$=r[l];break;case 62:n.addRel("rel_u",...r[l]),this.$=r[l];break;case 63:n.addRel("rel_d",...r[l]),this.$=r[l];break;case 64:n.addRel("rel_l",...r[l]),this.$=r[l];break;case 65:n.addRel("rel_r",...r[l]),this.$=r[l];break;case 66:n.addRel("rel_b",...r[l]),this.$=r[l];break;case 67:r[l].splice(0,1),n.addRel("rel",...r[l]),this.$=r[l];break;case 68:n.updateElStyle("update_el_style",...r[l]),this.$=r[l];break;case 69:n.updateRelStyle("update_rel_style",...r[l]),this.$=r[l];break;case 70:n.updateLayoutConfig("update_layout_config",...r[l]),this.$=r[l];break;case 71:this.$=[r[l]];break;case 72:r[l].unshift(r[l-1]),this.$=r[l];break;case 73:case 75:this.$=r[l].trim();break;case 74:let t={};t[r[l-1].trim()]=r[l].trim(),this.$=t;break;case 76:this.$=""}}),"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],7:[1,6],8:[1,7],9:[1,8],10:4,11:[1,9],15:[1,10],16:[1,11],17:[1,12],18:[1,13]},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,7]},{1:[2,3]},{1:[2,4]},{1:[2,5]},{1:[2,6]},{12:[1,14]},{12:[1,15]},{12:[1,16]},{12:[1,17]},{12:[1,18]},{13:19,19:20,20:21,21:22,22:e,23:a,24:n,26:i,28:s,29:49,30:61,32:62,34:l,36:o,37:h,38:d,39:u,40:p,41:y,43:23,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W},{13:70,19:20,20:21,21:22,22:e,23:a,24:n,26:i,28:s,29:49,30:61,32:62,34:l,36:o,37:h,38:d,39:u,40:p,41:y,43:23,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W},{13:71,19:20,20:21,21:22,22:e,23:a,24:n,26:i,28:s,29:49,30:61,32:62,34:l,36:o,37:h,38:d,39:u,40:p,41:y,43:23,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W},{13:72,19:20,20:21,21:22,22:e,23:a,24:n,26:i,28:s,29:49,30:61,32:62,34:l,36:o,37:h,38:d,39:u,40:p,41:y,43:23,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W},{13:73,19:20,20:21,21:22,22:e,23:a,24:n,26:i,28:s,29:49,30:61,32:62,34:l,36:o,37:h,38:d,39:u,40:p,41:y,43:23,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W},{14:[1,74]},t(Q,[2,13],{43:23,29:49,30:61,32:62,20:75,34:l,36:o,37:h,38:d,39:u,40:p,41:y,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W}),t(Q,[2,14]),t($,[2,16],{12:[1,76]}),t(Q,[2,36],{12:[1,77]}),t(H,[2,19]),t(H,[2,20]),{25:[1,78]},{27:[1,79]},t(H,[2,23]),{35:80,75:81,76:q,77:V,79:G,80:J},{35:86,75:81,76:q,77:V,79:G,80:J},{35:87,75:81,76:q,77:V,79:G,80:J},{35:88,75:81,76:q,77:V,79:G,80:J},{35:89,75:81,76:q,77:V,79:G,80:J},{35:90,75:81,76:q,77:V,79:G,80:J},{35:91,75:81,76:q,77:V,79:G,80:J},{35:92,75:81,76:q,77:V,79:G,80:J},{35:93,75:81,76:q,77:V,79:G,80:J},{35:94,75:81,76:q,77:V,79:G,80:J},{35:95,75:81,76:q,77:V,79:G,80:J},{35:96,75:81,76:q,77:V,79:G,80:J},{35:97,75:81,76:q,77:V,79:G,80:J},{35:98,75:81,76:q,77:V,79:G,80:J},{35:99,75:81,76:q,77:V,79:G,80:J},{35:100,75:81,76:q,77:V,79:G,80:J},{35:101,75:81,76:q,77:V,79:G,80:J},{35:102,75:81,76:q,77:V,79:G,80:J},{35:103,75:81,76:q,77:V,79:G,80:J},{35:104,75:81,76:q,77:V,79:G,80:J},t(Z,[2,59]),{35:105,75:81,76:q,77:V,79:G,80:J},{35:106,75:81,76:q,77:V,79:G,80:J},{35:107,75:81,76:q,77:V,79:G,80:J},{35:108,75:81,76:q,77:V,79:G,80:J},{35:109,75:81,76:q,77:V,79:G,80:J},{35:110,75:81,76:q,77:V,79:G,80:J},{35:111,75:81,76:q,77:V,79:G,80:J},{35:112,75:81,76:q,77:V,79:G,80:J},{35:113,75:81,76:q,77:V,79:G,80:J},{35:114,75:81,76:q,77:V,79:G,80:J},{35:115,75:81,76:q,77:V,79:G,80:J},{20:116,29:49,30:61,32:62,34:l,36:o,37:h,38:d,39:u,40:p,41:y,43:23,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W},{12:[1,118],33:[1,117]},{35:119,75:81,76:q,77:V,79:G,80:J},{35:120,75:81,76:q,77:V,79:G,80:J},{35:121,75:81,76:q,77:V,79:G,80:J},{35:122,75:81,76:q,77:V,79:G,80:J},{35:123,75:81,76:q,77:V,79:G,80:J},{35:124,75:81,76:q,77:V,79:G,80:J},{35:125,75:81,76:q,77:V,79:G,80:J},{14:[1,126]},{14:[1,127]},{14:[1,128]},{14:[1,129]},{1:[2,8]},t(Q,[2,15]),t($,[2,17],{21:22,19:130,22:e,23:a,24:n,26:i,28:s}),t(Q,[2,37],{19:20,20:21,21:22,43:23,29:49,30:61,32:62,13:131,22:e,23:a,24:n,26:i,28:s,34:l,36:o,37:h,38:d,39:u,40:p,41:y,44:g,45:f,46:b,47:x,48:_,49:m,50:E,51:S,52:A,53:C,54:w,55:k,56:O,57:T,58:v,59:R,60:D,61:N,62:P,63:B,64:I,65:M,66:j,67:K,68:L,69:Y,70:U,71:F,72:X,73:z,74:W}),t(H,[2,21]),t(H,[2,22]),t(Z,[2,39]),t(tt,[2,71],{75:81,35:132,76:q,77:V,79:G,80:J}),t(et,[2,73]),{78:[1,133]},t(et,[2,75]),t(et,[2,76]),t(Z,[2,40]),t(Z,[2,41]),t(Z,[2,42]),t(Z,[2,43]),t(Z,[2,44]),t(Z,[2,45]),t(Z,[2,46]),t(Z,[2,47]),t(Z,[2,48]),t(Z,[2,49]),t(Z,[2,50]),t(Z,[2,51]),t(Z,[2,52]),t(Z,[2,53]),t(Z,[2,54]),t(Z,[2,55]),t(Z,[2,56]),t(Z,[2,57]),t(Z,[2,58]),t(Z,[2,60]),t(Z,[2,61]),t(Z,[2,62]),t(Z,[2,63]),t(Z,[2,64]),t(Z,[2,65]),t(Z,[2,66]),t(Z,[2,67]),t(Z,[2,68]),t(Z,[2,69]),t(Z,[2,70]),{31:134,42:[1,135]},{12:[1,136]},{33:[1,137]},t(at,[2,28]),t(at,[2,29]),t(at,[2,30]),t(at,[2,31]),t(at,[2,32]),t(at,[2,33]),t(at,[2,34]),{1:[2,9]},{1:[2,10]},{1:[2,11]},{1:[2,12]},t($,[2,18]),t(Q,[2,38]),t(tt,[2,72]),t(et,[2,74]),t(Z,[2,24]),t(Z,[2,35]),t(nt,[2,25]),t(nt,[2,26],{12:[1,138]}),t(nt,[2,27])],defaultActions:{2:[2,1],3:[2,2],4:[2,7],5:[2,3],6:[2,4],7:[2,5],8:[2,6],74:[2,8],126:[2,9],127:[2,10],128:[2,11],129:[2,12]},parseError:(0,r.K2)((function(t,e){if(!e.recoverable){var a=new Error(t);throw a.hash=e,a}this.trace(t)}),"parseError"),parse:(0,r.K2)((function(t){var e=this,a=[0],n=[],i=[null],s=[],l=this.table,o="",c=0,h=0,d=0,u=s.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var f=p.yylloc;s.push(f);var b=p.options&&p.options.ranges;function x(){var t;return"number"!=typeof(t=n.pop()||p.lex()||1)&&(t instanceof Array&&(t=(n=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,r.K2)((function(t){a.length=a.length-2*t,i.length=i.length-t,s.length=s.length-t}),"popStack"),(0,r.K2)(x,"lex");for(var _,m,E,S,A,C,w,k,O,T={};;){if(E=a[a.length-1],this.defaultActions[E]?S=this.defaultActions[E]:(null==_&&(_=x()),S=l[E]&&l[E][_]),void 0===S||!S.length||!S[0]){var v="";for(C in O=[],l[E])this.terminals_[C]&&C>2&&O.push("'"+this.terminals_[C]+"'");v=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+O.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(1==_?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(v,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:f,expected:O})}if(S[0]instanceof Array&&S.length>1)throw new Error("Parse Error: multiple actions possible at state: "+E+", token: "+_);switch(S[0]){case 1:a.push(_),i.push(p.yytext),s.push(p.yylloc),a.push(S[1]),_=null,m?(_=m,m=null):(h=p.yyleng,o=p.yytext,c=p.yylineno,f=p.yylloc,d>0&&d--);break;case 2:if(w=this.productions_[S[1]][1],T.$=i[i.length-w],T._$={first_line:s[s.length-(w||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(w||1)].first_column,last_column:s[s.length-1].last_column},b&&(T._$.range=[s[s.length-(w||1)].range[0],s[s.length-1].range[1]]),void 0!==(A=this.performAction.apply(T,[o,h,c,y.yy,S[1],i,s].concat(u))))return A;w&&(a=a.slice(0,-1*w*2),i=i.slice(0,-1*w),s=s.slice(0,-1*w)),a.push(this.productions_[S[1]][0]),i.push(T.$),s.push(T._$),k=l[a[a.length-2]][a[a.length-1]],a.push(k);break;case 3:return!0}}return!0}),"parse")},rt=function(){return{EOF:1,parseError:(0,r.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,r.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,r.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,r.K2)((function(t){var e=t.length,a=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),a.length-1&&(this.yylineno-=a.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:a?(a.length===n.length?this.yylloc.first_column:0)+n[n.length-a.length].length-a[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,r.K2)((function(){return this._more=!0,this}),"more"),reject:(0,r.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,r.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,r.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,r.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,r.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,r.K2)((function(t,e){var a,n,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(n=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=n.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-n[n.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],a=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a)return a;if(this._backtrack){for(var r in i)this[r]=i[r];return!1}return!1}),"test_match"),next:(0,r.K2)((function(){if(this.done)return this.EOF;var t,e,a,n;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),r=0;re[0].length)){if(e=a,n=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(a,i[r])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[n]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,r.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,r.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,r.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,r.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,r.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,r.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,r.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{},performAction:(0,r.K2)((function(t,e,a,n){switch(a){case 0:return 6;case 1:return 7;case 2:return 8;case 3:return 9;case 4:return 22;case 5:return 23;case 6:return this.begin("acc_title"),24;case 7:return this.popState(),"acc_title_value";case 8:return this.begin("acc_descr"),26;case 9:return this.popState(),"acc_descr_value";case 10:this.begin("acc_descr_multiline");break;case 11:case 73:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:case 16:case 70:break;case 14:c;break;case 15:return 12;case 17:return 11;case 18:return 15;case 19:return 16;case 20:return 17;case 21:return 18;case 22:return this.begin("person_ext"),45;case 23:return this.begin("person"),44;case 24:return this.begin("system_ext_queue"),51;case 25:return this.begin("system_ext_db"),50;case 26:return this.begin("system_ext"),49;case 27:return this.begin("system_queue"),48;case 28:return this.begin("system_db"),47;case 29:return this.begin("system"),46;case 30:return this.begin("boundary"),37;case 31:return this.begin("enterprise_boundary"),34;case 32:return this.begin("system_boundary"),36;case 33:return this.begin("container_ext_queue"),57;case 34:return this.begin("container_ext_db"),56;case 35:return this.begin("container_ext"),55;case 36:return this.begin("container_queue"),54;case 37:return this.begin("container_db"),53;case 38:return this.begin("container"),52;case 39:return this.begin("container_boundary"),38;case 40:return this.begin("component_ext_queue"),63;case 41:return this.begin("component_ext_db"),62;case 42:return this.begin("component_ext"),61;case 43:return this.begin("component_queue"),60;case 44:return this.begin("component_db"),59;case 45:return this.begin("component"),58;case 46:case 47:return this.begin("node"),39;case 48:return this.begin("node_l"),40;case 49:return this.begin("node_r"),41;case 50:return this.begin("rel"),64;case 51:return this.begin("birel"),65;case 52:case 53:return this.begin("rel_u"),66;case 54:case 55:return this.begin("rel_d"),67;case 56:case 57:return this.begin("rel_l"),68;case 58:case 59:return this.begin("rel_r"),69;case 60:return this.begin("rel_b"),70;case 61:return this.begin("rel_index"),71;case 62:return this.begin("update_el_style"),72;case 63:return this.begin("update_rel_style"),73;case 64:return this.begin("update_layout_config"),74;case 65:return"EOF_IN_STRUCT";case 66:return this.begin("attribute"),"ATTRIBUTE_EMPTY";case 67:this.begin("attribute");break;case 68:case 79:this.popState(),this.popState();break;case 69:case 71:return 80;case 72:this.begin("string");break;case 74:case 80:return"STR";case 75:this.begin("string_kv");break;case 76:return this.begin("string_kv_key"),"STR_KEY";case 77:this.popState(),this.begin("string_kv_value");break;case 78:return"STR_VALUE";case 81:return"LBRACE";case 82:return"RBRACE";case 83:return"SPACE";case 84:return"EOL";case 85:return 14}}),"anonymous"),rules:[/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:title\s[^#\n;]+)/,/^(?:accDescription\s[^#\n;]+)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:C4Context\b)/,/^(?:C4Container\b)/,/^(?:C4Component\b)/,/^(?:C4Dynamic\b)/,/^(?:C4Deployment\b)/,/^(?:Person_Ext\b)/,/^(?:Person\b)/,/^(?:SystemQueue_Ext\b)/,/^(?:SystemDb_Ext\b)/,/^(?:System_Ext\b)/,/^(?:SystemQueue\b)/,/^(?:SystemDb\b)/,/^(?:System\b)/,/^(?:Boundary\b)/,/^(?:Enterprise_Boundary\b)/,/^(?:System_Boundary\b)/,/^(?:ContainerQueue_Ext\b)/,/^(?:ContainerDb_Ext\b)/,/^(?:Container_Ext\b)/,/^(?:ContainerQueue\b)/,/^(?:ContainerDb\b)/,/^(?:Container\b)/,/^(?:Container_Boundary\b)/,/^(?:ComponentQueue_Ext\b)/,/^(?:ComponentDb_Ext\b)/,/^(?:Component_Ext\b)/,/^(?:ComponentQueue\b)/,/^(?:ComponentDb\b)/,/^(?:Component\b)/,/^(?:Deployment_Node\b)/,/^(?:Node\b)/,/^(?:Node_L\b)/,/^(?:Node_R\b)/,/^(?:Rel\b)/,/^(?:BiRel\b)/,/^(?:Rel_Up\b)/,/^(?:Rel_U\b)/,/^(?:Rel_Down\b)/,/^(?:Rel_D\b)/,/^(?:Rel_Left\b)/,/^(?:Rel_L\b)/,/^(?:Rel_Right\b)/,/^(?:Rel_R\b)/,/^(?:Rel_Back\b)/,/^(?:RelIndex\b)/,/^(?:UpdateElementStyle\b)/,/^(?:UpdateRelStyle\b)/,/^(?:UpdateLayoutConfig\b)/,/^(?:$)/,/^(?:[(][ ]*[,])/,/^(?:[(])/,/^(?:[)])/,/^(?:,,)/,/^(?:,)/,/^(?:[ ]*["]["])/,/^(?:[ ]*["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:[ ]*[\$])/,/^(?:[^=]*)/,/^(?:[=][ ]*["])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:[^,]+)/,/^(?:\{)/,/^(?:\})/,/^(?:[\s]+)/,/^(?:[\n\r]+)/,/^(?:$)/],conditions:{acc_descr_multiline:{rules:[11,12],inclusive:!1},acc_descr:{rules:[9],inclusive:!1},acc_title:{rules:[7],inclusive:!1},string_kv_value:{rules:[78,79],inclusive:!1},string_kv_key:{rules:[77],inclusive:!1},string_kv:{rules:[76],inclusive:!1},string:{rules:[73,74],inclusive:!1},attribute:{rules:[68,69,70,71,72,75,80],inclusive:!1},update_layout_config:{rules:[65,66,67,68],inclusive:!1},update_rel_style:{rules:[65,66,67,68],inclusive:!1},update_el_style:{rules:[65,66,67,68],inclusive:!1},rel_b:{rules:[65,66,67,68],inclusive:!1},rel_r:{rules:[65,66,67,68],inclusive:!1},rel_l:{rules:[65,66,67,68],inclusive:!1},rel_d:{rules:[65,66,67,68],inclusive:!1},rel_u:{rules:[65,66,67,68],inclusive:!1},rel_bi:{rules:[],inclusive:!1},rel:{rules:[65,66,67,68],inclusive:!1},node_r:{rules:[65,66,67,68],inclusive:!1},node_l:{rules:[65,66,67,68],inclusive:!1},node:{rules:[65,66,67,68],inclusive:!1},index:{rules:[],inclusive:!1},rel_index:{rules:[65,66,67,68],inclusive:!1},component_ext_queue:{rules:[],inclusive:!1},component_ext_db:{rules:[65,66,67,68],inclusive:!1},component_ext:{rules:[65,66,67,68],inclusive:!1},component_queue:{rules:[65,66,67,68],inclusive:!1},component_db:{rules:[65,66,67,68],inclusive:!1},component:{rules:[65,66,67,68],inclusive:!1},container_boundary:{rules:[65,66,67,68],inclusive:!1},container_ext_queue:{rules:[65,66,67,68],inclusive:!1},container_ext_db:{rules:[65,66,67,68],inclusive:!1},container_ext:{rules:[65,66,67,68],inclusive:!1},container_queue:{rules:[65,66,67,68],inclusive:!1},container_db:{rules:[65,66,67,68],inclusive:!1},container:{rules:[65,66,67,68],inclusive:!1},birel:{rules:[65,66,67,68],inclusive:!1},system_boundary:{rules:[65,66,67,68],inclusive:!1},enterprise_boundary:{rules:[65,66,67,68],inclusive:!1},boundary:{rules:[65,66,67,68],inclusive:!1},system_ext_queue:{rules:[65,66,67,68],inclusive:!1},system_ext_db:{rules:[65,66,67,68],inclusive:!1},system_ext:{rules:[65,66,67,68],inclusive:!1},system_queue:{rules:[65,66,67,68],inclusive:!1},system_db:{rules:[65,66,67,68],inclusive:!1},system:{rules:[65,66,67,68],inclusive:!1},person_ext:{rules:[65,66,67,68],inclusive:!1},person:{rules:[65,66,67,68],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,8,10,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,81,82,83,84,85],inclusive:!0}}}}();function st(){this.yy={}}return it.lexer=rt,(0,r.K2)(st,"Parser"),st.prototype=it,it.Parser=st,new st}();o.parser=o;var h,d=o,u=[],p=[""],y="global",g="",f=[{alias:"global",label:{text:"global"},type:{text:"global"},tags:null,link:null,parentBoundary:""}],b=[],x="",_=!1,m=4,E=2,S=(0,r.K2)((function(){return h}),"getC4Type"),A=(0,r.K2)((function(t){let e=(0,r.jZ)(t,(0,r.D7)());h=e}),"setC4Type"),C=(0,r.K2)((function(t,e,a,n,i,r,s,l,o){if(null==t||null==e||null==a||null==n)return;let c={};const h=b.find((t=>t.from===e&&t.to===a));if(h?c=h:b.push(c),c.type=t,c.from=e,c.to=a,c.label={text:n},null==i)c.techn={text:""};else if("object"==typeof i){let[t,e]=Object.entries(i)[0];c[t]={text:e}}else c.techn={text:i};if(null==r)c.descr={text:""};else if("object"==typeof r){let[t,e]=Object.entries(r)[0];c[t]={text:e}}else c.descr={text:r};if("object"==typeof s){let[t,e]=Object.entries(s)[0];c[t]=e}else c.sprite=s;if("object"==typeof l){let[t,e]=Object.entries(l)[0];c[t]=e}else c.tags=l;if("object"==typeof o){let[t,e]=Object.entries(o)[0];c[t]=e}else c.link=o;c.wrap=$()}),"addRel"),w=(0,r.K2)((function(t,e,a,n,i,r,s){if(null===e||null===a)return;let l={};const o=u.find((t=>t.alias===e));if(o&&e===o.alias?l=o:(l.alias=e,u.push(l)),l.label=null==a?{text:""}:{text:a},null==n)l.descr={text:""};else if("object"==typeof n){let[t,e]=Object.entries(n)[0];l[t]={text:e}}else l.descr={text:n};if("object"==typeof i){let[t,e]=Object.entries(i)[0];l[t]=e}else l.sprite=i;if("object"==typeof r){let[t,e]=Object.entries(r)[0];l[t]=e}else l.tags=r;if("object"==typeof s){let[t,e]=Object.entries(s)[0];l[t]=e}else l.link=s;l.typeC4Shape={text:t},l.parentBoundary=y,l.wrap=$()}),"addPersonOrSystem"),k=(0,r.K2)((function(t,e,a,n,i,r,s,l){if(null===e||null===a)return;let o={};const c=u.find((t=>t.alias===e));if(c&&e===c.alias?o=c:(o.alias=e,u.push(o)),o.label=null==a?{text:""}:{text:a},null==n)o.techn={text:""};else if("object"==typeof n){let[t,e]=Object.entries(n)[0];o[t]={text:e}}else o.techn={text:n};if(null==i)o.descr={text:""};else if("object"==typeof i){let[t,e]=Object.entries(i)[0];o[t]={text:e}}else o.descr={text:i};if("object"==typeof r){let[t,e]=Object.entries(r)[0];o[t]=e}else o.sprite=r;if("object"==typeof s){let[t,e]=Object.entries(s)[0];o[t]=e}else o.tags=s;if("object"==typeof l){let[t,e]=Object.entries(l)[0];o[t]=e}else o.link=l;o.wrap=$(),o.typeC4Shape={text:t},o.parentBoundary=y}),"addContainer"),O=(0,r.K2)((function(t,e,a,n,i,r,s,l){if(null===e||null===a)return;let o={};const c=u.find((t=>t.alias===e));if(c&&e===c.alias?o=c:(o.alias=e,u.push(o)),o.label=null==a?{text:""}:{text:a},null==n)o.techn={text:""};else if("object"==typeof n){let[t,e]=Object.entries(n)[0];o[t]={text:e}}else o.techn={text:n};if(null==i)o.descr={text:""};else if("object"==typeof i){let[t,e]=Object.entries(i)[0];o[t]={text:e}}else o.descr={text:i};if("object"==typeof r){let[t,e]=Object.entries(r)[0];o[t]=e}else o.sprite=r;if("object"==typeof s){let[t,e]=Object.entries(s)[0];o[t]=e}else o.tags=s;if("object"==typeof l){let[t,e]=Object.entries(l)[0];o[t]=e}else o.link=l;o.wrap=$(),o.typeC4Shape={text:t},o.parentBoundary=y}),"addComponent"),T=(0,r.K2)((function(t,e,a,n,i){if(null===t||null===e)return;let r={};const s=f.find((e=>e.alias===t));if(s&&t===s.alias?r=s:(r.alias=t,f.push(r)),r.label=null==e?{text:""}:{text:e},null==a)r.type={text:"system"};else if("object"==typeof a){let[t,e]=Object.entries(a)[0];r[t]={text:e}}else r.type={text:a};if("object"==typeof n){let[t,e]=Object.entries(n)[0];r[t]=e}else r.tags=n;if("object"==typeof i){let[t,e]=Object.entries(i)[0];r[t]=e}else r.link=i;r.parentBoundary=y,r.wrap=$(),g=y,y=t,p.push(g)}),"addPersonOrSystemBoundary"),v=(0,r.K2)((function(t,e,a,n,i){if(null===t||null===e)return;let r={};const s=f.find((e=>e.alias===t));if(s&&t===s.alias?r=s:(r.alias=t,f.push(r)),r.label=null==e?{text:""}:{text:e},null==a)r.type={text:"container"};else if("object"==typeof a){let[t,e]=Object.entries(a)[0];r[t]={text:e}}else r.type={text:a};if("object"==typeof n){let[t,e]=Object.entries(n)[0];r[t]=e}else r.tags=n;if("object"==typeof i){let[t,e]=Object.entries(i)[0];r[t]=e}else r.link=i;r.parentBoundary=y,r.wrap=$(),g=y,y=t,p.push(g)}),"addContainerBoundary"),R=(0,r.K2)((function(t,e,a,n,i,r,s,l){if(null===e||null===a)return;let o={};const c=f.find((t=>t.alias===e));if(c&&e===c.alias?o=c:(o.alias=e,f.push(o)),o.label=null==a?{text:""}:{text:a},null==n)o.type={text:"node"};else if("object"==typeof n){let[t,e]=Object.entries(n)[0];o[t]={text:e}}else o.type={text:n};if(null==i)o.descr={text:""};else if("object"==typeof i){let[t,e]=Object.entries(i)[0];o[t]={text:e}}else o.descr={text:i};if("object"==typeof s){let[t,e]=Object.entries(s)[0];o[t]=e}else o.tags=s;if("object"==typeof l){let[t,e]=Object.entries(l)[0];o[t]=e}else o.link=l;o.nodeType=t,o.parentBoundary=y,o.wrap=$(),g=y,y=e,p.push(g)}),"addDeploymentNode"),D=(0,r.K2)((function(){y=g,p.pop(),g=p.pop(),p.push(g)}),"popBoundaryParseStack"),N=(0,r.K2)((function(t,e,a,n,i,r,s,l,o,c,h){let d=u.find((t=>t.alias===e));if(void 0!==d||(d=f.find((t=>t.alias===e)),void 0!==d)){if(null!=a)if("object"==typeof a){let[t,e]=Object.entries(a)[0];d[t]=e}else d.bgColor=a;if(null!=n)if("object"==typeof n){let[t,e]=Object.entries(n)[0];d[t]=e}else d.fontColor=n;if(null!=i)if("object"==typeof i){let[t,e]=Object.entries(i)[0];d[t]=e}else d.borderColor=i;if(null!=r)if("object"==typeof r){let[t,e]=Object.entries(r)[0];d[t]=e}else d.shadowing=r;if(null!=s)if("object"==typeof s){let[t,e]=Object.entries(s)[0];d[t]=e}else d.shape=s;if(null!=l)if("object"==typeof l){let[t,e]=Object.entries(l)[0];d[t]=e}else d.sprite=l;if(null!=o)if("object"==typeof o){let[t,e]=Object.entries(o)[0];d[t]=e}else d.techn=o;if(null!=c)if("object"==typeof c){let[t,e]=Object.entries(c)[0];d[t]=e}else d.legendText=c;if(null!=h)if("object"==typeof h){let[t,e]=Object.entries(h)[0];d[t]=e}else d.legendSprite=h}}),"updateElStyle"),P=(0,r.K2)((function(t,e,a,n,i,r,s){const l=b.find((t=>t.from===e&&t.to===a));if(void 0!==l){if(null!=n)if("object"==typeof n){let[t,e]=Object.entries(n)[0];l[t]=e}else l.textColor=n;if(null!=i)if("object"==typeof i){let[t,e]=Object.entries(i)[0];l[t]=e}else l.lineColor=i;if(null!=r)if("object"==typeof r){let[t,e]=Object.entries(r)[0];l[t]=parseInt(e)}else l.offsetX=parseInt(r);if(null!=s)if("object"==typeof s){let[t,e]=Object.entries(s)[0];l[t]=parseInt(e)}else l.offsetY=parseInt(s)}}),"updateRelStyle"),B=(0,r.K2)((function(t,e,a){let n=m,i=E;if("object"==typeof e){const t=Object.values(e)[0];n=parseInt(t)}else n=parseInt(e);if("object"==typeof a){const t=Object.values(a)[0];i=parseInt(t)}else i=parseInt(a);n>=1&&(m=n),i>=1&&(E=i)}),"updateLayoutConfig"),I=(0,r.K2)((function(){return m}),"getC4ShapeInRow"),M=(0,r.K2)((function(){return E}),"getC4BoundaryInRow"),j=(0,r.K2)((function(){return y}),"getCurrentBoundaryParse"),K=(0,r.K2)((function(){return g}),"getParentBoundaryParse"),L=(0,r.K2)((function(t){return null==t?u:u.filter((e=>e.parentBoundary===t))}),"getC4ShapeArray"),Y=(0,r.K2)((function(t){return u.find((e=>e.alias===t))}),"getC4Shape"),U=(0,r.K2)((function(t){return Object.keys(L(t))}),"getC4ShapeKeys"),F=(0,r.K2)((function(t){return null==t?f:f.filter((e=>e.parentBoundary===t))}),"getBoundaries"),X=F,z=(0,r.K2)((function(){return b}),"getRels"),W=(0,r.K2)((function(){return x}),"getTitle"),Q=(0,r.K2)((function(t){_=t}),"setWrap"),$=(0,r.K2)((function(){return _}),"autoWrap"),H=(0,r.K2)((function(){u=[],f=[{alias:"global",label:{text:"global"},type:{text:"global"},tags:null,link:null,parentBoundary:""}],g="",y="global",p=[""],b=[],p=[""],x="",_=!1,m=4,E=2}),"clear"),q=(0,r.K2)((function(t){let e=(0,r.jZ)(t,(0,r.D7)());x=e}),"setTitle"),V={addPersonOrSystem:w,addPersonOrSystemBoundary:T,addContainer:k,addContainerBoundary:v,addComponent:O,addDeploymentNode:R,popBoundaryParseStack:D,addRel:C,updateElStyle:N,updateRelStyle:P,updateLayoutConfig:B,autoWrap:$,setWrap:Q,getC4ShapeArray:L,getC4Shape:Y,getC4ShapeKeys:U,getBoundaries:F,getBoundarys:X,getCurrentBoundaryParse:j,getParentBoundaryParse:K,getRels:z,getTitle:W,getC4Type:S,getC4ShapeInRow:I,getC4BoundaryInRow:M,setAccTitle:r.SV,getAccTitle:r.iN,getAccDescription:r.m7,setAccDescription:r.EI,getConfig:(0,r.K2)((()=>(0,r.D7)().c4),"getConfig"),clear:H,LINETYPE:{SOLID:0,DOTTED:1,NOTE:2,SOLID_CROSS:3,DOTTED_CROSS:4,SOLID_OPEN:5,DOTTED_OPEN:6,LOOP_START:10,LOOP_END:11,ALT_START:12,ALT_ELSE:13,ALT_END:14,OPT_START:15,OPT_END:16,ACTIVE_START:17,ACTIVE_END:18,PAR_START:19,PAR_AND:20,PAR_END:21,RECT_START:22,RECT_END:23,SOLID_POINT:24,DOTTED_POINT:25},ARROWTYPE:{FILLED:0,OPEN:1},PLACEMENT:{LEFTOF:0,RIGHTOF:1,OVER:2},setTitle:q,setC4Type:A},G=(0,r.K2)((function(t,e){return(0,n.tk)(t,e)}),"drawRect"),J=(0,r.K2)((function(t,e,a,n,i,r){const s=t.append("image");s.attr("width",e),s.attr("height",a),s.attr("x",n),s.attr("y",i);let o=r.startsWith("data:image/png;base64")?r:(0,l.J)(r);s.attr("xlink:href",o)}),"drawImage"),Z=(0,r.K2)(((t,e,a)=>{const n=t.append("g");let i=0;for(let r of e){let t=r.textColor?r.textColor:"#444444",e=r.lineColor?r.lineColor:"#444444",s=r.offsetX?parseInt(r.offsetX):0,l=r.offsetY?parseInt(r.offsetY):0,o="";if(0===i){let t=n.append("line");t.attr("x1",r.startPoint.x),t.attr("y1",r.startPoint.y),t.attr("x2",r.endPoint.x),t.attr("y2",r.endPoint.y),t.attr("stroke-width","1"),t.attr("stroke",e),t.style("fill","none"),"rel_b"!==r.type&&t.attr("marker-end","url("+o+"#arrowhead)"),"birel"!==r.type&&"rel_b"!==r.type||t.attr("marker-start","url("+o+"#arrowend)"),i=-1}else{let t=n.append("path");t.attr("fill","none").attr("stroke-width","1").attr("stroke",e).attr("d","Mstartx,starty Qcontrolx,controly stopx,stopy ".replaceAll("startx",r.startPoint.x).replaceAll("starty",r.startPoint.y).replaceAll("controlx",r.startPoint.x+(r.endPoint.x-r.startPoint.x)/2-(r.endPoint.x-r.startPoint.x)/4).replaceAll("controly",r.startPoint.y+(r.endPoint.y-r.startPoint.y)/2).replaceAll("stopx",r.endPoint.x).replaceAll("stopy",r.endPoint.y)),"rel_b"!==r.type&&t.attr("marker-end","url("+o+"#arrowhead)"),"birel"!==r.type&&"rel_b"!==r.type||t.attr("marker-start","url("+o+"#arrowend)")}let c=a.messageFont();dt(a)(r.label.text,n,Math.min(r.startPoint.x,r.endPoint.x)+Math.abs(r.endPoint.x-r.startPoint.x)/2+s,Math.min(r.startPoint.y,r.endPoint.y)+Math.abs(r.endPoint.y-r.startPoint.y)/2+l,r.label.width,r.label.height,{fill:t},c),r.techn&&""!==r.techn.text&&(c=a.messageFont(),dt(a)("["+r.techn.text+"]",n,Math.min(r.startPoint.x,r.endPoint.x)+Math.abs(r.endPoint.x-r.startPoint.x)/2+s,Math.min(r.startPoint.y,r.endPoint.y)+Math.abs(r.endPoint.y-r.startPoint.y)/2+a.messageFontSize+5+l,Math.max(r.label.width,r.techn.width),r.techn.height,{fill:t,"font-style":"italic"},c))}}),"drawRels"),tt=(0,r.K2)((function(t,e,a){const n=t.append("g");let i=e.bgColor?e.bgColor:"none",r=e.borderColor?e.borderColor:"#444444",s=e.fontColor?e.fontColor:"black",l={"stroke-width":1,"stroke-dasharray":"7.0,7.0"};e.nodeType&&(l={"stroke-width":1});let o={x:e.x,y:e.y,fill:i,stroke:r,width:e.width,height:e.height,rx:2.5,ry:2.5,attrs:l};G(n,o);let c=a.boundaryFont();c.fontWeight="bold",c.fontSize=c.fontSize+2,c.fontColor=s,dt(a)(e.label.text,n,e.x,e.y+e.label.Y,e.width,e.height,{fill:"#444444"},c),e.type&&""!==e.type.text&&(c=a.boundaryFont(),c.fontColor=s,dt(a)(e.type.text,n,e.x,e.y+e.type.Y,e.width,e.height,{fill:"#444444"},c)),e.descr&&""!==e.descr.text&&(c=a.boundaryFont(),c.fontSize=c.fontSize-2,c.fontColor=s,dt(a)(e.descr.text,n,e.x,e.y+e.descr.Y,e.width,e.height,{fill:"#444444"},c))}),"drawBoundary"),et=(0,r.K2)((function(t,e,a){let i=e.bgColor?e.bgColor:a[e.typeC4Shape.text+"_bg_color"],r=e.borderColor?e.borderColor:a[e.typeC4Shape.text+"_border_color"],s=e.fontColor?e.fontColor:"#FFFFFF",l="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACD0lEQVR4Xu2YoU4EMRCGT+4j8Ai8AhaH4QHgAUjQuFMECUgMIUgwJAgMhgQsAYUiJCiQIBBY+EITsjfTdme6V24v4c8vyGbb+ZjOtN0bNcvjQXmkH83WvYBWto6PLm6v7p7uH1/w2fXD+PBycX1Pv2l3IdDm/vn7x+dXQiAubRzoURa7gRZWd0iGRIiJbOnhnfYBQZNJjNbuyY2eJG8fkDE3bbG4ep6MHUAsgYxmE3nVs6VsBWJSGccsOlFPmLIViMzLOB7pCVO2AtHJMohH7Fh6zqitQK7m0rJvAVYgGcEpe//PLdDz65sM4pF9N7ICcXDKIB5Nv6j7tD0NoSdM2QrU9Gg0ewE1LqBhHR3BBdvj2vapnidjHxD/q6vd7Pvhr31AwcY8eXMTXAKECZZJFXuEq27aLgQK5uLMohCenGGuGewOxSjBvYBqeG6B+Nqiblggdjnc+ZXDy+FNFpFzw76O3UBAROuXh6FoiAcf5g9eTvUgzy0nWg6I8cXHRUpg5bOVBCo+KDpFajOf23GgPme7RSQ+lacIENUgJ6gg1k6HjgOlqnLqip4tEuhv0hNEMXUD0clyXE3p6pZA0S2nnvTlXwLJEZWlb7cTQH1+USgTN4VhAenm/wea1OCAOmqo6fE1WCb9WSKBah+rbUWPWAmE2Rvk0ApiB45eOyNAzU8xcTvj8KvkKEoOaIYeHNA3ZuygAvFMUO0AAAAASUVORK5CYII=";switch(e.typeC4Shape.text){case"person":l="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACD0lEQVR4Xu2YoU4EMRCGT+4j8Ai8AhaH4QHgAUjQuFMECUgMIUgwJAgMhgQsAYUiJCiQIBBY+EITsjfTdme6V24v4c8vyGbb+ZjOtN0bNcvjQXmkH83WvYBWto6PLm6v7p7uH1/w2fXD+PBycX1Pv2l3IdDm/vn7x+dXQiAubRzoURa7gRZWd0iGRIiJbOnhnfYBQZNJjNbuyY2eJG8fkDE3bbG4ep6MHUAsgYxmE3nVs6VsBWJSGccsOlFPmLIViMzLOB7pCVO2AtHJMohH7Fh6zqitQK7m0rJvAVYgGcEpe//PLdDz65sM4pF9N7ICcXDKIB5Nv6j7tD0NoSdM2QrU9Gg0ewE1LqBhHR3BBdvj2vapnidjHxD/q6vd7Pvhr31AwcY8eXMTXAKECZZJFXuEq27aLgQK5uLMohCenGGuGewOxSjBvYBqeG6B+Nqiblggdjnc+ZXDy+FNFpFzw76O3UBAROuXh6FoiAcf5g9eTvUgzy0nWg6I8cXHRUpg5bOVBCo+KDpFajOf23GgPme7RSQ+lacIENUgJ6gg1k6HjgOlqnLqip4tEuhv0hNEMXUD0clyXE3p6pZA0S2nnvTlXwLJEZWlb7cTQH1+USgTN4VhAenm/wea1OCAOmqo6fE1WCb9WSKBah+rbUWPWAmE2Rvk0ApiB45eOyNAzU8xcTvj8KvkKEoOaIYeHNA3ZuygAvFMUO0AAAAASUVORK5CYII=";break;case"external_person":l="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAB6ElEQVR4Xu2YLY+EMBCG9+dWr0aj0Wg0Go1Go0+j8Xdv2uTCvv1gpt0ebHKPuhDaeW4605Z9mJvx4AdXUyTUdd08z+u6flmWZRnHsWkafk9DptAwDPu+f0eAYtu2PEaGWuj5fCIZrBAC2eLBAnRCsEkkxmeaJp7iDJ2QMDdHsLg8SxKFEJaAo8lAXnmuOFIhTMpxxKATebo4UiFknuNo4OniSIXQyRxEA3YsnjGCVEjVXD7yLUAqxBGUyPv/Y4W2beMgGuS7kVQIBycH0fD+oi5pezQETxdHKmQKGk1eQEYldK+jw5GxPfZ9z7Mk0Qnhf1W1m3w//EUn5BDmSZsbR44QQLBEqrBHqOrmSKaQAxdnLArCrxZcM7A7ZKs4ioRq8LFC+NpC3WCBJsvpVw5edm9iEXFuyNfxXAgSwfrFQ1c0iNda8AdejvUgnktOtJQQxmcfFzGglc5WVCj7oDgFqU18boeFSs52CUh8LE8BIVQDT1ABrB0HtgSEYlX5doJnCwv9TXocKCaKbnwhdDKPq4lf3SwU3HLq4V/+WYhHVMa/3b4IlfyikAduCkcBc7mQ3/z/Qq/cTuikhkzB12Ae/mcJC9U+Vo8Ej1gWAtgbeGgFsAMHr50BIWOLCbezvhpBFUdY6EJuJ/QDW0XoMX60zZ0AAAAASUVORK5CYII="}const o=t.append("g");o.attr("class","person-man");const c=(0,n.PB)();switch(e.typeC4Shape.text){case"person":case"external_person":case"system":case"external_system":case"container":case"external_container":case"component":case"external_component":c.x=e.x,c.y=e.y,c.fill=i,c.width=e.width,c.height=e.height,c.stroke=r,c.rx=2.5,c.ry=2.5,c.attrs={"stroke-width":.5},G(o,c);break;case"system_db":case"external_system_db":case"container_db":case"external_container_db":case"component_db":case"external_component_db":o.append("path").attr("fill",i).attr("stroke-width","0.5").attr("stroke",r).attr("d","Mstartx,startyc0,-10 half,-10 half,-10c0,0 half,0 half,10l0,heightc0,10 -half,10 -half,10c0,0 -half,0 -half,-10l0,-height".replaceAll("startx",e.x).replaceAll("starty",e.y).replaceAll("half",e.width/2).replaceAll("height",e.height)),o.append("path").attr("fill","none").attr("stroke-width","0.5").attr("stroke",r).attr("d","Mstartx,startyc0,10 half,10 half,10c0,0 half,0 half,-10".replaceAll("startx",e.x).replaceAll("starty",e.y).replaceAll("half",e.width/2));break;case"system_queue":case"external_system_queue":case"container_queue":case"external_container_queue":case"component_queue":case"external_component_queue":o.append("path").attr("fill",i).attr("stroke-width","0.5").attr("stroke",r).attr("d","Mstartx,startylwidth,0c5,0 5,half 5,halfc0,0 0,half -5,halfl-width,0c-5,0 -5,-half -5,-halfc0,0 0,-half 5,-half".replaceAll("startx",e.x).replaceAll("starty",e.y).replaceAll("width",e.width).replaceAll("half",e.height/2)),o.append("path").attr("fill","none").attr("stroke-width","0.5").attr("stroke",r).attr("d","Mstartx,startyc-5,0 -5,half -5,halfc0,half 5,half 5,half".replaceAll("startx",e.x+e.width).replaceAll("starty",e.y).replaceAll("half",e.height/2))}let h=ht(a,e.typeC4Shape.text);switch(o.append("text").attr("fill",s).attr("font-family",h.fontFamily).attr("font-size",h.fontSize-2).attr("font-style","italic").attr("lengthAdjust","spacing").attr("textLength",e.typeC4Shape.width).attr("x",e.x+e.width/2-e.typeC4Shape.width/2).attr("y",e.y+e.typeC4Shape.Y).text("<<"+e.typeC4Shape.text+">>"),e.typeC4Shape.text){case"person":case"external_person":J(o,48,48,e.x+e.width/2-24,e.y+e.image.Y,l)}let d=a[e.typeC4Shape.text+"Font"]();return d.fontWeight="bold",d.fontSize=d.fontSize+2,d.fontColor=s,dt(a)(e.label.text,o,e.x,e.y+e.label.Y,e.width,e.height,{fill:s},d),d=a[e.typeC4Shape.text+"Font"](),d.fontColor=s,e.techn&&""!==e.techn?.text?dt(a)(e.techn.text,o,e.x,e.y+e.techn.Y,e.width,e.height,{fill:s,"font-style":"italic"},d):e.type&&""!==e.type.text&&dt(a)(e.type.text,o,e.x,e.y+e.type.Y,e.width,e.height,{fill:s,"font-style":"italic"},d),e.descr&&""!==e.descr.text&&(d=a.personFont(),d.fontColor=s,dt(a)(e.descr.text,o,e.x,e.y+e.descr.Y,e.width,e.height,{fill:s},d)),e.height}),"drawC4Shape"),at=(0,r.K2)((function(t){t.append("defs").append("symbol").attr("id","database").attr("fill-rule","evenodd").attr("clip-rule","evenodd").append("path").attr("transform","scale(.5)").attr("d","M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z")}),"insertDatabaseIcon"),nt=(0,r.K2)((function(t){t.append("defs").append("symbol").attr("id","computer").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z")}),"insertComputerIcon"),it=(0,r.K2)((function(t){t.append("defs").append("symbol").attr("id","clock").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z")}),"insertClockIcon"),rt=(0,r.K2)((function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",9).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z")}),"insertArrowHead"),st=(0,r.K2)((function(t){t.append("defs").append("marker").attr("id","arrowend").attr("refX",1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 10 0 L 0 5 L 10 10 z")}),"insertArrowEnd"),lt=(0,r.K2)((function(t){t.append("defs").append("marker").attr("id","filled-head").attr("refX",18).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")}),"insertArrowFilledHead"),ot=(0,r.K2)((function(t){t.append("defs").append("marker").attr("id","sequencenumber").attr("refX",15).attr("refY",15).attr("markerWidth",60).attr("markerHeight",40).attr("orient","auto").append("circle").attr("cx",15).attr("cy",15).attr("r",6)}),"insertDynamicNumber"),ct=(0,r.K2)((function(t){const e=t.append("defs").append("marker").attr("id","crosshead").attr("markerWidth",15).attr("markerHeight",8).attr("orient","auto").attr("refX",16).attr("refY",4);e.append("path").attr("fill","black").attr("stroke","#000000").style("stroke-dasharray","0, 0").attr("stroke-width","1px").attr("d","M 9,2 V 6 L16,4 Z"),e.append("path").attr("fill","none").attr("stroke","#000000").style("stroke-dasharray","0, 0").attr("stroke-width","1px").attr("d","M 0,1 L 6,7 M 6,1 L 0,7")}),"insertArrowCrossHead"),ht=(0,r.K2)(((t,e)=>({fontFamily:t[e+"FontFamily"],fontSize:t[e+"FontSize"],fontWeight:t[e+"FontWeight"]})),"getC4ShapeFont"),dt=function(){function t(t,e,a,i,r,s,l){n(e.append("text").attr("x",a+r/2).attr("y",i+s/2+5).style("text-anchor","middle").text(t),l)}function e(t,e,a,i,s,l,o,c){const{fontSize:h,fontFamily:d,fontWeight:u}=c,p=t.split(r.Y2.lineBreakRegex);for(let r=0;r=this.data.widthLimit||a>=this.data.widthLimit||this.nextData.cnt>gt)&&(e=this.nextData.startx+t.margin+bt.nextLinePaddingX,n=this.nextData.stopy+2*t.margin,this.nextData.stopx=a=e+t.width,this.nextData.starty=this.nextData.stopy,this.nextData.stopy=i=n+t.height,this.nextData.cnt=1),t.x=e,t.y=n,this.updateVal(this.data,"startx",e,Math.min),this.updateVal(this.data,"starty",n,Math.min),this.updateVal(this.data,"stopx",a,Math.max),this.updateVal(this.data,"stopy",i,Math.max),this.updateVal(this.nextData,"startx",e,Math.min),this.updateVal(this.nextData,"starty",n,Math.min),this.updateVal(this.nextData,"stopx",a,Math.max),this.updateVal(this.nextData,"stopy",i,Math.max)}init(t){this.name="",this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0,widthLimit:void 0},this.nextData={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0,cnt:0},_t(t.db.getConfig())}bumpLastMargin(t){this.data.stopx+=t,this.data.stopy+=t}},_t=(0,r.K2)((function(t){(0,r.hH)(bt,t),t.fontFamily&&(bt.personFontFamily=bt.systemFontFamily=bt.messageFontFamily=t.fontFamily),t.fontSize&&(bt.personFontSize=bt.systemFontSize=bt.messageFontSize=t.fontSize),t.fontWeight&&(bt.personFontWeight=bt.systemFontWeight=bt.messageFontWeight=t.fontWeight)}),"setConf"),mt=(0,r.K2)(((t,e)=>({fontFamily:t[e+"FontFamily"],fontSize:t[e+"FontSize"],fontWeight:t[e+"FontWeight"]})),"c4ShapeFont"),Et=(0,r.K2)((t=>({fontFamily:t.boundaryFontFamily,fontSize:t.boundaryFontSize,fontWeight:t.boundaryFontWeight})),"boundaryFont"),St=(0,r.K2)((t=>({fontFamily:t.messageFontFamily,fontSize:t.messageFontSize,fontWeight:t.messageFontWeight})),"messageFont");function At(t,e,a,n,s){if(!e[t].width)if(a)e[t].text=(0,i.bH)(e[t].text,s,n),e[t].textLines=e[t].text.split(r.Y2.lineBreakRegex).length,e[t].width=s,e[t].height=(0,i.ru)(e[t].text,n);else{let a=e[t].text.split(r.Y2.lineBreakRegex);e[t].textLines=a.length;let s=0;e[t].height=0,e[t].width=0;for(const r of a)e[t].width=Math.max((0,i.Un)(r,n),e[t].width),s=(0,i.ru)(r,n),e[t].height=e[t].height+s}}(0,r.K2)(At,"calcC4ShapeTextWH");var Ct=(0,r.K2)((function(t,e,a){e.x=a.data.startx,e.y=a.data.starty,e.width=a.data.stopx-a.data.startx,e.height=a.data.stopy-a.data.starty,e.label.y=bt.c4ShapeMargin-35;let n=e.wrap&&bt.wrap,r=Et(bt);r.fontSize=r.fontSize+2,r.fontWeight="bold",At("label",e,n,r,(0,i.Un)(e.label.text,r)),ut.drawBoundary(t,e,bt)}),"drawBoundary"),wt=(0,r.K2)((function(t,e,a,n){let r=0;for(const s of n){r=0;const n=a[s];let l=mt(bt,n.typeC4Shape.text);switch(l.fontSize=l.fontSize-2,n.typeC4Shape.width=(0,i.Un)("\xab"+n.typeC4Shape.text+"\xbb",l),n.typeC4Shape.height=l.fontSize+2,n.typeC4Shape.Y=bt.c4ShapePadding,r=n.typeC4Shape.Y+n.typeC4Shape.height-4,n.image={width:0,height:0,Y:0},n.typeC4Shape.text){case"person":case"external_person":n.image.width=48,n.image.height=48,n.image.Y=r,r=n.image.Y+n.image.height}n.sprite&&(n.image.width=48,n.image.height=48,n.image.Y=r,r=n.image.Y+n.image.height);let o=n.wrap&&bt.wrap,c=bt.width-2*bt.c4ShapePadding,h=mt(bt,n.typeC4Shape.text);if(h.fontSize=h.fontSize+2,h.fontWeight="bold",At("label",n,o,h,c),n.label.Y=r+8,r=n.label.Y+n.label.height,n.type&&""!==n.type.text){n.type.text="["+n.type.text+"]",At("type",n,o,mt(bt,n.typeC4Shape.text),c),n.type.Y=r+5,r=n.type.Y+n.type.height}else if(n.techn&&""!==n.techn.text){n.techn.text="["+n.techn.text+"]",At("techn",n,o,mt(bt,n.techn.text),c),n.techn.Y=r+5,r=n.techn.Y+n.techn.height}let d=r,u=n.label.width;if(n.descr&&""!==n.descr.text){At("descr",n,o,mt(bt,n.typeC4Shape.text),c),n.descr.Y=r+20,r=n.descr.Y+n.descr.height,u=Math.max(n.label.width,n.descr.width),d=r-5*n.descr.textLines}u+=bt.c4ShapePadding,n.width=Math.max(n.width||bt.width,u,bt.width),n.height=Math.max(n.height||bt.height,d,bt.height),n.margin=n.margin||bt.c4ShapeMargin,t.insert(n),ut.drawC4Shape(e,n,bt)}t.bumpLastMargin(bt.c4ShapeMargin)}),"drawC4ShapeArray"),kt=class{static{(0,r.K2)(this,"Point")}constructor(t,e){this.x=t,this.y=e}},Ot=(0,r.K2)((function(t,e){let a=t.x,n=t.y,i=e.x,r=e.y,s=a+t.width/2,l=n+t.height/2,o=Math.abs(a-i),c=Math.abs(n-r),h=c/o,d=t.height/t.width,u=null;return n==r&&ai?u=new kt(a,l):a==i&&nr&&(u=new kt(s,n)),a>i&&n=h?new kt(a,l+h*t.width/2):new kt(s-o/c*t.height/2,n+t.height):a=h?new kt(a+t.width,l+h*t.width/2):new kt(s+o/c*t.height/2,n+t.height):ar?u=d>=h?new kt(a+t.width,l-h*t.width/2):new kt(s+t.height/2*o/c,n):a>i&&n>r&&(u=d>=h?new kt(a,l-t.width/2*h):new kt(s-t.height/2*o/c,n)),u}),"getIntersectPoint"),Tt=(0,r.K2)((function(t,e){let a={x:0,y:0};a.x=e.x+e.width/2,a.y=e.y+e.height/2;let n=Ot(t,a);return a.x=t.x+t.width/2,a.y=t.y+t.height/2,{startPoint:n,endPoint:Ot(e,a)}}),"getIntersectPoints"),vt=(0,r.K2)((function(t,e,a,n){let r=0;for(let s of e){r+=1;let t=s.wrap&&bt.wrap,e=St(bt);"C4Dynamic"===n.db.getC4Type()&&(s.label.text=r+": "+s.label.text);let l=(0,i.Un)(s.label.text,e);At("label",s,t,e,l),s.techn&&""!==s.techn.text&&(l=(0,i.Un)(s.techn.text,e),At("techn",s,t,e,l)),s.descr&&""!==s.descr.text&&(l=(0,i.Un)(s.descr.text,e),At("descr",s,t,e,l));let o=a(s.from),c=a(s.to),h=Tt(o,c);s.startPoint=h.startPoint,s.endPoint=h.endPoint}ut.drawRels(t,e,bt)}),"drawRels");function Rt(t,e,a,n,i){let r=new xt(i);r.data.widthLimit=a.data.widthLimit/Math.min(ft,n.length);for(let[s,l]of n.entries()){let n=0;l.image={width:0,height:0,Y:0},l.sprite&&(l.image.width=48,l.image.height=48,l.image.Y=n,n=l.image.Y+l.image.height);let o=l.wrap&&bt.wrap,c=Et(bt);if(c.fontSize=c.fontSize+2,c.fontWeight="bold",At("label",l,o,c,r.data.widthLimit),l.label.Y=n+8,n=l.label.Y+l.label.height,l.type&&""!==l.type.text){l.type.text="["+l.type.text+"]",At("type",l,o,Et(bt),r.data.widthLimit),l.type.Y=n+5,n=l.type.Y+l.type.height}if(l.descr&&""!==l.descr.text){let t=Et(bt);t.fontSize=t.fontSize-2,At("descr",l,o,t,r.data.widthLimit),l.descr.Y=n+20,n=l.descr.Y+l.descr.height}if(0==s||s%ft==0){let t=a.data.startx+bt.diagramMarginX,e=a.data.stopy+bt.diagramMarginY+n;r.setData(t,t,e,e)}else{let t=r.data.stopx!==r.data.startx?r.data.stopx+bt.diagramMarginX:r.data.startx,e=r.data.starty;r.setData(t,t,e,e)}r.name=l.alias;let h=i.db.getC4ShapeArray(l.alias),d=i.db.getC4ShapeKeys(l.alias);d.length>0&&wt(r,t,h,d),e=l.alias;let u=i.db.getBoundarys(e);u.length>0&&Rt(t,e,r,u,i),"global"!==l.alias&&Ct(t,l,r),a.data.stopy=Math.max(r.data.stopy+bt.c4ShapeMargin,a.data.stopy),a.data.stopx=Math.max(r.data.stopx+bt.c4ShapeMargin,a.data.stopx),pt=Math.max(pt,a.data.stopx),yt=Math.max(yt,a.data.stopy)}}(0,r.K2)(Rt,"drawInsideBoundary");var Dt={drawPersonOrSystemArray:wt,drawBoundary:Ct,setConf:_t,draw:(0,r.K2)((function(t,e,a,n){bt=(0,r.D7)().c4;const i=(0,r.D7)().securityLevel;let l;"sandbox"===i&&(l=(0,s.Ltv)("#i"+e));const o="sandbox"===i?(0,s.Ltv)(l.nodes()[0].contentDocument.body):(0,s.Ltv)("body");let c=n.db;n.db.setWrap(bt.wrap),gt=c.getC4ShapeInRow(),ft=c.getC4BoundaryInRow(),r.Rm.debug(`C:${JSON.stringify(bt,null,2)}`);const h="sandbox"===i?o.select(`[id="${e}"]`):(0,s.Ltv)(`[id="${e}"]`);ut.insertComputerIcon(h),ut.insertDatabaseIcon(h),ut.insertClockIcon(h);let d=new xt(n);d.setData(bt.diagramMarginX,bt.diagramMarginX,bt.diagramMarginY,bt.diagramMarginY),d.data.widthLimit=screen.availWidth,pt=bt.diagramMarginX,yt=bt.diagramMarginY;const u=n.db.getTitle();Rt(h,"",d,n.db.getBoundarys(""),n),ut.insertArrowHead(h),ut.insertArrowEnd(h),ut.insertArrowCrossHead(h),ut.insertArrowFilledHead(h),vt(h,n.db.getRels(),n.db.getC4Shape,n),d.data.stopx=pt,d.data.stopy=yt;const p=d.data;let y=p.stopy-p.starty+2*bt.diagramMarginY;const g=p.stopx-p.startx+2*bt.diagramMarginX;u&&h.append("text").text(u).attr("x",(p.stopx-p.startx)/2-4*bt.diagramMarginX).attr("y",p.starty+bt.diagramMarginY),(0,r.a$)(h,y,g,bt.useMaxWidth);const f=u?60:0;h.attr("viewBox",p.startx-bt.diagramMarginX+" -"+(bt.diagramMarginY+f)+" "+g+" "+(y+f)),r.Rm.debug("models:",p)}),"draw")},Nt={parser:d,db:V,renderer:Dt,styles:(0,r.K2)((t=>`.person {\n stroke: ${t.personBorder};\n fill: ${t.personBkg};\n }\n`),"getStyles"),init:(0,r.K2)((({c4:t,wrap:e})=>{Dt.setConf(t),V.setWrap(e)}),"init")}},83814:(t,e,a)=>{a.d(e,{CP:()=>c,HT:()=>d,PB:()=>h,aC:()=>o,lC:()=>s,m:()=>l,tk:()=>r});var n=a(10009),i=a(16750),r=(0,n.K2)(((t,e)=>{const a=t.append("rect");if(a.attr("x",e.x),a.attr("y",e.y),a.attr("fill",e.fill),a.attr("stroke",e.stroke),a.attr("width",e.width),a.attr("height",e.height),e.name&&a.attr("name",e.name),e.rx&&a.attr("rx",e.rx),e.ry&&a.attr("ry",e.ry),void 0!==e.attrs)for(const n in e.attrs)a.attr(n,e.attrs[n]);return e.class&&a.attr("class",e.class),a}),"drawRect"),s=(0,n.K2)(((t,e)=>{const a={x:e.startx,y:e.starty,width:e.stopx-e.startx,height:e.stopy-e.starty,fill:e.fill,stroke:e.stroke,class:"rect"};r(t,a).lower()}),"drawBackgroundRect"),l=(0,n.K2)(((t,e)=>{const a=e.text.replace(n.H1," "),i=t.append("text");i.attr("x",e.x),i.attr("y",e.y),i.attr("class","legend"),i.style("text-anchor",e.anchor),e.class&&i.attr("class",e.class);const r=i.append("tspan");return r.attr("x",e.x+2*e.textMargin),r.text(a),i}),"drawText"),o=(0,n.K2)(((t,e,a,n)=>{const r=t.append("image");r.attr("x",e),r.attr("y",a);const s=(0,i.J)(n);r.attr("xlink:href",s)}),"drawImage"),c=(0,n.K2)(((t,e,a,n)=>{const r=t.append("use");r.attr("x",e),r.attr("y",a);const s=(0,i.J)(n);r.attr("xlink:href",`#${s}`)}),"drawEmbeddedImage"),h=(0,n.K2)((()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0})),"getNoteRect"),d=(0,n.K2)((()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0})),"getTextObj")}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/26742c3b.ba01b343.js b/pr-preview/pr-1071/assets/js/26742c3b.ba01b343.js deleted file mode 100644 index f5226ce5fb..0000000000 --- a/pr-preview/pr-1071/assets/js/26742c3b.ba01b343.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3108],{45694:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","source":"@site/versioned_docs/version-0.9/architecture/secrets.md","sourceDirName":"architecture","slug":"/architecture/secrets","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/secrets","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/architecture/secrets.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/attestation"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/certificates"}}');var i=r(74848),n=r(28453);const o={},a="Secrets & recovery",c={},d=[{value:"Persistence",id:"persistence",level:2},{value:"Recovery",id:"recovery",level:2}];function h(e){const t={code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,n.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"secrets--recovery",children:"Secrets & recovery"})}),"\n",(0,i.jsx)(t.p,{children:"When the Coordinator is configured with the initial manifest, it generates a random secret seed.\nFrom this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history.\nThis derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state."}),"\n",(0,i.jsxs)(t.p,{children:["The secret seed is returned to the user on the first call to ",(0,i.jsx)(t.code,{children:"contrast set"}),", encrypted with the user's public seed share owner key.\nIf no seed share owner key is provided, a key is generated and stored in the working directory."]}),"\n",(0,i.jsx)(t.h2,{id:"persistence",children:"Persistence"}),"\n",(0,i.jsxs)(t.p,{children:["The Coordinator runs as a ",(0,i.jsx)(t.code,{children:"StatefulSet"})," with a dynamically provisioned persistent volume.\nThis volume stores the manifest history and the associated runtime policies.\nThe manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads.\nHowever, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users.\nThus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed."]}),"\n",(0,i.jsx)(t.h2,{id:"recovery",children:"Recovery"}),"\n",(0,i.jsxs)(t.p,{children:["When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests.\nIt needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures.\nThis procedure is called recovery and is initiated by the workload owner.\nThe CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the ",(0,i.jsx)(t.code,{children:"Recover"})," method.\nThe Coordinator recovers its key material and verifies the manifest history signature."]})]})}function u(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>a});var s=r(96540);const i={},n=s.createContext(i);function o(e){const t=s.useContext(n);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(n.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/27004ef7.d11dfe88.js b/pr-preview/pr-1071/assets/js/27004ef7.d11dfe88.js deleted file mode 100644 index a859205298..0000000000 --- a/pr-preview/pr-1071/assets/js/27004ef7.d11dfe88.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2154],{23003:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/versioned_docs/version-1.1/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/1.1/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/features-limitations.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/observability"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/1.1/about/telemetry"}}');var r=n(74848),s=n(28453);const o={},a="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2},{value:"Automatic recovery and high availability",id:"automatic-recovery-and-high-availability",level:2}];function d(e){const t={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,r.jsx)(t.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,r.jsx)(t.h2,{id:"availability",children:"Availability"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Bare-metal support"}),": Support for running ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal",children:"Contrast on bare-metal Kubernetes"})," is available for AMD SEV-SNP and Intel TDX."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Persistent volumes"}),": Contrast only supports volumes with ",(0,r.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode",children:(0,r.jsx)(t.code,{children:"volumeMode: Block"})}),". These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Port forwarding"}),": This feature ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,r.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,r.jsx)(t.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Volume integrity checks"}),": While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ",(0,r.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,r.jsx)(t.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsx)(t.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,r.jsx)(t.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"automatic-recovery-and-high-availability",children:"Automatic recovery and high availability"}),"\n",(0,r.jsx)(t.p,{children:"The Contrast Coordinator is a singleton and can't be scaled to more than one instance.\nWhen this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually.\nIn a future release, we plan to support distributed Coordinator instances that can recover automatically."})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const r={},s=i.createContext(r);function o(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/270470f6.5faa0f56.js b/pr-preview/pr-1071/assets/js/270470f6.5faa0f56.js deleted file mode 100644 index 7bf37ae892..0000000000 --- a/pr-preview/pr-1071/assets/js/270470f6.5faa0f56.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8671],{67669:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-1.0/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/1.0/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/components/service-mesh.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/1.0/components/policies"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/attestation"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"CONTRAST_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"CONTRAST_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"##false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:""})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"##true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: CONTRAST_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v1.0.0@sha256:2aa3a6711ed8dee36a8dcdae63dd10b9fd5bb9aac6dba688ed1be8ab1fbb310e"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-secrets\n mountPath: /contrast\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"#:#:"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:""}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/27a940ba.4bef4b04.js b/pr-preview/pr-1071/assets/js/27a940ba.4bef4b04.js deleted file mode 100644 index 9bcd35c2c4..0000000000 --- a/pr-preview/pr-1071/assets/js/27a940ba.4bef4b04.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5279],{85360:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-1.0/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/1.0/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/components/runtime.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/1.0/components/overview"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/1.0/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"cloud-hypervisor virtual machine manager (VMM)",id:"cloud-hypervisor-virtual-machine-manager-vmm",level:3},{value:"Tardev snapshotter",id:"tardev-snapshotter",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(62966).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"cloud-hypervisor-virtual-machine-manager-vmm",children:[(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," virtual machine manager (VMM)"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})})," to create a confidential virtual machine for every pod.\nThis requires the ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," binary to be installed on every node (responsibility of the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),")."]}),"\n",(0,i.jsx)(n.h3,{id:"tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"Tardev snapshotter"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses a special ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotter"]})," (",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})}),") to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},62966:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/27d05faa.67774e09.js b/pr-preview/pr-1071/assets/js/27d05faa.67774e09.js deleted file mode 100644 index 13b8e3f283..0000000000 --- a/pr-preview/pr-1071/assets/js/27d05faa.67774e09.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7697],{12346:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-0.6/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/0.6/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/about/telemetry.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"About","permalink":"/contrast/pr-preview/pr-1071/0.6/about/"}}');var r=s(74848),o=s(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,s)=>{s.d(t,{R:()=>i,x:()=>a});var n=s(96540);const r={},o=n.createContext(r);function i(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2a2a0c40.d49ea0e0.js b/pr-preview/pr-1071/assets/js/2a2a0c40.d49ea0e0.js deleted file mode 100644 index 0312085fb0..0000000000 --- a/pr-preview/pr-1071/assets/js/2a2a0c40.d49ea0e0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7292],{48672:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>l,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>i});const s=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/docs/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/getting-started/install.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/next/basics/features"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup"}}');var r=n(74848),a=n(28453);const o={},l="Installation",c={},i=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/latest/download/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>l});var s=n(96540);const r={},a=s.createContext(r);function o(t){const e=s.useContext(a);return s.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function l(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),s.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2cdf8d95.c5542a37.js b/pr-preview/pr-1071/assets/js/2cdf8d95.c5542a37.js deleted file mode 100644 index 88758134fb..0000000000 --- a/pr-preview/pr-1071/assets/js/2cdf8d95.c5542a37.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4118],{14175:e=>{e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Components","slug":"/category/components","permalink":"/contrast/pr-preview/pr-1071/0.5/category/components","sidebar":"docs","navigation":{"previous":{"title":"Architecture","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/"},"next":{"title":"Coordinator","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2d1295a3.1f87ff64.js b/pr-preview/pr-1071/assets/js/2d1295a3.1f87ff64.js deleted file mode 100644 index a18ad0d294..0000000000 --- a/pr-preview/pr-1071/assets/js/2d1295a3.1f87ff64.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5374],{74413:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.5","label":"0.5","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.5","isLast":false,"docsSidebars":{"docs":[{"type":"category","label":"What is Contrast?","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/0.5/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/"},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/0.5/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false},{"type":"link","label":"First steps","href":"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps","docId":"getting-started/first-steps","unlisted":false}],"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/getting-started/"},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/examples/"},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/0.5/deployment","docId":"deployment","unlisted":false},{"type":"category","label":"Architecture","items":[{"type":"category","label":"Components","items":[{"type":"link","label":"Coordinator","href":"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator","docId":"architecture/components/coordinator","unlisted":false},{"type":"link","label":"Init container","href":"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container","docId":"architecture/components/init-container","unlisted":false},{"type":"link","label":"CLI","href":"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli","docId":"architecture/components/cli","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/category/components"},{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers","docId":"architecture/confidential-containers","unlisted":false},{"type":"category","label":"Attestation","items":[{"type":"link","label":"Hardware","href":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware","docId":"architecture/attestation/hardware","unlisted":false},{"type":"link","label":"Pod VM","href":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm","docId":"architecture/attestation/pod-vm","unlisted":false},{"type":"link","label":"Runtime policies","href":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies","docId":"architecture/attestation/runtime-policies","unlisted":false},{"type":"link","label":"Manifest","href":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest","docId":"architecture/attestation/manifest","unlisted":false},{"type":"link","label":"Coordinator","href":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator","docId":"architecture/attestation/coordinator","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/category/attestation"},{"type":"category","label":"Certificates and Identities","items":[{"type":"link","label":"PKI","href":"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki","docId":"architecture/certificates-and-identities/pki","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities"},{"type":"category","label":"Network Encryption","items":[{"type":"link","label":"Sidecar","href":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar","docId":"architecture/network-encryption/sidecar","unlisted":false},{"type":"link","label":"Protocols and Keys","href":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys","docId":"architecture/network-encryption/protocols-and-keys","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption"}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.5/architecture/"}]},"docs":{"architecture/attestation/coordinator":{"id":"architecture/attestation/coordinator","title":"coordinator","description":"","sidebar":"docs"},"architecture/attestation/hardware":{"id":"architecture/attestation/hardware","title":"hardware","description":"","sidebar":"docs"},"architecture/attestation/manifest":{"id":"architecture/attestation/manifest","title":"manifest","description":"","sidebar":"docs"},"architecture/attestation/pod-vm":{"id":"architecture/attestation/pod-vm","title":"pod-vm","description":"","sidebar":"docs"},"architecture/attestation/runtime-policies":{"id":"architecture/attestation/runtime-policies","title":"runtime-policies","description":"","sidebar":"docs"},"architecture/certificates-and-identities/pki":{"id":"architecture/certificates-and-identities/pki","title":"pki","description":"","sidebar":"docs"},"architecture/components/cli":{"id":"architecture/components/cli","title":"cli","description":"","sidebar":"docs"},"architecture/components/coordinator":{"id":"architecture/components/coordinator","title":"coordinator","description":"","sidebar":"docs"},"architecture/components/init-container":{"id":"architecture/components/init-container","title":"init-container","description":"","sidebar":"docs"},"architecture/confidential-containers":{"id":"architecture/confidential-containers","title":"confidential-containers","description":"","sidebar":"docs"},"architecture/index":{"id":"architecture/index","title":"Architecture","description":"","sidebar":"docs"},"architecture/network-encryption/protocols-and-keys":{"id":"architecture/network-encryption/protocols-and-keys","title":"protocols-and-keys","description":"","sidebar":"docs"},"architecture/network-encryption/sidecar":{"id":"architecture/network-encryption/sidecar","title":"sidecar","description":"","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product Features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"security-benefits","description":"","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"examples/index":{"id":"examples/index","title":"Examples","description":"","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/first-steps":{"id":"getting-started/first-steps","title":"first-steps","description":"","sidebar":"docs"},"getting-started/index":{"id":"getting-started/index","title":"Getting started","description":"","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the bundle from the URL you received:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2dbe31cc.3c51b1f7.js b/pr-preview/pr-1071/assets/js/2dbe31cc.3c51b1f7.js deleted file mode 100644 index 8bbbc70b84..0000000000 --- a/pr-preview/pr-1071/assets/js/2dbe31cc.3c51b1f7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2700],{18856:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-0.7/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/0.7/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/components/service-mesh.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.7/components/policies"},"next":{"title":"Architecture","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"EDG_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"EDG_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"EDG_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"##false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:""})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"##true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: EDG_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v0.7.3@sha256:e297e9db93744445608f229d44479359313bc187a7f31e1a9c3c9b1d5407b5f6"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-tls-certs\n mountPath: /tls-config\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"#:#:"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:""}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2df6ad32.624fd64a.js b/pr-preview/pr-1071/assets/js/2df6ad32.624fd64a.js deleted file mode 100644 index 5542a077f8..0000000000 --- a/pr-preview/pr-1071/assets/js/2df6ad32.624fd64a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1597],{92258:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});const r=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-1.0/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/1.0/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/deployment.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto"},"next":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/1.0/troubleshooting"}}');var o=t(74848),s=t(28453);const i={},a="Workload deployment",c={},l=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2},{value:"Recover the Coordinator",id:"recover-the-coordinator",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components},{TabItem:t,Tabs:r}=n;return t||p("TabItem",!0),r||p("Tabs",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.header,{children:(0,o.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,o.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,o.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup",children:"setup guide"})," on how to set it up."]}),"\n",(0,o.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,o.jsxs)(n.p,{children:["Contrast depends on a ",(0,o.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:["custom Kubernetes ",(0,o.jsx)(n.code,{children:"RuntimeClass"})," (",(0,o.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,o.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,o.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/runtime.yml\n"})}),"\n",(0,o.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/coordinator.yml\n"})}),"\n",(0,o.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,o.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,o.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,o.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,o.jsxs)(r,{groupId:"yaml-source",children:[(0,o.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,o.jsx)(t,{value:"helm",label:"helm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,o.jsx)(t,{value:"copy",label:"copy",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,o.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,o.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,o.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,o.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,o.jsxs)(n.p,{children:["In the initialization process, the ",(0,o.jsx)(n.code,{children:"contrast-secrets"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,o.jsxs)(r,{groupId:"tls",children:[(0,o.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,o.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,o.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,o.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,o.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,o.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,o.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,o.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,o.jsxs)(n.p,{children:["During the ",(0,o.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,o.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,o.jsxs)(t,{value:"go",label:"Go integration",children:[(0,o.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,o.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,o.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,o.jsxs)(r,{groupId:"golang-tls-setup",children:[(0,o.jsx)(t,{value:"client",label:"Client",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,o.jsx)(t,{value:"server",label:"Server",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,o.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,o.jsxs)(n.p,{children:["Run the ",(0,o.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,o.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,o.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp resources/\n"})}),"\n",(0,o.jsx)(n.admonition,{type:"warning",children:(0,o.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,o.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,o.jsxs)(r,{groupId:"injection",children:[(0,o.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,o.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,o.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,o.jsx)(n.code,{children:"generate"})," command."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp --skip-initializer resources/\n"})})]}),(0,o.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,o.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,o.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,o.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,o.jsx)(n.code,{children:"contrast-secrets"})," ",(0,o.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:v1.0.0@sha256:a86b8637016aff07fe157f6334f58033707f2d657263e956f195a5254e1ee9b5"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /contrast\n name: contrast-secrets\n volumes:\n - emptyDir: {}\n name: contrast-secrets\n'})}),"\n",(0,o.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,o.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,o.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,o.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,o.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,o.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,o.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,o.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,o.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,o.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,o.jsx)(n.p,{children:"This will use the reference values from the manifest file to attest the Coordinator.\nAfter this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,o.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,o.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,o.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,o.jsxs)(n.p,{children:["The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the\nservice mesh root certificate and the history of manifests into the ",(0,o.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies\nreferenced in the active manifest are also written to the directory. The verification will fail if the active\nmanifest at the Coordinator doesn't match the manifest passed to the CLI."]}),"\n",(0,o.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,o.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,o.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,o.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,o.jsxs)(n.p,{children:["Using ",(0,o.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,o.jsx)(n.h2,{id:"recover-the-coordinator",children:"Recover the Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material.\nFor demonstration purposes, you can simulate this scenario by deleting the Coordinator pod."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl delete pod -l app.kubernetes.io/name=coordinator\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet.\nYou can confirm this by running ",(0,o.jsx)(n.code,{children:"verify"})," again, or you can restart a workload pod, which should stay in the initialization phase.\nHowever, the secret seed in your working directory is sufficient to recover the coordinator."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast recover -c "${coordinator}:1313"\n'})}),"\n",(0,o.jsx)(n.p,{children:"Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state.\nYou can now verify the Coordinator again, which should return the same manifest you set before."}),"\n",(0,o.jsx)(n.admonition,{type:"warning",children:(0,o.jsx)(n.p,{children:"The recovery process invalidates the mesh CA certificate:\nexisting workloads won't be able to communicate with workloads newly spawned.\nAll workloads should be restarted after the recovery succeeded."})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}function p(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>a});var r=t(96540);const o={},s=r.createContext(o);function i(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/2e82b444.af66ab87.js b/pr-preview/pr-1071/assets/js/2e82b444.af66ab87.js deleted file mode 100644 index 49800f028e..0000000000 --- a/pr-preview/pr-1071/assets/js/2e82b444.af66ab87.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6232],{91313:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-0.9/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/architecture/attestation.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.9/components/service-mesh"},"next":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/secrets"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(60483).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(8926).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nOn AMD SEV-SNP the hash of the policy is then added to the attestation report via the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field by the hypervisor.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(20957).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},20957:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},8926:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},60483:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3056.0ac094fe.js b/pr-preview/pr-1071/assets/js/3056.0ac094fe.js deleted file mode 100644 index 07f411de77..0000000000 --- a/pr-preview/pr-1071/assets/js/3056.0ac094fe.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3056],{43056:(s,r,a)=>{a.d(r,{diagram:()=>c});var e=a(66240),t=(a(96474),a(87308),a(37938),a(1282),a(64532),a(47588),a(33115),a(10483),a(8159),a(10009)),c={parser:e._$,db:e.z2,renderer:e.Lh,styles:e.tM,init:(0,t.K2)((s=>{s.class||(s.class={}),s.class.arrowMarkerAbsolute=s.arrowMarkerAbsolute,e.z2.clear()}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3175.969edfc2.js b/pr-preview/pr-1071/assets/js/3175.969edfc2.js deleted file mode 100644 index 7962b553da..0000000000 --- a/pr-preview/pr-1071/assets/js/3175.969edfc2.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3175],{26527:function(t,e,i){var r;r=function(t){return(()=>{"use strict";var e={658:t=>{t.exports=null!=Object.assign?Object.assign.bind(Object):function(t){for(var e=arguments.length,i=Array(e>1?e-1:0),r=1;r{var r=function(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return function(t,e){var i=[],r=!0,n=!1,o=void 0;try{for(var s,a=t[Symbol.iterator]();!(r=(s=a.next()).done)&&(i.push(s.value),!e||i.length!==e);r=!0);}catch(h){n=!0,o=h}finally{try{!r&&a.return&&a.return()}finally{if(n)throw o}}return i}(t,e);throw new TypeError("Invalid attempt to destructure non-iterable instance")},n=i(140).layoutBase.LinkedList,o={getTopMostNodes:function(t){for(var e={},i=0;i0&&l.merge(t)}));for(var c=0;c1){l=a[0],c=l.connectedEdges().length,a.forEach((function(t){t.connectedEdges().length0&&r.set("dummy"+(r.size+1),u),p},relocateComponent:function(t,e,i){if(!i.fixedNodeConstraint){var n=Number.POSITIVE_INFINITY,o=Number.NEGATIVE_INFINITY,s=Number.POSITIVE_INFINITY,a=Number.NEGATIVE_INFINITY;if("draft"==i.quality){var h=!0,l=!1,c=void 0;try{for(var d,g=e.nodeIndexes[Symbol.iterator]();!(h=(d=g.next()).done);h=!0){var u=d.value,p=r(u,2),f=p[0],v=p[1],y=i.cy.getElementById(f);if(y){var m=y.boundingBox(),E=e.xCoords[v]-m.w/2,N=e.xCoords[v]+m.w/2,T=e.yCoords[v]-m.h/2,A=e.yCoords[v]+m.h/2;Eo&&(o=N),Ta&&(a=A)}}}catch(C){l=!0,c=C}finally{try{!h&&g.return&&g.return()}finally{if(l)throw c}}var w=t.x-(o+n)/2,L=t.y-(a+s)/2;e.xCoords=e.xCoords.map((function(t){return t+w})),e.yCoords=e.yCoords.map((function(t){return t+L}))}else{Object.keys(e).forEach((function(t){var i=e[t],r=i.getRect().x,h=i.getRect().x+i.getRect().width,l=i.getRect().y,c=i.getRect().y+i.getRect().height;ro&&(o=h),la&&(a=c)}));var I=t.x-(o+n)/2,_=t.y-(a+s)/2;Object.keys(e).forEach((function(t){var i=e[t];i.setCenter(i.getCenterX()+I,i.getCenterY()+_)}))}}},calcBoundingBox:function(t,e,i,r){for(var n=Number.MAX_SAFE_INTEGER,o=Number.MIN_SAFE_INTEGER,s=Number.MAX_SAFE_INTEGER,a=Number.MIN_SAFE_INTEGER,h=void 0,l=void 0,c=void 0,d=void 0,g=t.descendants().not(":parent"),u=g.length,p=0;p(h=e[r.get(f.id())]-f.width()/2)&&(n=h),o<(l=e[r.get(f.id())]+f.width()/2)&&(o=l),s>(c=i[r.get(f.id())]-f.height()/2)&&(s=c),a<(d=i[r.get(f.id())]+f.height()/2)&&(a=d)}var v={};return v.topLeftX=n,v.topLeftY=s,v.width=o-n,v.height=a-s,v},calcParentsWithoutChildren:function(t,e){var i=t.collection();return e.nodes(":parent").forEach((function(t){var e=!1;t.children().forEach((function(t){"none"!=t.css("display")&&(e=!0)})),e||i.merge(t)})),i}};t.exports=o},816:(t,e,i)=>{var r=i(548),n=i(140).CoSELayout,o=i(140).CoSENode,s=i(140).layoutBase.PointD,a=i(140).layoutBase.DimensionD,h=i(140).layoutBase.LayoutConstants,l=i(140).layoutBase.FDLayoutConstants,c=i(140).CoSEConstants;t.exports={coseLayout:function(t,e){var i=t.cy,d=t.eles,g=d.nodes(),u=d.edges(),p=void 0,f=void 0,v=void 0,y={};t.randomize&&(p=e.nodeIndexes,f=e.xCoords,v=e.yCoords);var m=function(t){return"function"==typeof t},E=function(t,e){return m(t)?t(e):t},N=r.calcParentsWithoutChildren(i,d);null!=t.nestingFactor&&(c.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=l.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=t.nestingFactor),null!=t.gravity&&(c.DEFAULT_GRAVITY_STRENGTH=l.DEFAULT_GRAVITY_STRENGTH=t.gravity),null!=t.numIter&&(c.MAX_ITERATIONS=l.MAX_ITERATIONS=t.numIter),null!=t.gravityRange&&(c.DEFAULT_GRAVITY_RANGE_FACTOR=l.DEFAULT_GRAVITY_RANGE_FACTOR=t.gravityRange),null!=t.gravityCompound&&(c.DEFAULT_COMPOUND_GRAVITY_STRENGTH=l.DEFAULT_COMPOUND_GRAVITY_STRENGTH=t.gravityCompound),null!=t.gravityRangeCompound&&(c.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=t.gravityRangeCompound),null!=t.initialEnergyOnIncremental&&(c.DEFAULT_COOLING_FACTOR_INCREMENTAL=l.DEFAULT_COOLING_FACTOR_INCREMENTAL=t.initialEnergyOnIncremental),null!=t.tilingCompareBy&&(c.TILING_COMPARE_BY=t.tilingCompareBy),"proof"==t.quality?h.QUALITY=2:h.QUALITY=0,c.NODE_DIMENSIONS_INCLUDE_LABELS=l.NODE_DIMENSIONS_INCLUDE_LABELS=h.NODE_DIMENSIONS_INCLUDE_LABELS=t.nodeDimensionsIncludeLabels,c.DEFAULT_INCREMENTAL=l.DEFAULT_INCREMENTAL=h.DEFAULT_INCREMENTAL=!t.randomize,c.ANIMATE=l.ANIMATE=h.ANIMATE=t.animate,c.TILE=t.tile,c.TILING_PADDING_VERTICAL="function"==typeof t.tilingPaddingVertical?t.tilingPaddingVertical.call():t.tilingPaddingVertical,c.TILING_PADDING_HORIZONTAL="function"==typeof t.tilingPaddingHorizontal?t.tilingPaddingHorizontal.call():t.tilingPaddingHorizontal,c.DEFAULT_INCREMENTAL=l.DEFAULT_INCREMENTAL=h.DEFAULT_INCREMENTAL=!0,c.PURE_INCREMENTAL=!t.randomize,h.DEFAULT_UNIFORM_LEAF_NODE_SIZES=t.uniformNodeDimensions,"transformed"==t.step&&(c.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,c.ENFORCE_CONSTRAINTS=!1,c.APPLY_LAYOUT=!1),"enforced"==t.step&&(c.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,c.ENFORCE_CONSTRAINTS=!0,c.APPLY_LAYOUT=!1),"cose"==t.step&&(c.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,c.ENFORCE_CONSTRAINTS=!1,c.APPLY_LAYOUT=!0),"all"==t.step&&(t.randomize?c.TRANSFORM_ON_CONSTRAINT_HANDLING=!0:c.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,c.ENFORCE_CONSTRAINTS=!0,c.APPLY_LAYOUT=!0),t.fixedNodeConstraint||t.alignmentConstraint||t.relativePlacementConstraint?c.TREE_REDUCTION_ON_INCREMENTAL=!1:c.TREE_REDUCTION_ON_INCREMENTAL=!0;var T=new n,A=T.newGraphManager();return function t(e,i,n,h){for(var l=i.length,c=0;c0&&t(n.getGraphManager().add(n.newGraph(),u),g,n,h)}}(A.addRoot(),r.getTopMostNodes(g),T,t),function(e,i,r){for(var n=0,o=0,s=0;s0?c.DEFAULT_EDGE_LENGTH=l.DEFAULT_EDGE_LENGTH=n/o:m(t.idealEdgeLength)?c.DEFAULT_EDGE_LENGTH=l.DEFAULT_EDGE_LENGTH=50:c.DEFAULT_EDGE_LENGTH=l.DEFAULT_EDGE_LENGTH=t.idealEdgeLength,c.MIN_REPULSION_DIST=l.MIN_REPULSION_DIST=l.DEFAULT_EDGE_LENGTH/10,c.DEFAULT_RADIAL_SEPARATION=l.DEFAULT_EDGE_LENGTH)}(T,A,u),function(t,e){e.fixedNodeConstraint&&(t.constraints.fixedNodeConstraint=e.fixedNodeConstraint),e.alignmentConstraint&&(t.constraints.alignmentConstraint=e.alignmentConstraint),e.relativePlacementConstraint&&(t.constraints.relativePlacementConstraint=e.relativePlacementConstraint)}(T,t),T.runLayout(),y}}},212:(t,e,i)=>{var r=function(){function t(t,e){for(var i=0;i0)if(d){var g=o.getTopMostNodes(t.eles.nodes());if((h=o.connectComponents(e,t.eles,g)).forEach((function(t){var e=t.boundingBox();l.push({x:e.x1+e.w/2,y:e.y1+e.h/2})})),t.randomize&&h.forEach((function(e){t.eles=e,r.push(s(t))})),"default"==t.quality||"proof"==t.quality){var u=e.collection();if(t.tile){var p=new Map,f=0,v={nodeIndexes:p,xCoords:[],yCoords:[]},y=[];if(h.forEach((function(t,e){0==t.edges().length&&(t.nodes().forEach((function(e,i){u.merge(t.nodes()[i]),e.isParent()||(v.nodeIndexes.set(t.nodes()[i].id(),f++),v.xCoords.push(t.nodes()[0].position().x),v.yCoords.push(t.nodes()[0].position().y))})),y.push(e))})),u.length>1){var m=u.boundingBox();l.push({x:m.x1+m.w/2,y:m.y1+m.h/2}),h.push(u),r.push(v);for(var E=y.length-1;E>=0;E--)h.splice(y[E],1),r.splice(y[E],1),l.splice(y[E],1)}}h.forEach((function(e,i){t.eles=e,n.push(a(t,r[i])),o.relocateComponent(l[i],n[i],t)}))}else h.forEach((function(e,i){o.relocateComponent(l[i],r[i],t)}));var N=new Set;if(h.length>1){var T=[],A=i.filter((function(t){return"none"==t.css("display")}));h.forEach((function(e,i){var s=void 0;if("draft"==t.quality&&(s=r[i].nodeIndexes),e.nodes().not(A).length>0){var a={edges:[],nodes:[]},h=void 0;e.nodes().not(A).forEach((function(e){if("draft"==t.quality)if(e.isParent()){var l=o.calcBoundingBox(e,r[i].xCoords,r[i].yCoords,s);a.nodes.push({x:l.topLeftX,y:l.topLeftY,width:l.width,height:l.height})}else h=s.get(e.id()),a.nodes.push({x:r[i].xCoords[h]-e.boundingbox().w/2,y:r[i].yCoords[h]-e.boundingbox().h/2,width:e.boundingbox().w,height:e.boundingbox().h});else n[i][e.id()]&&a.nodes.push({x:n[i][e.id()].getLeft(),y:n[i][e.id()].getTop(),width:n[i][e.id()].getWidth(),height:n[i][e.id()].getHeight()})})),e.edges().forEach((function(e){var h=e.source(),l=e.target();if("none"!=h.css("display")&&"none"!=l.css("display"))if("draft"==t.quality){var c=s.get(h.id()),d=s.get(l.id()),g=[],u=[];if(h.isParent()){var p=o.calcBoundingBox(h,r[i].xCoords,r[i].yCoords,s);g.push(p.topLeftX+p.width/2),g.push(p.topLeftY+p.height/2)}else g.push(r[i].xCoords[c]),g.push(r[i].yCoords[c]);if(l.isParent()){var f=o.calcBoundingBox(l,r[i].xCoords,r[i].yCoords,s);u.push(f.topLeftX+f.width/2),u.push(f.topLeftY+f.height/2)}else u.push(r[i].xCoords[d]),u.push(r[i].yCoords[d]);a.edges.push({startX:g[0],startY:g[1],endX:u[0],endY:u[1]})}else n[i][h.id()]&&n[i][l.id()]&&a.edges.push({startX:n[i][h.id()].getCenterX(),startY:n[i][h.id()].getCenterY(),endX:n[i][l.id()].getCenterX(),endY:n[i][l.id()].getCenterY()})})),a.nodes.length>0&&(T.push(a),N.add(i))}}));var w=c.packComponents(T,t.randomize).shifts;if("draft"==t.quality)r.forEach((function(t,e){var i=t.xCoords.map((function(t){return t+w[e].dx})),r=t.yCoords.map((function(t){return t+w[e].dy}));t.xCoords=i,t.yCoords=r}));else{var L=0;N.forEach((function(t){Object.keys(n[t]).forEach((function(e){var i=n[t][e];i.setCenter(i.getCenterX()+w[L].dx,i.getCenterY()+w[L].dy)})),L++}))}}}else{var I=t.eles.boundingBox();if(l.push({x:I.x1+I.w/2,y:I.y1+I.h/2}),t.randomize){var _=s(t);r.push(_)}"default"==t.quality||"proof"==t.quality?(n.push(a(t,r[0])),o.relocateComponent(l[0],n[0],t)):o.relocateComponent(l[0],r[0],t)}var C=function(e,i){if("default"==t.quality||"proof"==t.quality){"number"==typeof e&&(e=i);var o=void 0,s=void 0,a=e.data("id");return n.forEach((function(t){a in t&&(o={x:t[a].getRect().getCenterX(),y:t[a].getRect().getCenterY()},s=t[a])})),t.nodeDimensionsIncludeLabels&&(s.labelWidth&&("left"==s.labelPosHorizontal?o.x+=s.labelWidth/2:"right"==s.labelPosHorizontal&&(o.x-=s.labelWidth/2)),s.labelHeight&&("top"==s.labelPosVertical?o.y+=s.labelHeight/2:"bottom"==s.labelPosVertical&&(o.y-=s.labelHeight/2))),null==o&&(o={x:e.position("x"),y:e.position("y")}),{x:o.x,y:o.y}}var h=void 0;return r.forEach((function(t){var i=t.nodeIndexes.get(e.id());null!=i&&(h={x:t.xCoords[i],y:t.yCoords[i]})})),null==h&&(h={x:e.position("x"),y:e.position("y")}),{x:h.x,y:h.y}};if("default"==t.quality||"proof"==t.quality||t.randomize){var M=o.calcParentsWithoutChildren(e,i),x=i.filter((function(t){return"none"==t.css("display")}));t.eles=i.not(x),i.nodes().not(":parent").not(x).layoutPositions(this,t,C),M.length>0&&M.forEach((function(t){t.position(C(t))}))}else console.log("If randomize option is set to false, then quality option must be 'default' or 'proof'.")}}]),t}();t.exports=l},657:(t,e,i)=>{var r=i(548),n=i(140).layoutBase.Matrix,o=i(140).layoutBase.SVD;t.exports={spectralLayout:function(t){var e=t.cy,i=t.eles,s=i.nodes(),a=i.nodes(":parent"),h=new Map,l=new Map,c=new Map,d=[],g=[],u=[],p=[],f=[],v=[],y=[],m=[],E=void 0,N=1e8,T=1e-9,A=t.piTol,w=t.samplingType,L=t.nodeSeparation,I=void 0,_=function(t,e,i){for(var r=[],n=0,o=0,s=0,a=void 0,h=[],c=0,g=1,u=0;u=n;){s=r[n++];for(var p=d[s],y=0;yc&&(c=f[T],g=T)}return g};r.connectComponents(e,i,r.getTopMostNodes(s),h),a.forEach((function(t){r.connectComponents(e,i,r.getTopMostNodes(t.descendants().intersection(i)),h)}));for(var C=0,M=0;M0&&(r.isParent()?d[e].push(c.get(r.id())):d[e].push(r.id()))}))}));var S=function(t){var i=l.get(t),r=void 0;h.get(t).forEach((function(n){r=e.getElementById(n).isParent()?c.get(n):n,d[i].push(r),d[l.get(r)].push(t)}))},P=!0,U=!1,Y=void 0;try{for(var k,H=h.keys()[Symbol.iterator]();!(P=(k=H.next()).done);P=!0)S(k.value)}catch(K){U=!0,Y=K}finally{try{!P&&H.return&&H.return()}finally{if(U)throw Y}}var X=void 0;if((E=l.size)>2){I=E=1)break;l=h}for(var p=0;p=1)break;l=h}for(var y=0;y{var r=i(212),n=function(t){t&&t("layout","fcose",r)};"undefined"!=typeof cytoscape&&n(cytoscape),t.exports=n},140:e=>{e.exports=t}},i={},r=function t(r){var n=i[r];if(void 0!==n)return n.exports;var o=i[r]={exports:{}};return e[r](o,o.exports,t),o.exports}(579);return r})()},t.exports=r(i(41709))},41709:function(t,e,i){var r;r=function(t){return(()=>{"use strict";var e={45:(t,e,i)=>{var r={};r.layoutBase=i(551),r.CoSEConstants=i(806),r.CoSEEdge=i(767),r.CoSEGraph=i(880),r.CoSEGraphManager=i(578),r.CoSELayout=i(765),r.CoSENode=i(991),r.ConstraintHandler=i(902),t.exports=r},806:(t,e,i)=>{var r=i(551).FDLayoutConstants;function n(){}for(var o in r)n[o]=r[o];n.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,n.DEFAULT_RADIAL_SEPARATION=r.DEFAULT_EDGE_LENGTH,n.DEFAULT_COMPONENT_SEPERATION=60,n.TILE=!0,n.TILING_PADDING_VERTICAL=10,n.TILING_PADDING_HORIZONTAL=10,n.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,n.ENFORCE_CONSTRAINTS=!0,n.APPLY_LAYOUT=!0,n.RELAX_MOVEMENT_ON_CONSTRAINTS=!0,n.TREE_REDUCTION_ON_INCREMENTAL=!0,n.PURE_INCREMENTAL=n.DEFAULT_INCREMENTAL,t.exports=n},767:(t,e,i)=>{var r=i(551).FDLayoutEdge;function n(t,e,i){r.call(this,t,e,i)}for(var o in n.prototype=Object.create(r.prototype),r)n[o]=r[o];t.exports=n},880:(t,e,i)=>{var r=i(551).LGraph;function n(t,e,i){r.call(this,t,e,i)}for(var o in n.prototype=Object.create(r.prototype),r)n[o]=r[o];t.exports=n},578:(t,e,i)=>{var r=i(551).LGraphManager;function n(t){r.call(this,t)}for(var o in n.prototype=Object.create(r.prototype),r)n[o]=r[o];t.exports=n},765:(t,e,i)=>{var r=i(551).FDLayout,n=i(578),o=i(880),s=i(991),a=i(767),h=i(806),l=i(902),c=i(551).FDLayoutConstants,d=i(551).LayoutConstants,g=i(551).Point,u=i(551).PointD,p=i(551).DimensionD,f=i(551).Layout,v=i(551).Integer,y=i(551).IGeometry,m=i(551).LGraph,E=i(551).Transform,N=i(551).LinkedList;function T(){r.call(this),this.toBeTiled={},this.constraints={}}for(var A in T.prototype=Object.create(r.prototype),r)T[A]=r[A];T.prototype.newGraphManager=function(){var t=new n(this);return this.graphManager=t,t},T.prototype.newGraph=function(t){return new o(null,this.graphManager,t)},T.prototype.newNode=function(t){return new s(this.graphManager,t)},T.prototype.newEdge=function(t){return new a(null,null,t)},T.prototype.initParameters=function(){r.prototype.initParameters.call(this,arguments),this.isSubLayout||(h.DEFAULT_EDGE_LENGTH<10?this.idealEdgeLength=10:this.idealEdgeLength=h.DEFAULT_EDGE_LENGTH,this.useSmartIdealEdgeLengthCalculation=h.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.gravityConstant=c.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=c.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=c.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=c.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.prunedNodesAll=[],this.growTreeIterations=0,this.afterGrowthIterations=0,this.isTreeGrowing=!1,this.isGrowthFinished=!1)},T.prototype.initSpringEmbedder=function(){r.prototype.initSpringEmbedder.call(this),this.coolingCycle=0,this.maxCoolingCycle=this.maxIterations/c.CONVERGENCE_CHECK_PERIOD,this.finalTemperature=.04,this.coolingAdjuster=1},T.prototype.layout=function(){return d.DEFAULT_CREATE_BENDS_AS_NEEDED&&(this.createBendpoints(),this.graphManager.resetAllEdges()),this.level=0,this.classicLayout()},T.prototype.classicLayout=function(){if(this.nodesWithGravity=this.calculateNodesToApplyGravitationTo(),this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity),this.calcNoOfChildrenForAllNodes(),this.graphManager.calcLowestCommonAncestors(),this.graphManager.calcInclusionTreeDepths(),this.graphManager.getRoot().calcEstimatedSize(),this.calcIdealEdgeLengths(),this.incremental)h.TREE_REDUCTION_ON_INCREMENTAL&&(this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation(),e=new Set(this.getAllNodes()),i=this.nodesWithGravity.filter((function(t){return e.has(t)})),this.graphManager.setAllNodesToApplyGravitation(i));else{var t=this.getFlatForest();if(t.length>0)this.positionNodesRadially(t);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var e=new Set(this.getAllNodes()),i=this.nodesWithGravity.filter((function(t){return e.has(t)}));this.graphManager.setAllNodesToApplyGravitation(i),this.positionNodesRandomly()}}return Object.keys(this.constraints).length>0&&(l.handleConstraints(this),this.initConstraintVariables()),this.initSpringEmbedder(),h.APPLY_LAYOUT&&this.runSpringEmbedder(),!0},T.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished){if(!(this.prunedNodesAll.length>0))return!0;this.isTreeGrowing=!0}if(this.totalIterations%c.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged()){if(!(this.prunedNodesAll.length>0))return!0;this.isTreeGrowing=!0}this.coolingCycle++,0==this.layoutQuality?this.coolingAdjuster=this.coolingCycle:1==this.layoutQuality&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var t=new Set(this.getAllNodes()),e=this.nodesWithGravity.filter((function(e){return t.has(e)}));this.graphManager.setAllNodesToApplyGravitation(e),this.graphManager.updateBounds(),this.updateGrid(),h.PURE_INCREMENTAL?this.coolingFactor=c.DEFAULT_COOLING_FACTOR_INCREMENTAL/2:this.coolingFactor=c.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),h.PURE_INCREMENTAL?this.coolingFactor=c.DEFAULT_COOLING_FACTOR_INCREMENTAL/2*((100-this.afterGrowthIterations)/100):this.coolingFactor=c.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var i=!this.isTreeGrowing&&!this.isGrowthFinished,r=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(i,r),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},T.prototype.getPositionsData=function(){for(var t=this.graphManager.getAllNodes(),e={},i=0;i0&&this.updateDisplacements(),e=0;e0&&(r.fixedNodeWeight=o)}if(this.constraints.relativePlacementConstraint){var s=new Map,a=new Map;if(this.dummyToNodeForVerticalAlignment=new Map,this.dummyToNodeForHorizontalAlignment=new Map,this.fixedNodesOnHorizontal=new Set,this.fixedNodesOnVertical=new Set,this.fixedNodeSet.forEach((function(e){t.fixedNodesOnHorizontal.add(e),t.fixedNodesOnVertical.add(e)})),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical){var l=this.constraints.alignmentConstraint.vertical;for(i=0;i=2*t.length/3;r--)e=Math.floor(Math.random()*(r+1)),i=t[r],t[r]=t[e],t[e]=i;return t},this.nodesInRelativeHorizontal=[],this.nodesInRelativeVertical=[],this.nodeToRelativeConstraintMapHorizontal=new Map,this.nodeToRelativeConstraintMapVertical=new Map,this.nodeToTempPositionMapHorizontal=new Map,this.nodeToTempPositionMapVertical=new Map,this.constraints.relativePlacementConstraint.forEach((function(e){if(e.left){var i=s.has(e.left)?s.get(e.left):e.left,r=s.has(e.right)?s.get(e.right):e.right;t.nodesInRelativeHorizontal.includes(i)||(t.nodesInRelativeHorizontal.push(i),t.nodeToRelativeConstraintMapHorizontal.set(i,[]),t.dummyToNodeForVerticalAlignment.has(i)?t.nodeToTempPositionMapHorizontal.set(i,t.idToNodeMap.get(t.dummyToNodeForVerticalAlignment.get(i)[0]).getCenterX()):t.nodeToTempPositionMapHorizontal.set(i,t.idToNodeMap.get(i).getCenterX())),t.nodesInRelativeHorizontal.includes(r)||(t.nodesInRelativeHorizontal.push(r),t.nodeToRelativeConstraintMapHorizontal.set(r,[]),t.dummyToNodeForVerticalAlignment.has(r)?t.nodeToTempPositionMapHorizontal.set(r,t.idToNodeMap.get(t.dummyToNodeForVerticalAlignment.get(r)[0]).getCenterX()):t.nodeToTempPositionMapHorizontal.set(r,t.idToNodeMap.get(r).getCenterX())),t.nodeToRelativeConstraintMapHorizontal.get(i).push({right:r,gap:e.gap}),t.nodeToRelativeConstraintMapHorizontal.get(r).push({left:i,gap:e.gap})}else{var n=a.has(e.top)?a.get(e.top):e.top,o=a.has(e.bottom)?a.get(e.bottom):e.bottom;t.nodesInRelativeVertical.includes(n)||(t.nodesInRelativeVertical.push(n),t.nodeToRelativeConstraintMapVertical.set(n,[]),t.dummyToNodeForHorizontalAlignment.has(n)?t.nodeToTempPositionMapVertical.set(n,t.idToNodeMap.get(t.dummyToNodeForHorizontalAlignment.get(n)[0]).getCenterY()):t.nodeToTempPositionMapVertical.set(n,t.idToNodeMap.get(n).getCenterY())),t.nodesInRelativeVertical.includes(o)||(t.nodesInRelativeVertical.push(o),t.nodeToRelativeConstraintMapVertical.set(o,[]),t.dummyToNodeForHorizontalAlignment.has(o)?t.nodeToTempPositionMapVertical.set(o,t.idToNodeMap.get(t.dummyToNodeForHorizontalAlignment.get(o)[0]).getCenterY()):t.nodeToTempPositionMapVertical.set(o,t.idToNodeMap.get(o).getCenterY())),t.nodeToRelativeConstraintMapVertical.get(n).push({bottom:o,gap:e.gap}),t.nodeToRelativeConstraintMapVertical.get(o).push({top:n,gap:e.gap})}}));else{var d=new Map,g=new Map;this.constraints.relativePlacementConstraint.forEach((function(t){if(t.left){var e=s.has(t.left)?s.get(t.left):t.left,i=s.has(t.right)?s.get(t.right):t.right;d.has(e)?d.get(e).push(i):d.set(e,[i]),d.has(i)?d.get(i).push(e):d.set(i,[e])}else{var r=a.has(t.top)?a.get(t.top):t.top,n=a.has(t.bottom)?a.get(t.bottom):t.bottom;g.has(r)?g.get(r).push(n):g.set(r,[n]),g.has(n)?g.get(n).push(r):g.set(n,[r])}}));var u=function(t,e){var i=[],r=[],n=new N,o=new Set,s=0;return t.forEach((function(a,h){if(!o.has(h)){i[s]=[],r[s]=!1;var l=h;for(n.push(l),o.add(l),i[s].push(l);0!=n.length;)l=n.shift(),e.has(l)&&(r[s]=!0),t.get(l).forEach((function(t){o.has(t)||(n.push(t),o.add(t),i[s].push(t))}));s++}})),{components:i,isFixed:r}},p=u(d,t.fixedNodesOnHorizontal);this.componentsOnHorizontal=p.components,this.fixedComponentsOnHorizontal=p.isFixed;var f=u(g,t.fixedNodesOnVertical);this.componentsOnVertical=f.components,this.fixedComponentsOnVertical=f.isFixed}}},T.prototype.updateDisplacements=function(){var t=this;if(this.constraints.fixedNodeConstraint&&this.constraints.fixedNodeConstraint.forEach((function(e){var i=t.idToNodeMap.get(e.nodeId);i.displacementX=0,i.displacementY=0})),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var e=this.constraints.alignmentConstraint.vertical,i=0;i1)for(a=0;ar&&(r=Math.floor(s.y)),o=Math.floor(s.x+h.DEFAULT_COMPONENT_SEPERATION)}this.transform(new u(d.WORLD_CENTER_X-s.x/2,d.WORLD_CENTER_Y-s.y/2))},T.radialLayout=function(t,e,i){var r=Math.max(this.maxDiagonalInTree(t),h.DEFAULT_RADIAL_SEPARATION);T.branchRadialLayout(e,null,0,359,0,r);var n=m.calculateBounds(t),o=new E;o.setDeviceOrgX(n.getMinX()),o.setDeviceOrgY(n.getMinY()),o.setWorldOrgX(i.x),o.setWorldOrgY(i.y);for(var s=0;s1;){var v=f[0];f.splice(0,1);var m=c.indexOf(v);m>=0&&c.splice(m,1),p--,d--}g=null!=e?(c.indexOf(f[0])+1)%p:0;for(var E=Math.abs(r-i)/d,N=g;u!=d;N=++N%p){var A=c[N].getOtherEnd(t);if(A!=e){var w=(i+u*E)%360,L=(w+E)%360;T.branchRadialLayout(A,t,w,L,n+o,o),u++}}},T.maxDiagonalInTree=function(t){for(var e=v.MIN_VALUE,i=0;ie&&(e=r)}return e},T.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},T.prototype.groupZeroDegreeMembers=function(){var t=this,e={};this.memberGroups={},this.idToDummyNode={};for(var i=[],r=this.graphManager.getAllNodes(),n=0;n1){var r="DummyCompound_"+i;t.memberGroups[r]=e[i];var n=e[i][0].getParent(),o=new s(t.graphManager);o.id=r,o.paddingLeft=n.paddingLeft||0,o.paddingRight=n.paddingRight||0,o.paddingBottom=n.paddingBottom||0,o.paddingTop=n.paddingTop||0,t.idToDummyNode[r]=o;var a=t.getGraphManager().add(t.newGraph(),o),h=n.getChild();h.add(o);for(var l=0;ln?(r.rect.x-=(r.labelWidth-n)/2,r.setWidth(r.labelWidth),r.labelMarginLeft=(r.labelWidth-n)/2):"right"==r.labelPosHorizontal&&r.setWidth(n+r.labelWidth)),r.labelHeight&&("top"==r.labelPosVertical?(r.rect.y-=r.labelHeight,r.setHeight(o+r.labelHeight),r.labelMarginTop=r.labelHeight):"center"==r.labelPosVertical&&r.labelHeight>o?(r.rect.y-=(r.labelHeight-o)/2,r.setHeight(r.labelHeight),r.labelMarginTop=(r.labelHeight-o)/2):"bottom"==r.labelPosVertical&&r.setHeight(o+r.labelHeight))}}))},T.prototype.repopulateCompounds=function(){for(var t=this.compoundOrder.length-1;t>=0;t--){var e=this.compoundOrder[t],i=e.id,r=e.paddingLeft,n=e.paddingTop,o=e.labelMarginLeft,s=e.labelMarginTop;this.adjustLocations(this.tiledMemberPack[i],e.rect.x,e.rect.y,r,n,o,s)}},T.prototype.repopulateZeroDegreeMembers=function(){var t=this,e=this.tiledZeroDegreePack;Object.keys(e).forEach((function(i){var r=t.idToDummyNode[i],n=r.paddingLeft,o=r.paddingTop,s=r.labelMarginLeft,a=r.labelMarginTop;t.adjustLocations(e[i],r.rect.x,r.rect.y,n,o,s,a)}))},T.prototype.getToBeTiled=function(t){var e=t.id;if(null!=this.toBeTiled[e])return this.toBeTiled[e];var i=t.getChild();if(null==i)return this.toBeTiled[e]=!1,!1;for(var r=i.getNodes(),n=0;n0)return this.toBeTiled[e]=!1,!1;if(null!=o.getChild()){if(!this.getToBeTiled(o))return this.toBeTiled[e]=!1,!1}else this.toBeTiled[o.id]=!1}return this.toBeTiled[e]=!0,!0},T.prototype.getNodeDegree=function(t){t.id;for(var e=t.getEdges(),i=0,r=0;rc&&(c=g.rect.height)}i+=c+t.verticalPadding}},T.prototype.tileCompoundMembers=function(t,e){var i=this;this.tiledMemberPack=[],Object.keys(t).forEach((function(r){var n=e[r];if(i.tiledMemberPack[r]=i.tileNodes(t[r],n.paddingLeft+n.paddingRight),n.rect.width=i.tiledMemberPack[r].width,n.rect.height=i.tiledMemberPack[r].height,n.setCenter(i.tiledMemberPack[r].centerX,i.tiledMemberPack[r].centerY),n.labelMarginLeft=0,n.labelMarginTop=0,h.NODE_DIMENSIONS_INCLUDE_LABELS){var o=n.rect.width,s=n.rect.height;n.labelWidth&&("left"==n.labelPosHorizontal?(n.rect.x-=n.labelWidth,n.setWidth(o+n.labelWidth),n.labelMarginLeft=n.labelWidth):"center"==n.labelPosHorizontal&&n.labelWidth>o?(n.rect.x-=(n.labelWidth-o)/2,n.setWidth(n.labelWidth),n.labelMarginLeft=(n.labelWidth-o)/2):"right"==n.labelPosHorizontal&&n.setWidth(o+n.labelWidth)),n.labelHeight&&("top"==n.labelPosVertical?(n.rect.y-=n.labelHeight,n.setHeight(s+n.labelHeight),n.labelMarginTop=n.labelHeight):"center"==n.labelPosVertical&&n.labelHeight>s?(n.rect.y-=(n.labelHeight-s)/2,n.setHeight(n.labelHeight),n.labelMarginTop=(n.labelHeight-s)/2):"bottom"==n.labelPosVertical&&n.setHeight(s+n.labelHeight))}}))},T.prototype.tileNodes=function(t,e){var i=this.tileNodesByFavoringDim(t,e,!0),r=this.tileNodesByFavoringDim(t,e,!1),n=this.getOrgRatio(i);return this.getOrgRatio(r)a&&(a=t.getWidth())}));var l,c=o/n,d=s/n,g=Math.pow(i-r,2)+4*(c+r)*(d+i)*n,u=(r-i+Math.sqrt(g))/(2*(c+r));e?(l=Math.ceil(u))==u&&l++:l=Math.floor(u);var p=l*(c+r)-r;return a>p&&(p=a),p+=2*r},T.prototype.tileNodesByFavoringDim=function(t,e,i){var r=h.TILING_PADDING_VERTICAL,n=h.TILING_PADDING_HORIZONTAL,o=h.TILING_COMPARE_BY,s={rows:[],rowWidth:[],rowHeight:[],width:0,height:e,verticalPadding:r,horizontalPadding:n,centerX:0,centerY:0};o&&(s.idealRowWidth=this.calcIdealRowWidth(t,i));var a=function(t){return t.rect.width*t.rect.height},l=function(t,e){return a(e)-a(t)};t.sort((function(t,e){var i=l;return s.idealRowWidth?(i=o)(t.id,e.id):i(t,e)}));for(var c=0,d=0,g=0;g0&&(o+=t.horizontalPadding),t.rowWidth[i]=o,t.width0&&(s+=t.verticalPadding);var a=0;s>t.rowHeight[i]&&(a=t.rowHeight[i],t.rowHeight[i]=s,a=t.rowHeight[i]-a),t.height+=a,t.rows[i].push(e)},T.prototype.getShortestRowIndex=function(t){for(var e=-1,i=Number.MAX_VALUE,r=0;ri&&(e=r,i=t.rowWidth[r]);return e},T.prototype.canAddHorizontal=function(t,e,i){if(t.idealRowWidth){var r=t.rows.length-1;return t.rowWidth[r]+e+t.horizontalPadding<=t.idealRowWidth}var n=this.getShortestRowIndex(t);if(n<0)return!0;var o=t.rowWidth[n];if(o+t.horizontalPadding+e<=t.width)return!0;var s,a,h=0;return t.rowHeight[n]0&&(h=i+t.verticalPadding-t.rowHeight[n]),s=t.width-o>=e+t.horizontalPadding?(t.height+h)/(o+e+t.horizontalPadding):(t.height+h)/t.width,h=i+t.verticalPadding,(a=t.widtho&&e!=i){r.splice(-1,1),t.rows[i].push(n),t.rowWidth[e]=t.rowWidth[e]-o,t.rowWidth[i]=t.rowWidth[i]+o,t.width=t.rowWidth[instance.getLongestRowIndex(t)];for(var s=Number.MIN_VALUE,a=0;as&&(s=r[a].height);e>0&&(s+=t.verticalPadding);var h=t.rowHeight[e]+t.rowHeight[i];t.rowHeight[e]=s,t.rowHeight[i]0)for(var d=n;d<=o;d++)l[0]+=this.grid[d][s-1].length+this.grid[d][s].length-1;if(o0)for(d=s;d<=a;d++)l[3]+=this.grid[n-1][d].length+this.grid[n][d].length-1;for(var g,u,p=v.MAX_VALUE,f=0;f{var r=i(551).FDLayoutNode,n=i(551).IMath;function o(t,e,i,n){r.call(this,t,e,i,n)}for(var s in o.prototype=Object.create(r.prototype),r)o[s]=r[s];o.prototype.calculateDisplacement=function(){var t=this.graphManager.getLayout();null!=this.getChild()&&this.fixedNodeWeight?(this.displacementX+=t.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.fixedNodeWeight,this.displacementY+=t.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.fixedNodeWeight):(this.displacementX+=t.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY+=t.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren),Math.abs(this.displacementX)>t.coolingFactor*t.maxNodeDisplacement&&(this.displacementX=t.coolingFactor*t.maxNodeDisplacement*n.sign(this.displacementX)),Math.abs(this.displacementY)>t.coolingFactor*t.maxNodeDisplacement&&(this.displacementY=t.coolingFactor*t.maxNodeDisplacement*n.sign(this.displacementY)),this.child&&this.child.getNodes().length>0&&this.propogateDisplacementToChildren(this.displacementX,this.displacementY)},o.prototype.propogateDisplacementToChildren=function(t,e){for(var i,r=this.getChild().getNodes(),n=0;n{function r(t){if(Array.isArray(t)){for(var e=0,i=Array(t.length);e0){var o=0;r.forEach((function(t){"horizontal"==e?(d.set(t,h.has(t)?l[h.get(t)]:n.get(t)),o+=d.get(t)):(d.set(t,h.has(t)?c[h.get(t)]:n.get(t)),o+=d.get(t))})),o/=r.length,t.forEach((function(t){i.has(t)||d.set(t,o)}))}else{var s=0;t.forEach((function(t){s+="horizontal"==e?h.has(t)?l[h.get(t)]:n.get(t):h.has(t)?c[h.get(t)]:n.get(t)})),s/=t.length,t.forEach((function(t){d.set(t,s)}))}}));for(var p=function(){var r=u.shift();t.get(r).forEach((function(t){if(d.get(t.id)s&&(s=m),Ea&&(a=E)}}catch(C){u=!0,p=C}finally{try{!g&&v.return&&v.return()}finally{if(u)throw p}}var N=(r+s)/2-(o+a)/2,T=!0,A=!1,w=void 0;try{for(var L,I=t[Symbol.iterator]();!(T=(L=I.next()).done);T=!0){var _=L.value;d.set(_,d.get(_)+N)}}catch(C){A=!0,w=C}finally{try{!T&&I.return&&I.return()}finally{if(A)throw w}}}))}return d},y=function(t){var e=0,i=0,r=0,n=0;if(t.forEach((function(t){t.left?l[h.get(t.left)]-l[h.get(t.right)]>=0?e++:i++:c[h.get(t.top)]-c[h.get(t.bottom)]>=0?r++:n++})),e>i&&r>n)for(var o=0;oi)for(var s=0;sn)for(var a=0;a1)e.fixedNodeConstraint.forEach((function(t,e){T[e]=[t.position.x,t.position.y],A[e]=[l[h.get(t.nodeId)],c[h.get(t.nodeId)]]})),w=!0;else if(e.alignmentConstraint)!function(){var t=0;if(e.alignmentConstraint.vertical){for(var i=e.alignmentConstraint.vertical,n=function(e){var n=new Set;i[e].forEach((function(t){n.add(t)}));var o=new Set([].concat(r(n)).filter((function(t){return I.has(t)}))),s=void 0;s=o.size>0?l[h.get(o.values().next().value)]:f(n).x,i[e].forEach((function(e){T[t]=[s,c[h.get(e)]],A[t]=[l[h.get(e)],c[h.get(e)]],t++}))},o=0;o0?l[h.get(n.values().next().value)]:f(i).y,s[e].forEach((function(e){T[t]=[l[h.get(e)],o],A[t]=[l[h.get(e)],c[h.get(e)]],t++}))},d=0;dx&&(x=M[D].length,O=D);if(x0){var j={x:0,y:0};e.fixedNodeConstraint.forEach((function(t,e){var i,r,n={x:l[h.get(t.nodeId)],y:c[h.get(t.nodeId)]},o=t.position,s=(r=n,{x:(i=o).x-r.x,y:i.y-r.y});j.x+=s.x,j.y+=s.y})),j.x/=e.fixedNodeConstraint.length,j.y/=e.fixedNodeConstraint.length,l.forEach((function(t,e){l[e]+=j.x})),c.forEach((function(t,e){c[e]+=j.y})),e.fixedNodeConstraint.forEach((function(t){l[h.get(t.nodeId)]=t.position.x,c[h.get(t.nodeId)]=t.position.y}))}if(e.alignmentConstraint){if(e.alignmentConstraint.vertical)for(var q=e.alignmentConstraint.vertical,$=function(t){var e=new Set;q[t].forEach((function(t){e.add(t)}));var i=new Set([].concat(r(e)).filter((function(t){return I.has(t)}))),n=void 0;n=i.size>0?l[h.get(i.values().next().value)]:f(e).x,e.forEach((function(t){I.has(t)||(l[h.get(t)]=n)}))},K=0;K0?c[h.get(i.values().next().value)]:f(e).y,e.forEach((function(t){I.has(t)||(c[h.get(t)]=n)}))},J=0;J{e.exports=t}},i={},r=function t(r){var n=i[r];if(void 0!==n)return n.exports;var o=i[r]={exports:{}};return e[r](o,o.exports,t),o.exports}(45);return r})()},t.exports=r(i(1917))},1917:function(t){var e;e=function(){return function(t){var e={};function i(r){if(e[r])return e[r].exports;var n=e[r]={i:r,l:!1,exports:{}};return t[r].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=t,i.c=e,i.i=function(t){return t},i.d=function(t,e,r){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=28)}([function(t,e,i){"use strict";function r(){}r.QUALITY=1,r.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,r.DEFAULT_INCREMENTAL=!1,r.DEFAULT_ANIMATION_ON_LAYOUT=!0,r.DEFAULT_ANIMATION_DURING_LAYOUT=!1,r.DEFAULT_ANIMATION_PERIOD=50,r.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,r.DEFAULT_GRAPH_MARGIN=15,r.NODE_DIMENSIONS_INCLUDE_LABELS=!1,r.SIMPLE_NODE_SIZE=40,r.SIMPLE_NODE_HALF_SIZE=r.SIMPLE_NODE_SIZE/2,r.EMPTY_COMPOUND_NODE_SIZE=40,r.MIN_EDGE_LENGTH=1,r.WORLD_BOUNDARY=1e6,r.INITIAL_WORLD_BOUNDARY=r.WORLD_BOUNDARY/1e3,r.WORLD_CENTER_X=1200,r.WORLD_CENTER_Y=900,t.exports=r},function(t,e,i){"use strict";var r=i(2),n=i(8),o=i(9);function s(t,e,i){r.call(this,i),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=i,this.bendpoints=[],this.source=t,this.target=e}for(var a in s.prototype=Object.create(r.prototype),r)s[a]=r[a];s.prototype.getSource=function(){return this.source},s.prototype.getTarget=function(){return this.target},s.prototype.isInterGraph=function(){return this.isInterGraph},s.prototype.getLength=function(){return this.length},s.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},s.prototype.getBendpoints=function(){return this.bendpoints},s.prototype.getLca=function(){return this.lca},s.prototype.getSourceInLca=function(){return this.sourceInLca},s.prototype.getTargetInLca=function(){return this.targetInLca},s.prototype.getOtherEnd=function(t){if(this.source===t)return this.target;if(this.target===t)return this.source;throw"Node is not incident with this edge"},s.prototype.getOtherEndInGraph=function(t,e){for(var i=this.getOtherEnd(t),r=e.getGraphManager().getRoot();;){if(i.getOwner()==e)return i;if(i.getOwner()==r)break;i=i.getOwner().getParent()}return null},s.prototype.updateLength=function(){var t=new Array(4);this.isOverlapingSourceAndTarget=n.getIntersection(this.target.getRect(),this.source.getRect(),t),this.isOverlapingSourceAndTarget||(this.lengthX=t[0]-t[2],this.lengthY=t[1]-t[3],Math.abs(this.lengthX)<1&&(this.lengthX=o.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=o.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},s.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=o.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=o.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},t.exports=s},function(t,e,i){"use strict";t.exports=function(t){this.vGraphObject=t}},function(t,e,i){"use strict";var r=i(2),n=i(10),o=i(13),s=i(0),a=i(16),h=i(5);function l(t,e,i,s){null==i&&null==s&&(s=e),r.call(this,s),null!=t.graphManager&&(t=t.graphManager),this.estimatedSize=n.MIN_VALUE,this.inclusionTreeDepth=n.MAX_VALUE,this.vGraphObject=s,this.edges=[],this.graphManager=t,this.rect=null!=i&&null!=e?new o(e.x,e.y,i.width,i.height):new o}for(var c in l.prototype=Object.create(r.prototype),r)l[c]=r[c];l.prototype.getEdges=function(){return this.edges},l.prototype.getChild=function(){return this.child},l.prototype.getOwner=function(){return this.owner},l.prototype.getWidth=function(){return this.rect.width},l.prototype.setWidth=function(t){this.rect.width=t},l.prototype.getHeight=function(){return this.rect.height},l.prototype.setHeight=function(t){this.rect.height=t},l.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},l.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},l.prototype.getCenter=function(){return new h(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},l.prototype.getLocation=function(){return new h(this.rect.x,this.rect.y)},l.prototype.getRect=function(){return this.rect},l.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},l.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},l.prototype.setRect=function(t,e){this.rect.x=t.x,this.rect.y=t.y,this.rect.width=e.width,this.rect.height=e.height},l.prototype.setCenter=function(t,e){this.rect.x=t-this.rect.width/2,this.rect.y=e-this.rect.height/2},l.prototype.setLocation=function(t,e){this.rect.x=t,this.rect.y=e},l.prototype.moveBy=function(t,e){this.rect.x+=t,this.rect.y+=e},l.prototype.getEdgeListToNode=function(t){var e=[],i=this;return i.edges.forEach((function(r){if(r.target==t){if(r.source!=i)throw"Incorrect edge source!";e.push(r)}})),e},l.prototype.getEdgesBetween=function(t){var e=[],i=this;return i.edges.forEach((function(r){if(r.source!=i&&r.target!=i)throw"Incorrect edge source and/or target";r.target!=t&&r.source!=t||e.push(r)})),e},l.prototype.getNeighborsList=function(){var t=new Set,e=this;return e.edges.forEach((function(i){if(i.source==e)t.add(i.target);else{if(i.target!=e)throw"Incorrect incidency!";t.add(i.source)}})),t},l.prototype.withChildren=function(){var t=new Set;if(t.add(this),null!=this.child)for(var e=this.child.getNodes(),i=0;ie?(this.rect.x-=(this.labelWidth-e)/2,this.setWidth(this.labelWidth)):"right"==this.labelPosHorizontal&&this.setWidth(e+this.labelWidth)),this.labelHeight&&("top"==this.labelPosVertical?(this.rect.y-=this.labelHeight,this.setHeight(i+this.labelHeight)):"center"==this.labelPosVertical&&this.labelHeight>i?(this.rect.y-=(this.labelHeight-i)/2,this.setHeight(this.labelHeight)):"bottom"==this.labelPosVertical&&this.setHeight(i+this.labelHeight))}}},l.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==n.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},l.prototype.transform=function(t){var e=this.rect.x;e>s.WORLD_BOUNDARY?e=s.WORLD_BOUNDARY:e<-s.WORLD_BOUNDARY&&(e=-s.WORLD_BOUNDARY);var i=this.rect.y;i>s.WORLD_BOUNDARY?i=s.WORLD_BOUNDARY:i<-s.WORLD_BOUNDARY&&(i=-s.WORLD_BOUNDARY);var r=new h(e,i),n=t.inverseTransformPoint(r);this.setLocation(n.x,n.y)},l.prototype.getLeft=function(){return this.rect.x},l.prototype.getRight=function(){return this.rect.x+this.rect.width},l.prototype.getTop=function(){return this.rect.y},l.prototype.getBottom=function(){return this.rect.y+this.rect.height},l.prototype.getParent=function(){return null==this.owner?null:this.owner.getParent()},t.exports=l},function(t,e,i){"use strict";var r=i(0);function n(){}for(var o in r)n[o]=r[o];n.MAX_ITERATIONS=2500,n.DEFAULT_EDGE_LENGTH=50,n.DEFAULT_SPRING_STRENGTH=.45,n.DEFAULT_REPULSION_STRENGTH=4500,n.DEFAULT_GRAVITY_STRENGTH=.4,n.DEFAULT_COMPOUND_GRAVITY_STRENGTH=1,n.DEFAULT_GRAVITY_RANGE_FACTOR=3.8,n.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=1.5,n.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION=!0,n.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION=!0,n.DEFAULT_COOLING_FACTOR_INCREMENTAL=.3,n.COOLING_ADAPTATION_FACTOR=.33,n.ADAPTATION_LOWER_NODE_LIMIT=1e3,n.ADAPTATION_UPPER_NODE_LIMIT=5e3,n.MAX_NODE_DISPLACEMENT_INCREMENTAL=100,n.MAX_NODE_DISPLACEMENT=3*n.MAX_NODE_DISPLACEMENT_INCREMENTAL,n.MIN_REPULSION_DIST=n.DEFAULT_EDGE_LENGTH/10,n.CONVERGENCE_CHECK_PERIOD=100,n.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=.1,n.MIN_EDGE_LENGTH=1,n.GRID_CALCULATION_CHECK_PERIOD=10,t.exports=n},function(t,e,i){"use strict";function r(t,e){null==t&&null==e?(this.x=0,this.y=0):(this.x=t,this.y=e)}r.prototype.getX=function(){return this.x},r.prototype.getY=function(){return this.y},r.prototype.setX=function(t){this.x=t},r.prototype.setY=function(t){this.y=t},r.prototype.getDifference=function(t){return new DimensionD(this.x-t.x,this.y-t.y)},r.prototype.getCopy=function(){return new r(this.x,this.y)},r.prototype.translate=function(t){return this.x+=t.width,this.y+=t.height,this},t.exports=r},function(t,e,i){"use strict";var r=i(2),n=i(10),o=i(0),s=i(7),a=i(3),h=i(1),l=i(13),c=i(12),d=i(11);function g(t,e,i){r.call(this,i),this.estimatedSize=n.MIN_VALUE,this.margin=o.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=t,null!=e&&e instanceof s?this.graphManager=e:null!=e&&e instanceof Layout&&(this.graphManager=e.graphManager)}for(var u in g.prototype=Object.create(r.prototype),r)g[u]=r[u];g.prototype.getNodes=function(){return this.nodes},g.prototype.getEdges=function(){return this.edges},g.prototype.getGraphManager=function(){return this.graphManager},g.prototype.getParent=function(){return this.parent},g.prototype.getLeft=function(){return this.left},g.prototype.getRight=function(){return this.right},g.prototype.getTop=function(){return this.top},g.prototype.getBottom=function(){return this.bottom},g.prototype.isConnected=function(){return this.isConnected},g.prototype.add=function(t,e,i){if(null==e&&null==i){var r=t;if(null==this.graphManager)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(r)>-1)throw"Node already in graph!";return r.owner=this,this.getNodes().push(r),r}var n=t;if(!(this.getNodes().indexOf(e)>-1&&this.getNodes().indexOf(i)>-1))throw"Source or target not in graph!";if(e.owner!=i.owner||e.owner!=this)throw"Both owners must be this graph!";return e.owner!=i.owner?null:(n.source=e,n.target=i,n.isInterGraph=!1,this.getEdges().push(n),e.edges.push(n),i!=e&&i.edges.push(n),n)},g.prototype.remove=function(t){var e=t;if(t instanceof a){if(null==e)throw"Node is null!";if(null==e.owner||e.owner!=this)throw"Owner graph is invalid!";if(null==this.graphManager)throw"Owner graph manager is invalid!";for(var i=e.edges.slice(),r=i.length,n=0;n-1&&c>-1))throw"Source and/or target doesn't know this edge!";if(o.source.edges.splice(l,1),o.target!=o.source&&o.target.edges.splice(c,1),-1==(s=o.source.owner.getEdges().indexOf(o)))throw"Not in owner's edge list!";o.source.owner.getEdges().splice(s,1)}},g.prototype.updateLeftTop=function(){for(var t,e,i,r=n.MAX_VALUE,o=n.MAX_VALUE,s=this.getNodes(),a=s.length,h=0;h(t=l.getTop())&&(r=t),o>(e=l.getLeft())&&(o=e)}return r==n.MAX_VALUE?null:(i=null!=s[0].getParent().paddingLeft?s[0].getParent().paddingLeft:this.margin,this.left=o-i,this.top=r-i,new c(this.left,this.top))},g.prototype.updateBounds=function(t){for(var e,i,r,o,s,a=n.MAX_VALUE,h=-n.MAX_VALUE,c=n.MAX_VALUE,d=-n.MAX_VALUE,g=this.nodes,u=g.length,p=0;p(e=f.getLeft())&&(a=e),h<(i=f.getRight())&&(h=i),c>(r=f.getTop())&&(c=r),d<(o=f.getBottom())&&(d=o)}var v=new l(a,c,h-a,d-c);a==n.MAX_VALUE&&(this.left=this.parent.getLeft(),this.right=this.parent.getRight(),this.top=this.parent.getTop(),this.bottom=this.parent.getBottom()),s=null!=g[0].getParent().paddingLeft?g[0].getParent().paddingLeft:this.margin,this.left=v.x-s,this.right=v.x+v.width+s,this.top=v.y-s,this.bottom=v.y+v.height+s},g.calculateBounds=function(t){for(var e,i,r,o,s=n.MAX_VALUE,a=-n.MAX_VALUE,h=n.MAX_VALUE,c=-n.MAX_VALUE,d=t.length,g=0;g(e=u.getLeft())&&(s=e),a<(i=u.getRight())&&(a=i),h>(r=u.getTop())&&(h=r),c<(o=u.getBottom())&&(c=o)}return new l(s,h,a-s,c-h)},g.prototype.getInclusionTreeDepth=function(){return this==this.graphManager.getRoot()?1:this.parent.getInclusionTreeDepth()},g.prototype.getEstimatedSize=function(){if(this.estimatedSize==n.MIN_VALUE)throw"assert failed";return this.estimatedSize},g.prototype.calcEstimatedSize=function(){for(var t=0,e=this.nodes,i=e.length,r=0;r=this.nodes.length){var h=0;n.forEach((function(e){e.owner==t&&h++})),h==this.nodes.length&&(this.isConnected=!0)}}else this.isConnected=!0},t.exports=g},function(t,e,i){"use strict";var r,n=i(1);function o(t){r=i(6),this.layout=t,this.graphs=[],this.edges=[]}o.prototype.addRoot=function(){var t=this.layout.newGraph(),e=this.layout.newNode(null),i=this.add(t,e);return this.setRootGraph(i),this.rootGraph},o.prototype.add=function(t,e,i,r,n){if(null==i&&null==r&&null==n){if(null==t)throw"Graph is null!";if(null==e)throw"Parent node is null!";if(this.graphs.indexOf(t)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(t),null!=t.parent)throw"Already has a parent!";if(null!=e.child)throw"Already has a child!";return t.parent=e,e.child=t,t}n=i,i=t;var o=(r=e).getOwner(),s=n.getOwner();if(null==o||o.getGraphManager()!=this)throw"Source not in this graph mgr!";if(null==s||s.getGraphManager()!=this)throw"Target not in this graph mgr!";if(o==s)return i.isInterGraph=!1,o.add(i,r,n);if(i.isInterGraph=!0,i.source=r,i.target=n,this.edges.indexOf(i)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(i),null==i.source||null==i.target)throw"Edge source and/or target is null!";if(-1!=i.source.edges.indexOf(i)||-1!=i.target.edges.indexOf(i))throw"Edge already in source and/or target incidency list!";return i.source.edges.push(i),i.target.edges.push(i),i},o.prototype.remove=function(t){if(t instanceof r){var e=t;if(e.getGraphManager()!=this)throw"Graph not in this graph mgr";if(e!=this.rootGraph&&(null==e.parent||e.parent.graphManager!=this))throw"Invalid parent node!";for(var i,o=[],s=(o=o.concat(e.getEdges())).length,a=0;a=e.getRight()?i[0]+=Math.min(e.getX()-t.getX(),t.getRight()-e.getRight()):e.getX()<=t.getX()&&e.getRight()>=t.getRight()&&(i[0]+=Math.min(t.getX()-e.getX(),e.getRight()-t.getRight())),t.getY()<=e.getY()&&t.getBottom()>=e.getBottom()?i[1]+=Math.min(e.getY()-t.getY(),t.getBottom()-e.getBottom()):e.getY()<=t.getY()&&e.getBottom()>=t.getBottom()&&(i[1]+=Math.min(t.getY()-e.getY(),e.getBottom()-t.getBottom()));var o=Math.abs((e.getCenterY()-t.getCenterY())/(e.getCenterX()-t.getCenterX()));e.getCenterY()===t.getCenterY()&&e.getCenterX()===t.getCenterX()&&(o=1);var s=o*i[0],a=i[1]/o;i[0]s)return i[0]=r,i[1]=h,i[2]=o,i[3]=E,!1;if(no)return i[0]=a,i[1]=n,i[2]=y,i[3]=s,!1;if(ro?(i[0]=c,i[1]=d,w=!0):(i[0]=l,i[1]=h,w=!0):I===C&&(r>o?(i[0]=a,i[1]=h,w=!0):(i[0]=g,i[1]=d,w=!0)),-_===C?o>r?(i[2]=m,i[3]=E,L=!0):(i[2]=y,i[3]=v,L=!0):_===C&&(o>r?(i[2]=f,i[3]=v,L=!0):(i[2]=N,i[3]=E,L=!0)),w&&L)return!1;if(r>o?n>s?(M=this.getCardinalDirection(I,C,4),x=this.getCardinalDirection(_,C,2)):(M=this.getCardinalDirection(-I,C,3),x=this.getCardinalDirection(-_,C,1)):n>s?(M=this.getCardinalDirection(-I,C,1),x=this.getCardinalDirection(-_,C,3)):(M=this.getCardinalDirection(I,C,2),x=this.getCardinalDirection(_,C,4)),!w)switch(M){case 1:D=h,O=r+-p/C,i[0]=O,i[1]=D;break;case 2:O=g,D=n+u*C,i[0]=O,i[1]=D;break;case 3:D=d,O=r+p/C,i[0]=O,i[1]=D;break;case 4:O=c,D=n+-u*C,i[0]=O,i[1]=D}if(!L)switch(x){case 1:b=v,R=o+-A/C,i[2]=R,i[3]=b;break;case 2:R=N,b=s+T*C,i[2]=R,i[3]=b;break;case 3:b=E,R=o+A/C,i[2]=R,i[3]=b;break;case 4:R=m,b=s+-T*C,i[2]=R,i[3]=b}}return!1},n.getCardinalDirection=function(t,e,i){return t>e?i:1+i%4},n.getIntersection=function(t,e,i,n){if(null==n)return this.getIntersection2(t,e,i);var o,s,a,h,l,c,d,g=t.x,u=t.y,p=e.x,f=e.y,v=i.x,y=i.y,m=n.x,E=n.y;return 0==(d=(o=f-u)*(h=v-m)-(s=E-y)*(a=g-p))?null:new r((a*(c=m*y-v*E)-h*(l=p*u-g*f))/d,(s*l-o*c)/d)},n.angleOfVector=function(t,e,i,r){var n=void 0;return t!==i?(n=Math.atan((r-e)/(i-t)),i=0){var c=(-h+Math.sqrt(h*h-4*a*l))/(2*a),d=(-h-Math.sqrt(h*h-4*a*l))/(2*a);return c>=0&&c<=1?[c]:d>=0&&d<=1?[d]:null}return null},n.HALF_PI=.5*Math.PI,n.ONE_AND_HALF_PI=1.5*Math.PI,n.TWO_PI=2*Math.PI,n.THREE_PI=3*Math.PI,t.exports=n},function(t,e,i){"use strict";function r(){}r.sign=function(t){return t>0?1:t<0?-1:0},r.floor=function(t){return t<0?Math.ceil(t):Math.floor(t)},r.ceil=function(t){return t<0?Math.floor(t):Math.ceil(t)},t.exports=r},function(t,e,i){"use strict";function r(){}r.MAX_VALUE=2147483647,r.MIN_VALUE=-2147483648,t.exports=r},function(t,e,i){"use strict";var r=function(){function t(t,e){for(var i=0;i0&&e;){for(a.push(l[0]);a.length>0&&e;){var c=a[0];a.splice(0,1),s.add(c);var d=c.getEdges();for(o=0;o-1&&l.splice(f,1)}s=new Set,h=new Map}else t=[]}return t},g.prototype.createDummyNodesForBendpoints=function(t){for(var e=[],i=t.source,r=this.graphManager.calcLowestCommonAncestor(t.source,t.target),n=0;n0){for(var n=this.edgeToDummyNodes.get(i),o=0;o=0&&e.splice(d,1),c.getNeighborsList().forEach((function(t){if(i.indexOf(t)<0){var e=r.get(t)-1;1==e&&h.push(t),r.set(t,e)}}))}i=i.concat(h),1!=e.length&&2!=e.length||(n=!0,o=e[0])}return o},g.prototype.setGraphManager=function(t){this.graphManager=t},t.exports=g},function(t,e,i){"use strict";function r(){}r.seed=1,r.x=0,r.nextDouble=function(){return r.x=1e4*Math.sin(r.seed++),r.x-Math.floor(r.x)},t.exports=r},function(t,e,i){"use strict";var r=i(5);function n(t,e){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}n.prototype.getWorldOrgX=function(){return this.lworldOrgX},n.prototype.setWorldOrgX=function(t){this.lworldOrgX=t},n.prototype.getWorldOrgY=function(){return this.lworldOrgY},n.prototype.setWorldOrgY=function(t){this.lworldOrgY=t},n.prototype.getWorldExtX=function(){return this.lworldExtX},n.prototype.setWorldExtX=function(t){this.lworldExtX=t},n.prototype.getWorldExtY=function(){return this.lworldExtY},n.prototype.setWorldExtY=function(t){this.lworldExtY=t},n.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},n.prototype.setDeviceOrgX=function(t){this.ldeviceOrgX=t},n.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},n.prototype.setDeviceOrgY=function(t){this.ldeviceOrgY=t},n.prototype.getDeviceExtX=function(){return this.ldeviceExtX},n.prototype.setDeviceExtX=function(t){this.ldeviceExtX=t},n.prototype.getDeviceExtY=function(){return this.ldeviceExtY},n.prototype.setDeviceExtY=function(t){this.ldeviceExtY=t},n.prototype.transformX=function(t){var e=0,i=this.lworldExtX;return 0!=i&&(e=this.ldeviceOrgX+(t-this.lworldOrgX)*this.ldeviceExtX/i),e},n.prototype.transformY=function(t){var e=0,i=this.lworldExtY;return 0!=i&&(e=this.ldeviceOrgY+(t-this.lworldOrgY)*this.ldeviceExtY/i),e},n.prototype.inverseTransformX=function(t){var e=0,i=this.ldeviceExtX;return 0!=i&&(e=this.lworldOrgX+(t-this.ldeviceOrgX)*this.lworldExtX/i),e},n.prototype.inverseTransformY=function(t){var e=0,i=this.ldeviceExtY;return 0!=i&&(e=this.lworldOrgY+(t-this.ldeviceOrgY)*this.lworldExtY/i),e},n.prototype.inverseTransformPoint=function(t){return new r(this.inverseTransformX(t.x),this.inverseTransformY(t.y))},t.exports=n},function(t,e,i){"use strict";var r=i(15),n=i(4),o=i(0),s=i(8),a=i(9);function h(){r.call(this),this.useSmartIdealEdgeLengthCalculation=n.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.gravityConstant=n.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=n.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=n.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=n.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.displacementThresholdPerNode=3*n.DEFAULT_EDGE_LENGTH/100,this.coolingFactor=n.DEFAULT_COOLING_FACTOR_INCREMENTAL,this.initialCoolingFactor=n.DEFAULT_COOLING_FACTOR_INCREMENTAL,this.totalDisplacement=0,this.oldTotalDisplacement=0,this.maxIterations=n.MAX_ITERATIONS}for(var l in h.prototype=Object.create(r.prototype),r)h[l]=r[l];h.prototype.initParameters=function(){r.prototype.initParameters.call(this,arguments),this.totalIterations=0,this.notAnimatedIterations=0,this.useFRGridVariant=n.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION,this.grid=[]},h.prototype.calcIdealEdgeLengths=function(){for(var t,e,i,r,s,a,h,l=this.getGraphManager().getAllEdges(),c=0;cn.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*n.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(t-n.ADAPTATION_LOWER_NODE_LIMIT)/(n.ADAPTATION_UPPER_NODE_LIMIT-n.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-n.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=n.MAX_NODE_DISPLACEMENT_INCREMENTAL):(t>n.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(n.COOLING_ADAPTATION_FACTOR,1-(t-n.ADAPTATION_LOWER_NODE_LIMIT)/(n.ADAPTATION_UPPER_NODE_LIMIT-n.ADAPTATION_LOWER_NODE_LIMIT)*(1-n.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=n.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(5*this.getAllNodes().length,this.maxIterations),this.displacementThresholdPerNode=3*n.DEFAULT_EDGE_LENGTH/100,this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},h.prototype.calcSpringForces=function(){for(var t,e=this.getAllEdges(),i=0;i0&&void 0!==arguments[0])||arguments[0],a=arguments.length>1&&void 0!==arguments[1]&&arguments[1],h=this.getAllNodes();if(this.useFRGridVariant)for(this.totalIterations%n.GRID_CALCULATION_CHECK_PERIOD==1&&s&&this.updateGrid(),o=new Set,t=0;t(h=e.getEstimatedSize()*this.gravityRangeFactor)||a>h)&&(t.gravitationForceX=-this.gravityConstant*n,t.gravitationForceY=-this.gravityConstant*o):(s>(h=e.getEstimatedSize()*this.compoundGravityRangeFactor)||a>h)&&(t.gravitationForceX=-this.gravityConstant*n*this.compoundGravityConstant,t.gravitationForceY=-this.gravityConstant*o*this.compoundGravityConstant)},h.prototype.isConverged=function(){var t,e=!1;return this.totalIterations>this.maxIterations/3&&(e=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),t=this.totalDisplacement=a.length||l>=a[0].length))for(var c=0;ct}}]),t}();t.exports=o},function(t,e,i){"use strict";function r(){}r.svd=function(t){this.U=null,this.V=null,this.s=null,this.m=0,this.n=0,this.m=t.length,this.n=t[0].length;var e=Math.min(this.m,this.n);this.s=function(t){for(var e=[];t-- >0;)e.push(0);return e}(Math.min(this.m+1,this.n)),this.U=function t(e){if(0==e.length)return 0;for(var i=[],r=0;r0;)e.push(0);return e}(this.n),s=function(t){for(var e=[];t-- >0;)e.push(0);return e}(this.m),a=Math.min(this.m-1,this.n),h=Math.max(0,Math.min(this.n-2,this.m)),l=0;l=0;x--)if(0!==this.s[x]){for(var O=x+1;O=0;P--){if(function(t,e){return t&&e}(P0;){var W=void 0,j=void 0;for(W=_-2;W>=-1&&-1!==W;W--)if(Math.abs(o[W])<=B+V*(Math.abs(this.s[W])+Math.abs(this.s[W+1]))){o[W]=0;break}if(W===_-2)j=4;else{var q=void 0;for(q=_-1;q>=W&&q!==W;q--){var $=(q!==_?Math.abs(o[q]):0)+(q!==W+1?Math.abs(o[q-1]):0);if(Math.abs(this.s[q])<=B+V*$){this.s[q]=0;break}}q===W?j=3:q===_-1?j=1:(j=2,W=q)}switch(W++,j){case 1:var K=o[_-2];o[_-2]=0;for(var Z=_-2;Z>=W;Z--){var Q=r.hypot(this.s[Z],K),J=this.s[Z]/Q,tt=K/Q;this.s[Z]=Q,Z!==W&&(K=-tt*o[Z-1],o[Z-1]=J*o[Z-1]);for(var et=0;et=this.s[W+1]);){var _t=this.s[W];if(this.s[W]=this.s[W+1],this.s[W+1]=_t,WMath.abs(e)?(i=e/t,i=Math.abs(t)*Math.sqrt(1+i*i)):0!=e?(i=t/e,i=Math.abs(e)*Math.sqrt(1+i*i)):i=0,i},t.exports=r},function(t,e,i){"use strict";var r=function(){function t(t,e){for(var i=0;i2&&void 0!==arguments[2]?arguments[2]:1,n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:-1,o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.sequence1=e,this.sequence2=i,this.match_score=r,this.mismatch_penalty=n,this.gap_penalty=o,this.iMax=e.length+1,this.jMax=i.length+1,this.grid=new Array(this.iMax);for(var s=0;s=0;i--){var r=this.listeners[i];r.event===t&&r.callback===e&&this.listeners.splice(i,1)}},n.emit=function(t,e){for(var i=0;i{"use strict";i.d(e,{diagram:()=>dt});var r=i(64532),n=i(10483),o=i(63933),s=i(98160),a=(i(8159),i(77286)),h=i(10009),l=i(78731),c=i(90165),d=i(26527),g=i(20007),u={L:"left",R:"right",T:"top",B:"bottom"},p={L:(0,h.K2)((t=>`${t},${t/2} 0,${t} 0,0`),"L"),R:(0,h.K2)((t=>`0,${t/2} ${t},0 ${t},${t}`),"R"),T:(0,h.K2)((t=>`0,0 ${t},0 ${t/2},${t}`),"T"),B:(0,h.K2)((t=>`${t/2},0 ${t},${t} 0,${t}`),"B")},f={L:(0,h.K2)(((t,e)=>t-e+2),"L"),R:(0,h.K2)(((t,e)=>t-2),"R"),T:(0,h.K2)(((t,e)=>t-e+2),"T"),B:(0,h.K2)(((t,e)=>t-2),"B")},v=(0,h.K2)((function(t){return m(t)?"L"===t?"R":"L":"T"===t?"B":"T"}),"getOppositeArchitectureDirection"),y=(0,h.K2)((function(t){return"L"===t||"R"===t||"T"===t||"B"===t}),"isArchitectureDirection"),m=(0,h.K2)((function(t){return"L"===t||"R"===t}),"isArchitectureDirectionX"),E=(0,h.K2)((function(t){return"T"===t||"B"===t}),"isArchitectureDirectionY"),N=(0,h.K2)((function(t,e){const i=m(t)&&E(e),r=E(t)&&m(e);return i||r}),"isArchitectureDirectionXY"),T=(0,h.K2)((function(t){const e=t[0],i=t[1],r=m(e)&&E(i),n=E(e)&&m(i);return r||n}),"isArchitecturePairXY"),A=(0,h.K2)((function(t){return"LL"!==t&&"RR"!==t&&"TT"!==t&&"BB"!==t}),"isValidArchitectureDirectionPair"),w=(0,h.K2)((function(t,e){const i=`${t}${e}`;return A(i)?i:void 0}),"getArchitectureDirectionPair"),L=(0,h.K2)((function([t,e],i){const r=i[0],n=i[1];return m(r)?E(n)?[t+("L"===r?-1:1),e+("T"===n?1:-1)]:[t+("L"===r?-1:1),e]:m(n)?[t+("L"===n?1:-1),e+("T"===r?1:-1)]:[t,e+("T"===r?1:-1)]}),"shiftPositionByArchitectureDirectionPair"),I=(0,h.K2)((function(t){return"LT"===t||"TL"===t?[1,1]:"BL"===t||"LB"===t?[1,-1]:"BR"===t||"RB"===t?[-1,-1]:[-1,1]}),"getArchitectureDirectionXYFactors"),_=(0,h.K2)((function(t){return"service"===t.type}),"isArchitectureService"),C=(0,h.K2)((function(t){return"junction"===t.type}),"isArchitectureJunction"),M=(0,h.K2)((t=>t.data()),"edgeData"),x=(0,h.K2)((t=>t.data()),"nodeData"),O=h.UI.architecture,D=new s.m((()=>({nodes:{},groups:{},edges:[],registeredIds:{},config:O,dataStructures:void 0,elements:{}}))),R=(0,h.K2)((()=>{D.reset(),(0,h.IU)()}),"clear"),b=(0,h.K2)((function({id:t,icon:e,in:i,title:r,iconText:n}){if(void 0!==D.records.registeredIds[t])throw new Error(`The service id [${t}] is already in use by another ${D.records.registeredIds[t]}`);if(void 0!==i){if(t===i)throw new Error(`The service [${t}] cannot be placed within itself`);if(void 0===D.records.registeredIds[i])throw new Error(`The service [${t}]'s parent does not exist. Please make sure the parent is created before this service`);if("node"===D.records.registeredIds[i])throw new Error(`The service [${t}]'s parent is not a group`)}D.records.registeredIds[t]="node",D.records.nodes[t]={id:t,type:"service",icon:e,iconText:n,title:r,edges:[],in:i}}),"addService"),G=(0,h.K2)((()=>Object.values(D.records.nodes).filter(_)),"getServices"),F=(0,h.K2)((function({id:t,in:e}){D.records.registeredIds[t]="node",D.records.nodes[t]={id:t,type:"junction",edges:[],in:e}}),"addJunction"),S=(0,h.K2)((()=>Object.values(D.records.nodes).filter(C)),"getJunctions"),P=(0,h.K2)((()=>Object.values(D.records.nodes)),"getNodes"),U=(0,h.K2)((t=>D.records.nodes[t]),"getNode"),Y=(0,h.K2)((function({id:t,icon:e,in:i,title:r}){if(void 0!==D.records.registeredIds[t])throw new Error(`The group id [${t}] is already in use by another ${D.records.registeredIds[t]}`);if(void 0!==i){if(t===i)throw new Error(`The group [${t}] cannot be placed within itself`);if(void 0===D.records.registeredIds[i])throw new Error(`The group [${t}]'s parent does not exist. Please make sure the parent is created before this group`);if("node"===D.records.registeredIds[i])throw new Error(`The group [${t}]'s parent is not a group`)}D.records.registeredIds[t]="group",D.records.groups[t]={id:t,icon:e,title:r,in:i}}),"addGroup"),k=(0,h.K2)((()=>Object.values(D.records.groups)),"getGroups"),H=(0,h.K2)((function({lhsId:t,rhsId:e,lhsDir:i,rhsDir:r,lhsInto:n,rhsInto:o,lhsGroup:s,rhsGroup:a,title:h}){if(!y(i))throw new Error(`Invalid direction given for left hand side of edge ${t}--${e}. Expected (L,R,T,B) got ${i}`);if(!y(r))throw new Error(`Invalid direction given for right hand side of edge ${t}--${e}. Expected (L,R,T,B) got ${r}`);if(void 0===D.records.nodes[t]&&void 0===D.records.groups[t])throw new Error(`The left-hand id [${t}] does not yet exist. Please create the service/group before declaring an edge to it.`);if(void 0===D.records.nodes[e]&&void 0===D.records.groups[t])throw new Error(`The right-hand id [${e}] does not yet exist. Please create the service/group before declaring an edge to it.`);const l=D.records.nodes[t].in,c=D.records.nodes[e].in;if(s&&l&&c&&l==c)throw new Error(`The left-hand id [${t}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);if(a&&l&&c&&l==c)throw new Error(`The right-hand id [${e}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);const d={lhsId:t,lhsDir:i,lhsInto:n,lhsGroup:s,rhsId:e,rhsDir:r,rhsInto:o,rhsGroup:a,title:h};D.records.edges.push(d),D.records.nodes[t]&&D.records.nodes[e]&&(D.records.nodes[t].edges.push(D.records.edges[D.records.edges.length-1]),D.records.nodes[e].edges.push(D.records.edges[D.records.edges.length-1]))}),"addEdge"),X=(0,h.K2)((()=>D.records.edges),"getEdges"),z=(0,h.K2)((()=>{if(void 0===D.records.dataStructures){const t=Object.entries(D.records.nodes).reduce(((t,[e,i])=>(t[e]=i.edges.reduce(((t,i)=>{if(i.lhsId===e){const e=w(i.lhsDir,i.rhsDir);e&&(t[e]=i.rhsId)}else{const e=w(i.rhsDir,i.lhsDir);e&&(t[e]=i.lhsId)}return t}),{}),t)),{}),e=Object.keys(t)[0],i={[e]:1},r=Object.keys(t).reduce(((t,i)=>i===e?t:{...t,[i]:1}),{}),n=(0,h.K2)((e=>{const n={[e]:[0,0]},o=[e];for(;o.length>0;){const e=o.shift();if(e){i[e]=1,delete r[e];const s=t[e],[a,h]=n[e];Object.entries(s).forEach((([t,e])=>{i[e]||(n[e]=L([a,h],t),o.push(e))}))}}return n}),"BFS"),o=[n(e)];for(;Object.keys(r).length>0;)o.push(n(Object.keys(r)[0]));D.records.dataStructures={adjList:t,spatialMaps:o}}return D.records.dataStructures}),"getDataStructures"),V=(0,h.K2)(((t,e)=>{D.records.elements[t]=e}),"setElementForId"),B=(0,h.K2)((t=>D.records.elements[t]),"getElementById"),W={clear:R,setDiagramTitle:h.ke,getDiagramTitle:h.ab,setAccTitle:h.SV,getAccTitle:h.iN,setAccDescription:h.EI,getAccDescription:h.m7,addService:b,getServices:G,addJunction:F,getJunctions:S,getNodes:P,getNode:U,addGroup:Y,getGroups:k,addEdge:H,getEdges:X,setElementForId:V,getElementById:B,getDataStructures:z};function j(t){const e=(0,h.D7)().architecture;return e?.[t]?e[t]:O[t]}(0,h.K2)(j,"getConfigField");var q=(0,h.K2)(((t,e)=>{(0,o.S)(t,e),t.groups.map(e.addGroup),t.services.map((t=>e.addService({...t,type:"service"}))),t.junctions.map((t=>e.addJunction({...t,type:"junction"}))),t.edges.map(e.addEdge)}),"populateDb"),$={parse:(0,h.K2)((async t=>{const e=await(0,l.qg)("architecture",t);h.Rm.debug(e),q(e,W)}),"parse")},K=(0,h.K2)((t=>`\n .edge {\n stroke-width: ${t.archEdgeWidth};\n stroke: ${t.archEdgeColor};\n fill: none;\n }\n\n .arrow {\n fill: ${t.archEdgeArrowColor};\n }\n\n .node-bkg {\n fill: none;\n stroke: ${t.archGroupBorderColor};\n stroke-width: ${t.archGroupBorderWidth};\n stroke-dasharray: 8;\n }\n .node-icon-text {\n display: flex; \n align-items: center;\n }\n \n .node-icon-text > div {\n color: #fff;\n margin: 1px;\n height: fit-content;\n text-align: center;\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n }\n`),"getStyles"),Z=(0,h.K2)((t=>`${t}`),"wrapIcon"),Q={prefix:"mermaid-architecture",height:80,width:80,icons:{database:{body:Z('')},server:{body:Z('')},disk:{body:Z('')},internet:{body:Z('')},cloud:{body:Z('')},unknown:r.Gc,blank:{body:Z("")}}},J=(0,h.K2)((async function(t,e){const i=j("padding"),r=j("iconSize"),o=r/2,s=r/6,a=s/2;await Promise.all(e.edges().map((async e=>{const{source:r,sourceDir:l,sourceArrow:c,sourceGroup:d,target:g,targetDir:u,targetArrow:v,targetGroup:y,label:A}=M(e);let{x:L,y:_}=e[0].sourceEndpoint();const{x:C,y:x}=e[0].midpoint();let{x:O,y:D}=e[0].targetEndpoint();const R=i+4;if(d&&(m(l)?L+="L"===l?-R:R:_+="T"===l?-R:R+18),y&&(m(u)?O+="L"===u?-R:R:D+="T"===u?-R:R+18),d||"junction"!==W.getNode(r)?.type||(m(l)?L+="L"===l?o:-o:_+="T"===l?o:-o),y||"junction"!==W.getNode(g)?.type||(m(u)?O+="L"===u?o:-o:D+="T"===u?o:-o),e[0]._private.rscratch){const e=t.insert("g");if(e.insert("path").attr("d",`M ${L},${_} L ${C},${x} L${O},${D} `).attr("class","edge"),c){const t=m(l)?f[l](L,s):L-a,i=E(l)?f[l](_,s):_-a;e.insert("polygon").attr("points",p[l](s)).attr("transform",`translate(${t},${i})`).attr("class","arrow")}if(v){const t=m(u)?f[u](O,s):O-a,i=E(u)?f[u](D,s):D-a;e.insert("polygon").attr("points",p[u](s)).attr("transform",`translate(${t},${i})`).attr("class","arrow")}if(A){const t=N(l,u)?"XY":m(l)?"X":"Y";let i=0;i="X"===t?Math.abs(L-O):"Y"===t?Math.abs(_-D)/1.5:Math.abs(L-O)/2;const r=e.append("g");if(await(0,n.GZ)(r,A,{useHtmlLabels:!1,width:i,classes:"architecture-service-label"},(0,h.D7)()),r.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle"),"X"===t)r.attr("transform","translate("+C+", "+x+")");else if("Y"===t)r.attr("transform","translate("+C+", "+x+") rotate(-90)");else if("XY"===t){const t=w(l,u);if(t&&T(t)){const e=r.node().getBoundingClientRect(),[i,n]=I(t);r.attr("dominant-baseline","auto").attr("transform",`rotate(${-1*i*n*45})`);const o=r.node().getBoundingClientRect();r.attr("transform",`\n translate(${C}, ${x-e.height/2})\n translate(${i*o.width/2}, ${n*o.height/2})\n rotate(${-1*i*n*45}, 0, ${e.height/2})\n `)}}}}})))}),"drawEdges"),tt=(0,h.K2)((async function(t,e){const i=.75*j("padding"),o=j("fontSize"),s=j("iconSize")/2;await Promise.all(e.nodes().map((async e=>{const a=x(e);if("group"===a.type){const{h:l,w:c,x1:d,y1:g}=e.boundingBox();t.append("rect").attr("x",d+s).attr("y",g+s).attr("width",c).attr("height",l).attr("class","node-bkg");const u=t.append("g");let p=d,f=g;if(a.icon){const t=u.append("g");t.html(`${await(0,r.WY)(a.icon,{height:i,width:i,fallbackPrefix:Q.prefix})}`),t.attr("transform","translate("+(p+s+1)+", "+(f+s+1)+")"),p+=i,f+=o/2-1-2}if(a.label){const t=u.append("g");await(0,n.GZ)(t,a.label,{useHtmlLabels:!1,width:c,classes:"architecture-service-label"},(0,h.D7)()),t.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","start").attr("text-anchor","start"),t.attr("transform","translate("+(p+s+4)+", "+(f+s+2)+")")}}})))}),"drawGroups"),et=(0,h.K2)((async function(t,e,i){for(const o of i){const i=e.append("g"),s=j("iconSize");if(o.title){const t=i.append("g");await(0,n.GZ)(t,o.title,{useHtmlLabels:!1,width:1.5*s,classes:"architecture-service-label"},(0,h.D7)()),t.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle"),t.attr("transform","translate("+s/2+", "+s+")")}const a=i.append("g");if(o.icon)a.html(`${await(0,r.WY)(o.icon,{height:s,width:s,fallbackPrefix:Q.prefix})}`);else if(o.iconText){a.html(`${await(0,r.WY)("blank",{height:s,width:s,fallbackPrefix:Q.prefix})}`);const t=a.append("g").append("foreignObject").attr("width",s).attr("height",s).append("div").attr("class","node-icon-text").attr("style",`height: ${s}px;`).append("div").html(o.iconText),e=parseInt(window.getComputedStyle(t.node(),null).getPropertyValue("font-size").replace(/\D/g,""))??16;t.attr("style",`-webkit-line-clamp: ${Math.floor((s-2)/e)};`)}else a.append("path").attr("class","node-bkg").attr("id","node-"+o.id).attr("d",`M0 ${s} v${-s} q0,-5 5,-5 h${s} q5,0 5,5 v${s} H0 Z`);i.attr("class","architecture-service");const{width:l,height:c}=i._groups[0][0].getBBox();o.width=l,o.height=c,t.setElementForId(o.id,i)}return 0}),"drawServices"),it=(0,h.K2)((function(t,e,i){i.forEach((i=>{const r=e.append("g"),n=j("iconSize");r.append("g").append("rect").attr("id","node-"+i.id).attr("fill-opacity","0").attr("width",n).attr("height",n),r.attr("class","architecture-junction");const{width:o,height:s}=r._groups[0][0].getBBox();r.width=o,r.height=s,t.setElementForId(i.id,r)}))}),"drawJunctions");function rt(t,e){t.forEach((t=>{e.add({group:"nodes",data:{type:"service",id:t.id,icon:t.icon,label:t.title,parent:t.in,width:j("iconSize"),height:j("iconSize")},classes:"node-service"})}))}function nt(t,e){t.forEach((t=>{e.add({group:"nodes",data:{type:"junction",id:t.id,parent:t.in,width:j("iconSize"),height:j("iconSize")},classes:"node-junction"})}))}function ot(t,e){e.nodes().map((e=>{const i=x(e);if("group"===i.type)return;i.x=e.position().x,i.y=e.position().y;t.getElementById(i.id).attr("transform","translate("+(i.x||0)+","+(i.y||0)+")")}))}function st(t,e){t.forEach((t=>{e.add({group:"nodes",data:{type:"group",id:t.id,icon:t.icon,label:t.title,parent:t.in},classes:"node-group"})}))}function at(t,e){t.forEach((t=>{const{lhsId:i,rhsId:r,lhsInto:n,lhsGroup:o,rhsInto:s,lhsDir:a,rhsDir:h,rhsGroup:l,title:c}=t,d=N(t.lhsDir,t.rhsDir)?"segments":"straight",g={id:`${i}-${r}`,label:c,source:i,sourceDir:a,sourceArrow:n,sourceGroup:o,sourceEndpoint:"L"===a?"0 50%":"R"===a?"100% 50%":"T"===a?"50% 0":"50% 100%",target:r,targetDir:h,targetArrow:s,targetGroup:l,targetEndpoint:"L"===h?"0 50%":"R"===h?"100% 50%":"T"===h?"50% 0":"50% 100%"};e.add({group:"edges",data:g,classes:d})}))}function ht(t){const e=t.map((t=>{const e={},i={};return Object.entries(t).forEach((([t,[r,n]])=>{e[n]||(e[n]=[]),i[r]||(i[r]=[]),e[n].push(t),i[r].push(t)})),{horiz:Object.values(e).filter((t=>t.length>1)),vert:Object.values(i).filter((t=>t.length>1))}})),[i,r]=e.reduce((([t,e],{horiz:i,vert:r})=>[[...t,...i],[...e,...r]]),[[],[]]);return{horizontal:i,vertical:r}}function lt(t){const e=[],i=(0,h.K2)((t=>`${t[0]},${t[1]}`),"posToStr"),r=(0,h.K2)((t=>t.split(",").map((t=>parseInt(t)))),"strToPos");return t.forEach((t=>{const n=Object.fromEntries(Object.entries(t).map((([t,e])=>[i(e),t]))),o=[i([0,0])],s={},a={L:[-1,0],R:[1,0],T:[0,1],B:[0,-1]};for(;o.length>0;){const t=o.shift();if(t){s[t]=1;const h=n[t];if(h){const l=r(t);Object.entries(a).forEach((([t,r])=>{const a=i([l[0]+r[0],l[1]+r[1]]),c=n[a];c&&!s[a]&&(o.push(a),e.push({[u[t]]:c,[u[v(t)]]:h,gap:1.5*j("iconSize")}))}))}}}})),e}function ct(t,e,i,r,{spatialMaps:n}){return new Promise((o=>{const s=(0,g.Ltv)("body").append("div").attr("id","cy").attr("style","display:none"),a=(0,c.A)({container:document.getElementById("cy"),style:[{selector:"edge",style:{"curve-style":"straight",label:"data(label)","source-endpoint":"data(sourceEndpoint)","target-endpoint":"data(targetEndpoint)"}},{selector:"edge.segments",style:{"curve-style":"segments","segment-weights":"0","segment-distances":[.5],"edge-distances":"endpoints","source-endpoint":"data(sourceEndpoint)","target-endpoint":"data(targetEndpoint)"}},{selector:"node",style:{"compound-sizing-wrt-labels":"include"}},{selector:"node[label]",style:{"text-valign":"bottom","text-halign":"center","font-size":`${j("fontSize")}px`}},{selector:".node-service",style:{label:"data(label)",width:"data(width)",height:"data(height)"}},{selector:".node-junction",style:{width:"data(width)",height:"data(height)"}},{selector:".node-group",style:{padding:`${j("padding")}px`}}]});s.remove(),st(i,a),rt(t,a),nt(e,a),at(r,a);const l=ht(n),d=lt(n),u=a.layout({name:"fcose",quality:"proof",styleEnabled:!1,animate:!1,nodeDimensionsIncludeLabels:!1,idealEdgeLength(t){const[e,i]=t.connectedNodes(),{parent:r}=x(e),{parent:n}=x(i);return r===n?1.5*j("iconSize"):.5*j("iconSize")},edgeElasticity(t){const[e,i]=t.connectedNodes(),{parent:r}=x(e),{parent:n}=x(i);return r===n?.45:.001},alignmentConstraint:l,relativePlacementConstraint:d});u.one("layoutstop",(()=>{function t(t,e,i,r){let n,o;const{x:s,y:a}=t,{x:h,y:l}=e;o=(r-a+(s-i)*(a-l)/(s-h))/Math.sqrt(1+Math.pow((a-l)/(s-h),2)),n=Math.sqrt(Math.pow(r-a,2)+Math.pow(i-s,2)-Math.pow(o,2));n/=Math.sqrt(Math.pow(h-s,2)+Math.pow(l-a,2));let c=(h-s)*(r-a)-(l-a)*(i-s);switch(!0){case c>=0:c=1;break;case c<0:c=-1}let d=(h-s)*(i-s)+(l-a)*(r-a);switch(!0){case d>=0:d=1;break;case d<0:d=-1}return o=Math.abs(o)*c,n*=d,{distances:o,weights:n}}(0,h.K2)(t,"getSegmentWeights"),a.startBatch();for(const e of Object.values(a.edges()))if(e.data?.()){const{x:i,y:r}=e.source().position(),{x:n,y:o}=e.target().position();if(i!==n&&r!==o){const i=e.sourceEndpoint(),r=e.targetEndpoint(),{sourceDir:n}=M(e),[o,s]=E(n)?[i.x,r.y]:[r.x,i.y],{weights:a,distances:h}=t(i,r,o,s);e.style("segment-distances",h),e.style("segment-weights",a)}}a.endBatch(),u.run()})),u.run(),a.ready((t=>{h.Rm.info("Ready",t),o(a)}))}))}(0,r.pC)([{name:Q.prefix,icons:Q}]),c.A.use(d),(0,h.K2)(rt,"addServices"),(0,h.K2)(nt,"addJunctions"),(0,h.K2)(ot,"positionNodes"),(0,h.K2)(st,"addGroups"),(0,h.K2)(at,"addEdges"),(0,h.K2)(ht,"getAlignments"),(0,h.K2)(lt,"getRelativeConstraints"),(0,h.K2)(ct,"layoutArchitecture");var dt={parser:$,db:W,renderer:{draw:(0,h.K2)((async(t,e,i,r)=>{const n=r.db,o=n.getServices(),s=n.getJunctions(),l=n.getGroups(),c=n.getEdges(),d=n.getDataStructures(),g=(0,a.D)(e),u=g.append("g");u.attr("class","architecture-edges");const p=g.append("g");p.attr("class","architecture-services");const f=g.append("g");f.attr("class","architecture-groups"),await et(n,p,o),it(n,p,s);const v=await ct(o,s,l,c,d);await J(u,v),await tt(f,v),ot(n,v),(0,h.ot)(void 0,g,j("padding"),j("useMaxWidth"))}),"draw")},styles:K}},98160:(t,e,i)=>{"use strict";i.d(e,{m:()=>n});var r=i(10009),n=class{constructor(t){this.init=t,this.records=this.init()}static{(0,r.K2)(this,"ImperativeState")}reset(){this.records=this.init()}}},63933:(t,e,i)=>{"use strict";function r(t,e){t.accDescr&&e.setAccDescription?.(t.accDescr),t.accTitle&&e.setAccTitle?.(t.accTitle),t.title&&e.setDiagramTitle?.(t.title)}i.d(e,{S:()=>r}),(0,i(10009).K2)(r,"populateCommonDb")}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/327db732.8b71bf7f.js b/pr-preview/pr-1071/assets/js/327db732.8b71bf7f.js deleted file mode 100644 index d9484e2ddc..0000000000 --- a/pr-preview/pr-1071/assets/js/327db732.8b71bf7f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1751],{59414:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>r,toc:()=>p});const r=JSON.parse('{"id":"getting-started/first-steps","title":"first-steps","description":"","source":"@site/versioned_docs/version-0.5/getting-started/first-steps.md","sourceDirName":"getting-started","slug":"/getting-started/first-steps","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/getting-started/first-steps.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup"},"next":{"title":"Examples","permalink":"/contrast/pr-preview/pr-1071/0.5/examples/"}}');var n=s(74848),o=s(28453);const i={},a=void 0,c={},p=[];function d(t){return(0,n.jsx)(n.Fragment,{})}function u(t={}){const{wrapper:e}={...(0,o.R)(),...t.components};return e?(0,n.jsx)(e,{...t,children:(0,n.jsx)(d,{...t})}):d()}},28453:(t,e,s)=>{s.d(e,{R:()=>i,x:()=>a});var r=s(96540);const n={},o=r.createContext(n);function i(t){const e=r.useContext(o);return r.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(n):t.components||n:i(t.components),r.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/327e592d.8189d855.js b/pr-preview/pr-1071/assets/js/327e592d.8189d855.js deleted file mode 100644 index 9f769dcbba..0000000000 --- a/pr-preview/pr-1071/assets/js/327e592d.8189d855.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[388],{17160:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-0.9/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/basics/security-benefits.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(17317).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(27109).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},27109:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},17317:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/35dd9928.5731d66f.js b/pr-preview/pr-1071/assets/js/35dd9928.5731d66f.js deleted file mode 100644 index ca86e02f45..0000000000 --- a/pr-preview/pr-1071/assets/js/35dd9928.5731d66f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[95],{90087:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/docs/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/next/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/features-limitations.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/next/architecture/observability"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/next/about/telemetry"}}');var r=t(74848),s=t(28453);const a={},o="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2},{value:"Automatic recovery and high availability",id:"automatic-recovery-and-high-availability",level:2},{value:"Overriding Kata configuration",id:"overriding-kata-configuration",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,r.jsx)(n.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,r.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,r.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Bare-metal support"}),": Support for running ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal",children:"Contrast on bare-metal Kubernetes"})," is available for AMD SEV-SNP and Intel TDX."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Persistent volumes"}),": Contrast only supports volumes with ",(0,r.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode",children:(0,r.jsx)(n.code,{children:"volumeMode: Block"})}),". These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Port forwarding"}),": This feature ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,r.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,r.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,r.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Volume integrity checks"}),": Integrity checks don't cover any volume mounts, such as ",(0,r.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,r.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container, affect the service mesh implementation of Contrast.\nCurrently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,r.jsx)(n.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"automatic-recovery-and-high-availability",children:"Automatic recovery and high availability"}),"\n",(0,r.jsx)(n.p,{children:"The Contrast Coordinator is a singleton and can't be scaled to more than one instance.\nWhen this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually.\nIn a future release, we plan to support distributed Coordinator instances that can recover automatically."}),"\n",(0,r.jsx)(n.h2,{id:"overriding-kata-configuration",children:"Overriding Kata configuration"}),"\n",(0,r.jsxs)(n.p,{children:["Kata Containers supports ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/blob/b4da4b5e3b9b21048af9333b071235a57a3e9493/docs/how-to/how-to-set-sandbox-config-kata.md",children:"overriding certain configuration values via Kubernetes annotations"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"It needs to be noted that setting these values is unsupported, and doing so may lead to unexpected\nbehaviour, as Contrast isn't tested against all possible configuration combinations."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var i=t(96540);const r={},s=i.createContext(r);function a(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3624.631ec2ee.js b/pr-preview/pr-1071/assets/js/3624.631ec2ee.js deleted file mode 100644 index 5ab8d6a88a..0000000000 --- a/pr-preview/pr-1071/assets/js/3624.631ec2ee.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3624],{62062:(t,n,r)=>{r.d(n,{A:()=>a});var e=r(29471);const o=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this};const c=function(t){return this.__data__.has(t)};function u(t){var n=-1,r=null==t?0:t.length;for(this.__data__=new e.A;++n{r.d(n,{A:()=>e});const e=function(t,n){for(var r=-1,e=null==t?0:t.length;++r{r.d(n,{A:()=>e});const e=function(t,n){for(var r=-1,e=null==t?0:t.length,o=0,c=[];++r{r.d(n,{A:()=>o});var e=r(60818);const o=function(t,n){return!!(null==t?0:t.length)&&(0,e.A)(t,n,0)>-1}},87809:(t,n,r)=>{r.d(n,{A:()=>e});const e=function(t,n,r){for(var e=-1,o=null==t?0:t.length;++e{r.d(n,{A:()=>e});const e=function(t,n){for(var r=-1,e=null==t?0:t.length,o=Array(e);++r{r.d(n,{A:()=>e});const e=function(t,n){for(var r=-1,e=n.length,o=t.length;++r{r.d(n,{A:()=>e});const e=function(t,n){for(var r=-1,e=null==t?0:t.length;++r{r.d(n,{A:()=>Q});var e=r(11754),o=r(72641),c=r(52851),u=r(22031),a=r(27422);const i=function(t,n){return t&&(0,u.A)(n,(0,a.A)(n),t)};var f=r(55615);const A=function(t,n){return t&&(0,u.A)(n,(0,f.A)(n),t)};var s=r(80154),v=r(39759),l=r(14792);const b=function(t,n){return(0,u.A)(t,(0,l.A)(t),n)};var d=r(83511);const j=function(t,n){return(0,u.A)(t,(0,d.A)(t),n)};var p=r(19042),h=r(83973),y=r(9779),g=Object.prototype.hasOwnProperty;const w=function(t){var n=t.length,r=new t.constructor(n);return n&&"string"==typeof t[0]&&g.call(t,"index")&&(r.index=t.index,r.input=t.input),r};var _=r(90565);const O=function(t,n){var r=n?(0,_.A)(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)};var m=/\w*$/;const S=function(t){var n=new t.constructor(t.source,m.exec(t));return n.lastIndex=t.lastIndex,n};var k=r(241),E=k.A?k.A.prototype:void 0,x=E?E.valueOf:void 0;const I=function(t){return x?Object(x.call(t)):{}};var U=r(1801);const B=function(t,n,r){var e=t.constructor;switch(n){case"[object ArrayBuffer]":return(0,_.A)(t);case"[object Boolean]":case"[object Date]":return new e(+t);case"[object DataView]":return O(t,r);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return(0,U.A)(t,r);case"[object Map]":case"[object Set]":return new e;case"[object Number]":case"[object String]":return new e(t);case"[object RegExp]":return S(t);case"[object Symbol]":return I(t)}};var C=r(18598),D=r(92049),F=r(99912),M=r(53098);const z=function(t){return(0,M.A)(t)&&"[object Map]"==(0,y.A)(t)};var L=r(52789),P=r(64841),$=P.A&&P.A.isMap;const N=$?(0,L.A)($):z;var R=r(23149);const V=function(t){return(0,M.A)(t)&&"[object Set]"==(0,y.A)(t)};var G=P.A&&P.A.isSet;const W=G?(0,L.A)(G):V;var q="[object Arguments]",H="[object Function]",J="[object Object]",K={};K[q]=K["[object Array]"]=K["[object ArrayBuffer]"]=K["[object DataView]"]=K["[object Boolean]"]=K["[object Date]"]=K["[object Float32Array]"]=K["[object Float64Array]"]=K["[object Int8Array]"]=K["[object Int16Array]"]=K["[object Int32Array]"]=K["[object Map]"]=K["[object Number]"]=K[J]=K["[object RegExp]"]=K["[object Set]"]=K["[object String]"]=K["[object Symbol]"]=K["[object Uint8Array]"]=K["[object Uint8ClampedArray]"]=K["[object Uint16Array]"]=K["[object Uint32Array]"]=!0,K["[object Error]"]=K[H]=K["[object WeakMap]"]=!1;const Q=function t(n,r,u,l,d,g){var _,O=1&r,m=2&r,S=4&r;if(u&&(_=d?u(n,l,d,g):u(n)),void 0!==_)return _;if(!(0,R.A)(n))return n;var k=(0,D.A)(n);if(k){if(_=w(n),!O)return(0,v.A)(n,_)}else{var E=(0,y.A)(n),x=E==H||"[object GeneratorFunction]"==E;if((0,F.A)(n))return(0,s.A)(n,O);if(E==J||E==q||x&&!d){if(_=m||x?{}:(0,C.A)(n),!O)return m?j(n,A(_,n)):b(n,i(_,n))}else{if(!K[E])return d?n:{};_=B(n,E,O)}}g||(g=new e.A);var I=g.get(n);if(I)return I;g.set(n,_),W(n)?n.forEach((function(e){_.add(t(e,r,u,e,n,g))})):N(n)&&n.forEach((function(e,o){_.set(o,t(e,r,u,o,n,g))}));var U=S?m?h.A:p.A:m?f.A:a.A,M=k?void 0:U(n);return(0,o.A)(M||n,(function(e,o){M&&(e=n[o=e]),(0,c.A)(_,o,t(e,r,u,o,n,g))})),_}},6240:(t,n,r)=>{r.d(n,{A:()=>c});var e=r(79841),o=r(38446);const c=function(t,n){return function(r,e){if(null==r)return r;if(!(0,o.A)(r))return t(r,e);for(var c=r.length,u=n?c:-1,a=Object(r);(n?u--:++u{r.d(n,{A:()=>o});var e=r(6240);const o=function(t,n){var r=[];return(0,e.A)(t,(function(t,e,o){n(t,e,o)&&r.push(t)})),r}},25707:(t,n,r)=>{r.d(n,{A:()=>e});const e=function(t,n,r,e){for(var o=t.length,c=r+(e?1:-1);e?c--:++c{r.d(n,{A:()=>f});var e=r(76912),o=r(241),c=r(52274),u=r(92049),a=o.A?o.A.isConcatSpreadable:void 0;const i=function(t){return(0,u.A)(t)||(0,c.A)(t)||!!(a&&t&&t[a])};const f=function t(n,r,o,c,u){var a=-1,f=n.length;for(o||(o=i),u||(u=[]);++a0&&o(A)?r>1?t(A,r-1,o,c,u):(0,e.A)(u,A):c||(u[u.length]=A)}return u}},79841:(t,n,r)=>{r.d(n,{A:()=>c});var e=r(4574),o=r(27422);const c=function(t,n){return t&&(0,e.A)(t,n,o.A)}},66318:(t,n,r)=>{r.d(n,{A:()=>c});var e=r(7819),o=r(30901);const c=function(t,n){for(var r=0,c=(n=(0,e.A)(n,t)).length;null!=t&&r{r.d(n,{A:()=>c});var e=r(76912),o=r(92049);const c=function(t,n,r){var c=n(t);return(0,o.A)(t)?c:(0,e.A)(c,r(t))}},60818:(t,n,r)=>{r.d(n,{A:()=>u});var e=r(25707);const o=function(t){return t!=t};const c=function(t,n,r){for(var e=r-1,o=t.length;++e{r.d(n,{A:()=>J});var e=r(11754),o=r(62062),c=r(63736),u=r(64099);const a=function(t,n,r,e,a,i){var f=1&r,A=t.length,s=n.length;if(A!=s&&!(f&&s>A))return!1;var v=i.get(t),l=i.get(n);if(v&&l)return v==n&&l==t;var b=-1,d=!0,j=2&r?new o.A:void 0;for(i.set(t,n),i.set(n,t);++b{r.d(n,{A:()=>e});const e=function(t){return function(n){return null==n?void 0:n[t]}}},99902:(t,n,r)=>{r.d(n,{A:()=>s});var e=r(62062),o=r(83149),c=r(87809),u=r(64099),a=r(39857),i=r(42302),f=r(29959);const A=a.A&&1/(0,f.A)(new a.A([,-0]))[1]==1/0?function(t){return new a.A(t)}:i.A;const s=function(t,n,r){var a=-1,i=o.A,s=t.length,v=!0,l=[],b=l;if(r)v=!1,i=c.A;else if(s>=200){var d=n?null:A(t);if(d)return(0,f.A)(d);v=!1,i=u.A,b=new e.A}else b=n?[]:l;t:for(;++a{r.d(n,{A:()=>e});const e=function(t,n){return t.has(n)}},99922:(t,n,r)=>{r.d(n,{A:()=>o});var e=r(29008);const o=function(t){return"function"==typeof t?t:e.A}},7819:(t,n,r)=>{r.d(n,{A:()=>A});var e=r(92049),o=r(86586),c=r(46632);var u=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,a=/\\(\\)?/g;const i=function(t){var n=(0,c.A)(t,(function(t){return 500===r.size&&r.clear(),t})),r=n.cache;return n}((function(t){var n=[];return 46===t.charCodeAt(0)&&n.push(""),t.replace(u,(function(t,r,e,o){n.push(e?o.replace(a,"$1"):r||t)})),n}));var f=r(28894);const A=function(t,n){return(0,e.A)(t)?t:(0,o.A)(t,n)?[t]:i((0,f.A)(t))}},19042:(t,n,r)=>{r.d(n,{A:()=>u});var e=r(33831),o=r(14792),c=r(27422);const u=function(t){return(0,e.A)(t,c.A,o.A)}},83973:(t,n,r)=>{r.d(n,{A:()=>u});var e=r(33831),o=r(83511),c=r(55615);const u=function(t){return(0,e.A)(t,c.A,o.A)}},14792:(t,n,r)=>{r.d(n,{A:()=>a});var e=r(2634),o=r(13153),c=Object.prototype.propertyIsEnumerable,u=Object.getOwnPropertySymbols;const a=u?function(t){return null==t?[]:(t=Object(t),(0,e.A)(u(t),(function(n){return c.call(t,n)})))}:o.A},83511:(t,n,r)=>{r.d(n,{A:()=>a});var e=r(76912),o=r(15647),c=r(14792),u=r(13153);const a=Object.getOwnPropertySymbols?function(t){for(var n=[];t;)(0,e.A)(n,(0,c.A)(t)),t=(0,o.A)(t);return n}:u.A},85054:(t,n,r)=>{r.d(n,{A:()=>f});var e=r(7819),o=r(52274),c=r(92049),u=r(25353),a=r(5254),i=r(30901);const f=function(t,n,r){for(var f=-1,A=(n=(0,e.A)(n,t)).length,s=!1;++f{r.d(n,{A:()=>a});var e=r(92049),o=r(61882),c=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,u=/^\w*$/;const a=function(t,n){if((0,e.A)(t))return!1;var r=typeof t;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=t&&!(0,o.A)(t))||(u.test(t)||!c.test(t)||null!=n&&t in Object(n))}},29959:(t,n,r)=>{r.d(n,{A:()=>e});const e=function(t){var n=-1,r=Array(t.size);return t.forEach((function(t){r[++n]=t})),r}},30901:(t,n,r)=>{r.d(n,{A:()=>o});var e=r(61882);const o=function(t){if("string"==typeof t||(0,e.A)(t))return t;var n=t+"";return"0"==n&&1/t==-1/0?"-0":n}},94092:(t,n,r)=>{r.d(n,{A:()=>a});var e=r(2634),o=r(51790),c=r(23958),u=r(92049);const a=function(t,n){return((0,u.A)(t)?e.A:o.A)(t,(0,c.A)(n,3))}},8058:(t,n,r)=>{r.d(n,{A:()=>a});var e=r(72641),o=r(6240),c=r(99922),u=r(92049);const a=function(t,n){return((0,u.A)(t)?e.A:o.A)(t,(0,c.A)(n))}},39188:(t,n,r)=>{r.d(n,{A:()=>c});const e=function(t,n){return null!=t&&n in Object(t)};var o=r(85054);const c=function(t,n){return null!=t&&(0,o.A)(t,n,e)}},61882:(t,n,r)=>{r.d(n,{A:()=>c});var e=r(88496),o=r(53098);const c=function(t){return"symbol"==typeof t||(0,o.A)(t)&&"[object Symbol]"==(0,e.A)(t)}},69592:(t,n,r)=>{r.d(n,{A:()=>e});const e=function(t){return void 0===t}},27422:(t,n,r)=>{r.d(n,{A:()=>u});var e=r(83607),o=r(69471),c=r(38446);const u=function(t){return(0,c.A)(t)?(0,e.A)(t):(0,o.A)(t)}},42302:(t,n,r)=>{r.d(n,{A:()=>e});const e=function(){}},89463:(t,n,r)=>{r.d(n,{A:()=>i});const e=function(t,n,r,e){var o=-1,c=null==t?0:t.length;for(e&&c&&(r=t[++o]);++o{r.d(n,{A:()=>e});const e=function(){return[]}},28894:(t,n,r)=>{r.d(n,{A:()=>A});var e=r(241),o=r(45572),c=r(92049),u=r(61882),a=e.A?e.A.prototype:void 0,i=a?a.toString:void 0;const f=function t(n){if("string"==typeof n)return n;if((0,c.A)(n))return(0,o.A)(n,t)+"";if((0,u.A)(n))return i?i.call(n):"";var r=n+"";return"0"==r&&1/n==-1/0?"-0":r};const A=function(t){return null==t?"":f(t)}},38207:(t,n,r)=>{r.d(n,{A:()=>u});var e=r(45572);const o=function(t,n){return(0,e.A)(n,(function(n){return t[n]}))};var c=r(27422);const u=function(t){return null==t?[]:o(t,(0,c.A)(t))}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3683601e.4d7dd5e0.js b/pr-preview/pr-1071/assets/js/3683601e.4d7dd5e0.js deleted file mode 100644 index 56f0325e36..0000000000 --- a/pr-preview/pr-1071/assets/js/3683601e.4d7dd5e0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2987],{85863:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});const r=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-0.9/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/0.9/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/deployment.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto"},"next":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/0.9/troubleshooting"}}');var o=t(74848),s=t(28453);const i={},a="Workload deployment",c={},l=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2},{value:"Recover the Coordinator",id:"recover-the-coordinator",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components},{TabItem:t,Tabs:r}=n;return t||p("TabItem",!0),r||p("Tabs",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.header,{children:(0,o.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,o.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,o.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup",children:"setup guide"})," on how to set it up."]}),"\n",(0,o.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,o.jsxs)(n.p,{children:["Contrast depends on a ",(0,o.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:["custom Kubernetes ",(0,o.jsx)(n.code,{children:"RuntimeClass"})," (",(0,o.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,o.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,o.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/runtime.yml\n"})}),"\n",(0,o.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/coordinator.yml\n"})}),"\n",(0,o.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,o.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,o.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,o.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,o.jsxs)(r,{groupId:"yaml-source",children:[(0,o.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,o.jsx)(t,{value:"helm",label:"helm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,o.jsx)(t,{value:"copy",label:"copy",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,o.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,o.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,o.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,o.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,o.jsxs)(n.p,{children:["In the initialization process, the ",(0,o.jsx)(n.code,{children:"contrast-tls-certs"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,o.jsxs)(r,{groupId:"tls",children:[(0,o.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,o.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,o.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,o.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,o.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,o.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,o.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,o.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,o.jsxs)(n.p,{children:["During the ",(0,o.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,o.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,o.jsxs)(t,{value:"go",label:"Go integration",children:[(0,o.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,o.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,o.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,o.jsxs)(r,{groupId:"golang-tls-setup",children:[(0,o.jsx)(t,{value:"client",label:"Client",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,o.jsx)(t,{value:"server",label:"Server",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,o.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,o.jsxs)(n.p,{children:["Run the ",(0,o.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,o.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,o.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp resources/\n"})}),"\n",(0,o.jsx)(n.admonition,{type:"warning",children:(0,o.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,o.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,o.jsxs)(r,{groupId:"injection",children:[(0,o.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,o.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,o.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,o.jsx)(n.code,{children:"generate"})," command."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp --skip-initializer resources/\n"})})]}),(0,o.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,o.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,o.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,o.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,o.jsx)(n.code,{children:"contrast-tls-certs"})," ",(0,o.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:v0.9.0@sha256:ca1ee62f9abb47224a70cb4b1a4593b3fa83481e083047ec707ded911baf134b"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /tls-config\n name: contrast-tls-certs\n volumes:\n - emptyDir: {}\n name: contrast-tls-certs\n'})}),"\n",(0,o.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,o.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,o.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,o.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,o.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,o.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,o.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,o.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,o.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,o.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,o.jsx)(n.p,{children:"This will use the reference values from the manifest file to attest the Coordinator.\nAfter this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,o.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,o.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,o.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,o.jsxs)(n.p,{children:["The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the\nservice mesh root certificate and the history of manifests into the ",(0,o.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies\nreferenced in the active manifest are also written to the directory. The verification will fail if the active\nmanifest at the Coordinator doesn't match the manifest passed to the CLI."]}),"\n",(0,o.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,o.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,o.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,o.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,o.jsxs)(n.p,{children:["Using ",(0,o.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,o.jsx)(n.h2,{id:"recover-the-coordinator",children:"Recover the Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material.\nFor demonstration purposes, you can simulate this scenario by deleting the Coordinator pod."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl delete pod -l app.kubernetes.io/name=coordinator\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet.\nYou can confirm this by running ",(0,o.jsx)(n.code,{children:"verify"})," again, or you can restart a workload pod, which should stay in the initialization phase.\nHowever, the secret seed in your working directory is sufficient to recover the coordinator."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast recover -c "${coordinator}:1313"\n'})}),"\n",(0,o.jsx)(n.p,{children:"Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state.\nYou can now verify the Coordinator again, which should return the same manifest you set before."}),"\n",(0,o.jsx)(n.admonition,{type:"warning",children:(0,o.jsx)(n.p,{children:"The recovery process invalidates the mesh CA certificate:\nexisting workloads won't be able to communicate with workloads newly spawned.\nAll workloads should be restarted after the recovery succeeded."})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}function p(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>a});var r=t(96540);const o={},s=r.createContext(o);function i(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/368b3075.b498094d.js b/pr-preview/pr-1071/assets/js/368b3075.b498094d.js deleted file mode 100644 index f6926d6435..0000000000 --- a/pr-preview/pr-1071/assets/js/368b3075.b498094d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5919],{97447:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"1.2","label":"1.2","banner":null,"badge":true,"noIndex":false,"className":"docs-version-1.2","isLast":true,"docsSidebars":{"docs":[{"type":"link","label":"What is Contrast?","href":"/contrast/pr-preview/pr-1071/","docId":"intro","unlisted":false},{"type":"category","label":"Basics","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false},{"type":"link","label":"Bare metal setup","href":"/contrast/pr-preview/pr-1071/getting-started/bare-metal","docId":"getting-started/bare-metal","unlisted":false}],"collapsible":true},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/examples/emojivoto","docId":"examples/emojivoto","unlisted":false},{"type":"link","label":"Encrypted volume mount","href":"/contrast/pr-preview/pr-1071/examples/mysql","docId":"examples/mysql","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/deployment","docId":"deployment","unlisted":false},{"type":"link","label":"Troubleshooting","href":"/contrast/pr-preview/pr-1071/troubleshooting","docId":"troubleshooting","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Overview","href":"/contrast/pr-preview/pr-1071/components/overview","docId":"components/overview","unlisted":false},{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Secrets & recovery","href":"/contrast/pr-preview/pr-1071/architecture/secrets","docId":"architecture/secrets","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Security considerations","href":"/contrast/pr-preview/pr-1071/architecture/security-considerations","docId":"architecture/security-considerations","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"architecture/secrets":{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","sidebar":"docs"},"architecture/security-considerations":{"id":"architecture/security-considerations","title":"Security Considerations","description":"Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits).","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/overview":{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"examples/mysql":{"id":"examples/mysql","title":"Encrypted volume mount","description":"This tutorial guides you through deploying a simple application with an","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/bare-metal":{"id":"getting-started/bare-metal","title":"Prepare a bare-metal instance","description":"Hardware and firmware setup","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"troubleshooting":{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3764.c12c89cb.js b/pr-preview/pr-1071/assets/js/3764.c12c89cb.js deleted file mode 100644 index 8a7ef512c9..0000000000 --- a/pr-preview/pr-1071/assets/js/3764.c12c89cb.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 3764.c12c89cb.js.LICENSE.txt */ -(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3764],{69119:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BLANK_URL=e.relativeFirstCharacters=e.whitespaceEscapeCharsRegex=e.urlSchemeRegex=e.ctrlCharactersRegex=e.htmlCtrlEntityRegex=e.htmlEntitiesRegex=e.invalidProtocolRegex=void 0,e.invalidProtocolRegex=/^([^\w]*)(javascript|data|vbscript)/im,e.htmlEntitiesRegex=/&#(\w+)(^\w|;)?/g,e.htmlCtrlEntityRegex=/&(newline|tab);/gi,e.ctrlCharactersRegex=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,e.urlSchemeRegex=/^.+(:|:)/gim,e.whitespaceEscapeCharsRegex=/(\\|%5[cC])((%(6[eE]|72|74))|[nrt])/g,e.relativeFirstCharacters=[".","/"],e.BLANK_URL="about:blank"},16750:(t,e,r)=>{"use strict";e.J=void 0;var n=r(69119);function i(t){try{return decodeURIComponent(t)}catch(e){return t}}e.J=function(t){if(!t)return n.BLANK_URL;var e,r,a=i(t.trim());do{e=(a=i(a=(r=a,r.replace(n.ctrlCharactersRegex,"").replace(n.htmlEntitiesRegex,(function(t,e){return String.fromCharCode(e)}))).replace(n.htmlCtrlEntityRegex,"").replace(n.ctrlCharactersRegex,"").replace(n.whitespaceEscapeCharsRegex,"").trim())).match(n.ctrlCharactersRegex)||a.match(n.htmlEntitiesRegex)||a.match(n.htmlCtrlEntityRegex)||a.match(n.whitespaceEscapeCharsRegex)}while(e&&e.length>0);var o=a;if(!o)return n.BLANK_URL;if(function(t){return n.relativeFirstCharacters.indexOf(t[0])>-1}(o))return o;var s=o.trimStart(),l=s.match(n.urlSchemeRegex);if(!l)return o;var c=l[0].toLowerCase().trim();if(n.invalidProtocolRegex.test(c))return n.BLANK_URL;var h=s.replace(/\\/g,"/");if("mailto:"===c||c.includes("://"))return h;if("http:"===c||"https:"===c){if(!function(t){return URL.canParse(t)}(h))return n.BLANK_URL;var u=new URL(h);return u.protocol=u.protocol.toLowerCase(),u.hostname=u.hostname.toLowerCase(),u.toString()}return h}},54182:(t,e,r)=>{"use strict";r.d(e,{A:()=>$});var n=r(96540),i=r(74848);function a(t){const{mdxAdmonitionTitle:e,rest:r}=function(t){const e=n.Children.toArray(t),r=e.find((t=>n.isValidElement(t)&&"mdxAdmonitionTitle"===t.type)),a=e.filter((t=>t!==r)),o=r?.props.children;return{mdxAdmonitionTitle:o,rest:a.length>0?(0,i.jsx)(i.Fragment,{children:a}):null}}(t.children),a=t.title??e;return{...t,...a&&{title:a},children:r}}var o=r(34164),s=r(23230),l=r(18630);const c="admonition_xJq3",h="admonitionHeading_Gvgb",u="admonitionIcon_Rf37",d="admonitionContent_BuS1";function p(t){let{type:e,className:r,children:n}=t;return(0,i.jsx)("div",{className:(0,o.A)(l.G.common.admonition,l.G.common.admonitionType(e),c,r),children:n})}function f(t){let{icon:e,title:r}=t;return(0,i.jsxs)("div",{className:h,children:[(0,i.jsx)("span",{className:u,children:e}),r]})}function g(t){let{children:e}=t;return e?(0,i.jsx)("div",{className:d,children:e}):null}function m(t){const{type:e,icon:r,title:n,children:a,className:o}=t;return(0,i.jsxs)(p,{type:e,className:o,children:[n||r?(0,i.jsx)(f,{title:n,icon:r}):null,(0,i.jsx)(g,{children:a})]})}function y(t){return(0,i.jsx)("svg",{viewBox:"0 0 14 16",...t,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const x={icon:(0,i.jsx)(y,{}),title:(0,i.jsx)(s.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function b(t){return(0,i.jsx)(m,{...x,...t,className:(0,o.A)("alert alert--secondary",t.className),children:t.children})}function k(t){return(0,i.jsx)("svg",{viewBox:"0 0 12 16",...t,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const C={icon:(0,i.jsx)(k,{}),title:(0,i.jsx)(s.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function w(t){return(0,i.jsx)(m,{...C,...t,className:(0,o.A)("alert alert--success",t.className),children:t.children})}function _(t){return(0,i.jsx)("svg",{viewBox:"0 0 14 16",...t,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const v={icon:(0,i.jsx)(_,{}),title:(0,i.jsx)(s.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function S(t){return(0,i.jsx)(m,{...v,...t,className:(0,o.A)("alert alert--info",t.className),children:t.children})}function A(t){return(0,i.jsx)("svg",{viewBox:"0 0 16 16",...t,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const T={icon:(0,i.jsx)(A,{}),title:(0,i.jsx)(s.A,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function M(t){return(0,i.jsx)("svg",{viewBox:"0 0 12 16",...t,children:(0,i.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const B={icon:(0,i.jsx)(M,{}),title:(0,i.jsx)(s.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const L={icon:(0,i.jsx)(A,{}),title:(0,i.jsx)(s.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const F={...{note:b,tip:w,info:S,warning:function(t){return(0,i.jsx)(m,{...T,...t,className:(0,o.A)("alert alert--warning",t.className),children:t.children})},danger:function(t){return(0,i.jsx)(m,{...B,...t,className:(0,o.A)("alert alert--danger",t.className),children:t.children})}},...{secondary:t=>(0,i.jsx)(b,{title:"secondary",...t}),important:t=>(0,i.jsx)(S,{title:"important",...t}),success:t=>(0,i.jsx)(w,{title:"success",...t}),caution:function(t){return(0,i.jsx)(m,{...L,...t,className:(0,o.A)("alert alert--warning",t.className),children:t.children})}}};function $(t){const e=a(t),r=(n=e.type,F[n]||(console.warn(`No admonition component found for admonition type "${n}". Using Info as fallback.`),F.info));var n;return(0,i.jsx)(r,{...e})}},44168:(t,e,r)=>{"use strict";r.d(e,{A:()=>y});r(96540);var n=r(34164),i=r(18630),a=r(45357),o=r(80260),s=r(14783),l=r(23230),c=r(98180),h=r(74848);function u(t){return(0,h.jsx)("svg",{viewBox:"0 0 24 24",...t,children:(0,h.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const d={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function p(){const t=(0,c.Ay)("/");return(0,h.jsx)("li",{className:"breadcrumbs__item",children:(0,h.jsx)(s.A,{"aria-label":(0,l.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:t,children:(0,h.jsx)(u,{className:d.breadcrumbHomeIcon})})})}const f={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function g(t){let{children:e,href:r,isLast:n}=t;const i="breadcrumbs__link";return n?(0,h.jsx)("span",{className:i,itemProp:"name",children:e}):r?(0,h.jsx)(s.A,{className:i,href:r,itemProp:"item",children:(0,h.jsx)("span",{itemProp:"name",children:e})}):(0,h.jsx)("span",{className:i,children:e})}function m(t){let{children:e,active:r,index:i,addMicrodata:a}=t;return(0,h.jsxs)("li",{...a&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},className:(0,n.A)("breadcrumbs__item",{"breadcrumbs__item--active":r}),children:[e,(0,h.jsx)("meta",{itemProp:"position",content:String(i+1)})]})}function y(){const t=(0,a.OF)(),e=(0,o.Dt)();return t?(0,h.jsx)("nav",{className:(0,n.A)(i.G.docs.docBreadcrumbs,f.breadcrumbsContainer),"aria-label":(0,l.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,h.jsxs)("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList",children:[e&&(0,h.jsx)(p,{}),t.map(((e,r)=>{const n=r===t.length-1,i="category"===e.type&&e.linkUnlisted?void 0:e.href;return(0,h.jsx)(m,{active:n,index:r,addMicrodata:!!i,children:(0,h.jsx)(g,{href:i,isLast:n,children:e.label})},r)}))]})}):null}},86829:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>wt});var n=r(96540),i=r(69817),a=r(4799),o=r(74848);const s=n.createContext(null);function l(t){let{children:e,content:r}=t;const i=function(t){return(0,n.useMemo)((()=>({metadata:t.metadata,frontMatter:t.frontMatter,assets:t.assets,contentTitle:t.contentTitle,toc:t.toc})),[t])}(r);return(0,o.jsx)(s.Provider,{value:i,children:e})}function c(){const t=(0,n.useContext)(s);if(null===t)throw new a.dV("DocProvider");return t}function h(){const{metadata:t,frontMatter:e,assets:r}=c();return(0,o.jsx)(i.be,{title:t.title,description:t.description,keywords:e.keywords,image:r.image??e.image})}var u=r(34164),d=r(82216),p=r(62400);function f(){const{metadata:t}=c();return(0,o.jsx)(p.A,{previous:t.previous,next:t.next})}var g=r(84799),m=r(79436),y=r(18630),x=r(23230),b=r(14783);const k={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function C(t){let{permalink:e,label:r,count:n,description:i}=t;return(0,o.jsxs)(b.A,{href:e,title:i,className:(0,u.A)(k.tag,n?k.tagWithCount:k.tagRegular),children:[r,n&&(0,o.jsx)("span",{children:n})]})}const w={tags:"tags_jXut",tag:"tag_QGVx"};function _(t){let{tags:e}=t;return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("b",{children:(0,o.jsx)(x.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list",children:"Tags:"})}),(0,o.jsx)("ul",{className:(0,u.A)(w.tags,"padding--none","margin-left--sm"),children:e.map((t=>(0,o.jsx)("li",{className:w.tag,children:(0,o.jsx)(C,{...t})},t.permalink)))})]})}const v={iconEdit:"iconEdit_Z9Sw"};function S(t){let{className:e,...r}=t;return(0,o.jsx)("svg",{fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.A)(v.iconEdit,e),"aria-hidden":"true",...r,children:(0,o.jsx)("g",{children:(0,o.jsx)("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})})})}function A(t){let{editUrl:e}=t;return(0,o.jsxs)(b.A,{to:e,className:y.G.common.editThisPage,children:[(0,o.jsx)(S,{}),(0,o.jsx)(x.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page",children:"Edit this page"})]})}var T=r(97639);function M(t){void 0===t&&(t={});const{i18n:{currentLocale:e}}=(0,T.A)(),r=function(){const{i18n:{currentLocale:t,localeConfigs:e}}=(0,T.A)();return e[t].calendar}();return new Intl.DateTimeFormat(e,{calendar:r,...t})}function B(t){let{lastUpdatedAt:e}=t;const r=new Date(e),n=M({day:"numeric",month:"short",year:"numeric",timeZone:"UTC"}).format(r);return(0,o.jsx)(x.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:(0,o.jsx)("b",{children:(0,o.jsx)("time",{dateTime:r.toISOString(),itemProp:"dateModified",children:n})})},children:" on {date}"})}function L(t){let{lastUpdatedBy:e}=t;return(0,o.jsx)(x.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:(0,o.jsx)("b",{children:e})},children:" by {user}"})}function F(t){let{lastUpdatedAt:e,lastUpdatedBy:r}=t;return(0,o.jsxs)("span",{className:y.G.common.lastUpdated,children:[(0,o.jsx)(x.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:e?(0,o.jsx)(B,{lastUpdatedAt:e}):"",byUser:r?(0,o.jsx)(L,{lastUpdatedBy:r}):""},children:"Last updated{atDate}{byUser}"}),!1]})}const $={lastUpdated:"lastUpdated_JAkA"};function E(t){let{className:e,editUrl:r,lastUpdatedAt:n,lastUpdatedBy:i}=t;return(0,o.jsxs)("div",{className:(0,u.A)("row",e),children:[(0,o.jsx)("div",{className:"col",children:r&&(0,o.jsx)(A,{editUrl:r})}),(0,o.jsx)("div",{className:(0,u.A)("col",$.lastUpdated),children:(n||i)&&(0,o.jsx)(F,{lastUpdatedAt:n,lastUpdatedBy:i})})]})}function N(){const{metadata:t}=c(),{editUrl:e,lastUpdatedAt:r,lastUpdatedBy:n,tags:i}=t,a=i.length>0,s=!!(e||r||n);return a||s?(0,o.jsxs)("footer",{className:(0,u.A)(y.G.docs.docFooter,"docusaurus-mt-lg"),children:[a&&(0,o.jsx)("div",{className:(0,u.A)("row margin-top--sm",y.G.docs.docFooterTagsRow),children:(0,o.jsx)("div",{className:"col",children:(0,o.jsx)(_,{tags:i})})}),s&&(0,o.jsx)(E,{className:(0,u.A)("margin-top--sm",y.G.docs.docFooterEditMetaRow),editUrl:e,lastUpdatedAt:r,lastUpdatedBy:n})]}):null}var D=r(94549),j=r(86957);function I(t){const e=t.map((t=>({...t,parentIndex:-1,children:[]}))),r=Array(7).fill(-1);e.forEach(((t,e)=>{const n=r.slice(2,t.level);t.parentIndex=Math.max(...n),r[t.level]=e}));const n=[];return e.forEach((t=>{const{parentIndex:r,...i}=t;r>=0?e[r].children.push(i):n.push(i)})),n}function O(t){let{toc:e,minHeadingLevel:r,maxHeadingLevel:n}=t;return e.flatMap((t=>{const e=O({toc:t.children,minHeadingLevel:r,maxHeadingLevel:n});return function(t){return t.level>=r&&t.level<=n}(t)?[{...t,children:e}]:e}))}function R(t){const e=t.getBoundingClientRect();return e.top===e.bottom?R(t.parentNode):e}function P(t,e){let{anchorTopOffset:r}=e;const n=t.find((t=>R(t).top>=r));if(n){return function(t){return t.top>0&&t.bottom{t.current=e?0:document.querySelector(".navbar").clientHeight}),[e]),t}function K(t){const e=(0,n.useRef)(void 0),r=z();(0,n.useEffect)((()=>{if(!t)return()=>{};const{linkClassName:n,linkActiveClassName:i,minHeadingLevel:a,maxHeadingLevel:o}=t;function s(){const t=function(t){return Array.from(document.getElementsByClassName(t))}(n),s=function(t){let{minHeadingLevel:e,maxHeadingLevel:r}=t;const n=[];for(let i=e;i<=r;i+=1)n.push(`h${i}.anchor`);return Array.from(document.querySelectorAll(n.join()))}({minHeadingLevel:a,maxHeadingLevel:o}),l=P(s,{anchorTopOffset:r.current}),c=t.find((t=>l&&l.id===function(t){return decodeURIComponent(t.href.substring(t.href.indexOf("#")+1))}(t)));t.forEach((t=>{!function(t,r){r?(e.current&&e.current!==t&&e.current.classList.remove(i),t.classList.add(i),e.current=t):t.classList.remove(i)}(t,t===c)}))}return document.addEventListener("scroll",s),document.addEventListener("resize",s),s(),()=>{document.removeEventListener("scroll",s),document.removeEventListener("resize",s)}}),[t,r])}function q(t){let{toc:e,className:r,linkClassName:n,isChild:i}=t;return e.length?(0,o.jsx)("ul",{className:i?void 0:r,children:e.map((t=>(0,o.jsxs)("li",{children:[(0,o.jsx)(b.A,{to:`#${t.id}`,className:n??void 0,dangerouslySetInnerHTML:{__html:t.value}}),(0,o.jsx)(q,{isChild:!0,toc:t.children,className:r,linkClassName:n})]},t.id)))}):null}const W=n.memo(q);function H(t){let{toc:e,className:r="table-of-contents table-of-contents__left-border",linkClassName:i="table-of-contents__link",linkActiveClassName:a,minHeadingLevel:s,maxHeadingLevel:l,...c}=t;const h=(0,j.p)(),u=s??h.tableOfContents.minHeadingLevel,d=l??h.tableOfContents.maxHeadingLevel,p=function(t){let{toc:e,minHeadingLevel:r,maxHeadingLevel:i}=t;return(0,n.useMemo)((()=>O({toc:I(e),minHeadingLevel:r,maxHeadingLevel:i})),[e,r,i])}({toc:e,minHeadingLevel:u,maxHeadingLevel:d});return K((0,n.useMemo)((()=>{if(i&&a)return{linkClassName:i,linkActiveClassName:a,minHeadingLevel:u,maxHeadingLevel:d}}),[i,a,u,d])),(0,o.jsx)(W,{toc:p,className:r,linkClassName:i,...c})}const U={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function Y(t){let{collapsed:e,...r}=t;return(0,o.jsx)("button",{type:"button",...r,className:(0,u.A)("clean-btn",U.tocCollapsibleButton,!e&&U.tocCollapsibleButtonExpanded,r.className),children:(0,o.jsx)(x.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component",children:"On this page"})})}const V={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function G(t){let{toc:e,className:r,minHeadingLevel:n,maxHeadingLevel:i}=t;const{collapsed:a,toggleCollapsed:s}=(0,D.u)({initialState:!0});return(0,o.jsxs)("div",{className:(0,u.A)(V.tocCollapsible,!a&&V.tocCollapsibleExpanded,r),children:[(0,o.jsx)(Y,{collapsed:a,onClick:s}),(0,o.jsx)(D.N,{lazy:!0,className:V.tocCollapsibleContent,collapsed:a,children:(0,o.jsx)(H,{toc:e,minHeadingLevel:n,maxHeadingLevel:i})})]})}const Z={tocMobile:"tocMobile_ITEo"};function X(){const{toc:t,frontMatter:e}=c();return(0,o.jsx)(G,{toc:t,minHeadingLevel:e.toc_min_heading_level,maxHeadingLevel:e.toc_max_heading_level,className:(0,u.A)(y.G.docs.docTocMobile,Z.tocMobile)})}const Q={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},J="table-of-contents__link toc-highlight",tt="table-of-contents__link--active";function et(t){let{className:e,...r}=t;return(0,o.jsx)("div",{className:(0,u.A)(Q.tableOfContents,"thin-scrollbar",e),children:(0,o.jsx)(H,{...r,linkClassName:J,linkActiveClassName:tt})})}function rt(){const{toc:t,frontMatter:e}=c();return(0,o.jsx)(et,{toc:t,minHeadingLevel:e.toc_min_heading_level,maxHeadingLevel:e.toc_max_heading_level,className:y.G.docs.docTocDesktop})}var nt=r(85225),it=r(28453),at=r(51807);function ot(t){let{children:e}=t;return(0,o.jsx)(it.x,{components:at.A,children:e})}function st(t){let{children:e}=t;const r=function(){const{metadata:t,frontMatter:e,contentTitle:r}=c();return e.hide_title||void 0!==r?null:t.title}();return(0,o.jsxs)("div",{className:(0,u.A)(y.G.docs.docMarkdown,"markdown"),children:[r&&(0,o.jsx)("header",{children:(0,o.jsx)(nt.A,{as:"h1",children:r})}),(0,o.jsx)(ot,{children:e})]})}var lt=r(44168),ct=r(21141);function ht(){return(0,o.jsx)(x.A,{id:"theme.contentVisibility.unlistedBanner.title",description:"The unlisted content banner title",children:"Unlisted page"})}function ut(){return(0,o.jsx)(x.A,{id:"theme.contentVisibility.unlistedBanner.message",description:"The unlisted content banner message",children:"This page is unlisted. Search engines will not index it, and only users having a direct link can access it."})}function dt(){return(0,o.jsx)(ct.A,{children:(0,o.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})}function pt(){return(0,o.jsx)(x.A,{id:"theme.contentVisibility.draftBanner.title",description:"The draft content banner title",children:"Draft page"})}function ft(){return(0,o.jsx)(x.A,{id:"theme.contentVisibility.draftBanner.message",description:"The draft content banner message",children:"This page is a draft. It will only be visible in dev and be excluded from the production build."})}var gt=r(54182);function mt(t){let{className:e}=t;return(0,o.jsx)(gt.A,{type:"caution",title:(0,o.jsx)(pt,{}),className:(0,u.A)(e,y.G.common.draftBanner),children:(0,o.jsx)(ft,{})})}function yt(t){let{className:e}=t;return(0,o.jsx)(gt.A,{type:"caution",title:(0,o.jsx)(ht,{}),className:(0,u.A)(e,y.G.common.unlistedBanner),children:(0,o.jsx)(ut,{})})}function xt(t){return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(dt,{}),(0,o.jsx)(yt,{...t})]})}function bt(t){let{metadata:e}=t;const{unlisted:r,frontMatter:n}=e;return(0,o.jsxs)(o.Fragment,{children:[(r||n.unlisted)&&(0,o.jsx)(xt,{}),n.draft&&(0,o.jsx)(mt,{})]})}const kt={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function Ct(t){let{children:e}=t;const r=function(){const{frontMatter:t,toc:e}=c(),r=(0,d.l)(),n=t.hide_table_of_contents,i=!n&&e.length>0;return{hidden:n,mobile:i?(0,o.jsx)(X,{}):void 0,desktop:!i||"desktop"!==r&&"ssr"!==r?void 0:(0,o.jsx)(rt,{})}}(),{metadata:n}=c();return(0,o.jsxs)("div",{className:"row",children:[(0,o.jsxs)("div",{className:(0,u.A)("col",!r.hidden&&kt.docItemCol),children:[(0,o.jsx)(bt,{metadata:n}),(0,o.jsx)(g.A,{}),(0,o.jsxs)("div",{className:kt.docItemContainer,children:[(0,o.jsxs)("article",{children:[(0,o.jsx)(lt.A,{}),(0,o.jsx)(m.A,{}),r.mobile,(0,o.jsx)(st,{children:e}),(0,o.jsx)(N,{})]}),(0,o.jsx)(f,{})]})]}),r.desktop&&(0,o.jsx)("div",{className:"col col--3",children:r.desktop})]})}function wt(t){const e=`docs-doc-id-${t.content.metadata.id}`,r=t.content;return(0,o.jsx)(l,{content:t.content,children:(0,o.jsxs)(i.e3,{className:e,children:[(0,o.jsx)(h,{}),(0,o.jsx)(Ct,{children:(0,o.jsx)(r,{})})]})})}},62400:(t,e,r)=>{"use strict";r.d(e,{A:()=>l});r(96540);var n=r(23230),i=r(34164),a=r(14783),o=r(74848);function s(t){const{permalink:e,title:r,subLabel:n,isNext:s}=t;return(0,o.jsxs)(a.A,{className:(0,i.A)("pagination-nav__link",s?"pagination-nav__link--next":"pagination-nav__link--prev"),to:e,children:[n&&(0,o.jsx)("div",{className:"pagination-nav__sublabel",children:n}),(0,o.jsx)("div",{className:"pagination-nav__label",children:r})]})}function l(t){const{previous:e,next:r}=t;return(0,o.jsxs)("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,n.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[e&&(0,o.jsx)(s,{...e,subLabel:(0,o.jsx)(n.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),r&&(0,o.jsx)(s,{...r,subLabel:(0,o.jsx)(n.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}},79436:(t,e,r)=>{"use strict";r.d(e,{A:()=>l});r(96540);var n=r(34164),i=r(23230),a=r(18630),o=r(91704),s=r(74848);function l(t){let{className:e}=t;const r=(0,o.r)();return r.badge?(0,s.jsx)("span",{className:(0,n.A)(e,a.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,s.jsx)(i.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:r.label},children:"Version: {versionLabel}"})}):null}},84799:(t,e,r)=>{"use strict";r.d(e,{A:()=>m});r(96540);var n=r(34164),i=r(97639),a=r(14783),o=r(23230),s=r(19802),l=r(18630),c=r(86457),h=r(91704),u=r(74848);const d={unreleased:function(t){let{siteTitle:e,versionMetadata:r}=t;return(0,u.jsx)(o.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:e,versionLabel:(0,u.jsx)("b",{children:r.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function(t){let{siteTitle:e,versionMetadata:r}=t;return(0,u.jsx)(o.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:e,versionLabel:(0,u.jsx)("b",{children:r.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function p(t){const e=d[t.versionMetadata.banner];return(0,u.jsx)(e,{...t})}function f(t){let{versionLabel:e,to:r,onClick:n}=t;return(0,u.jsx)(o.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:e,latestVersionLink:(0,u.jsx)("b",{children:(0,u.jsx)(a.A,{to:r,onClick:n,children:(0,u.jsx)(o.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function g(t){let{className:e,versionMetadata:r}=t;const{siteConfig:{title:a}}=(0,i.A)(),{pluginId:o}=(0,s.vT)({failfast:!0}),{savePreferredVersionName:h}=(0,c.g1)(o),{latestDocSuggestion:d,latestVersionSuggestion:g}=(0,s.HW)(o),m=d??(y=g).docs.find((t=>t.id===y.mainDocId));var y;return(0,u.jsxs)("div",{className:(0,n.A)(e,l.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,u.jsx)("div",{children:(0,u.jsx)(p,{siteTitle:a,versionMetadata:r})}),(0,u.jsx)("div",{className:"margin-top--md",children:(0,u.jsx)(f,{versionLabel:g.label,to:m.path,onClick:()=>h(g.name)})})]})}function m(t){let{className:e}=t;const r=(0,h.r)();return r.banner?(0,u.jsx)(g,{className:e,versionMetadata:r}):null}},13404:(t,e,r)=>{"use strict";r.d(e,{A:()=>rn});var n=r(96540),i=r(21141),a=r(11062),o=r(34164),s=r(7710),l=r(86957);function c(){const{prism:t}=(0,l.p)(),{colorMode:e}=(0,s.G)(),r=t.theme,n=t.darkTheme||r;return"dark"===e?n:r}var h=r(18630),u=r(18426),d=r.n(u);const p=/title=(?["'])(?.*?)\1/,f=/\{(?<range>[\d,-]+)\}/,g={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},m={...g,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},y=Object.keys(g);function x(t,e){const r=t.map((t=>{const{start:r,end:n}=m[t];return`(?:${r}\\s*(${e.flatMap((t=>[t.line,t.block?.start,t.block?.end].filter(Boolean))).join("|")})\\s*${n})`})).join("|");return new RegExp(`^\\s*(?:${r})\\s*$`)}function b(t,e){let r=t.replace(/\n$/,"");const{language:n,magicComments:i,metastring:a}=e;if(a&&f.test(a)){const t=a.match(f).groups.range;if(0===i.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${a}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const e=i[0].className,n=d()(t).filter((t=>t>0)).map((t=>[t-1,[e]]));return{lineClassNames:Object.fromEntries(n),code:r}}if(void 0===n)return{lineClassNames:{},code:r};const o=function(t,e){switch(t){case"js":case"javascript":case"ts":case"typescript":return x(["js","jsBlock"],e);case"jsx":case"tsx":return x(["js","jsBlock","jsx"],e);case"html":return x(["js","jsBlock","html"],e);case"python":case"py":case"bash":return x(["bash"],e);case"markdown":case"md":return x(["html","jsx","bash"],e);case"tex":case"latex":case"matlab":return x(["tex"],e);case"lua":case"haskell":case"sql":return x(["lua"],e);case"wasm":return x(["wasm"],e);case"vb":case"vba":case"visual-basic":return x(["vb","rem"],e);case"vbnet":return x(["vbnet","rem"],e);case"batch":return x(["rem"],e);case"basic":return x(["rem","f90"],e);case"fsharp":return x(["js","ml"],e);case"ocaml":case"sml":return x(["ml"],e);case"fortran":return x(["f90"],e);case"cobol":return x(["cobol"],e);default:return x(y,e)}}(n,i),s=r.split("\n"),l=Object.fromEntries(i.map((t=>[t.className,{start:0,range:""}]))),c=Object.fromEntries(i.filter((t=>t.line)).map((t=>{let{className:e,line:r}=t;return[r,e]}))),h=Object.fromEntries(i.filter((t=>t.block)).map((t=>{let{className:e,block:r}=t;return[r.start,e]}))),u=Object.fromEntries(i.filter((t=>t.block)).map((t=>{let{className:e,block:r}=t;return[r.end,e]})));for(let d=0;d<s.length;){const t=s[d].match(o);if(!t){d+=1;continue}const e=t.slice(1).find((t=>void 0!==t));c[e]?l[c[e]].range+=`${d},`:h[e]?l[h[e]].start=d:u[e]&&(l[u[e]].range+=`${l[u[e]].start}-${d-1},`),s.splice(d,1)}r=s.join("\n");const p={};return Object.entries(l).forEach((t=>{let[e,{range:r}]=t;d()(r).forEach((t=>{p[t]??=[],p[t].push(e)}))})),{lineClassNames:p,code:r}}const k="codeBlockContainer_Ckt0";var C=r(74848);function w(t){let{as:e,...r}=t;const n=function(t){const e={color:"--prism-color",backgroundColor:"--prism-background-color"},r={};return Object.entries(t.plain).forEach((t=>{let[n,i]=t;const a=e[n];a&&"string"==typeof i&&(r[a]=i)})),r}(c());return(0,C.jsx)(e,{...r,style:n,className:(0,o.A)(r.className,k,h.G.common.codeBlock)})}const _={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function v(t){let{children:e,className:r}=t;return(0,C.jsx)(w,{as:"pre",tabIndex:0,className:(0,o.A)(_.codeBlockStandalone,"thin-scrollbar",r),children:(0,C.jsx)("code",{className:_.codeBlockLines,children:e})})}var S=r(4799);const A={attributes:!0,characterData:!0,childList:!0,subtree:!0};function T(t,e){const[r,i]=(0,n.useState)(),a=(0,n.useCallback)((()=>{i(t.current?.closest("[role=tabpanel][hidden]"))}),[t,i]);(0,n.useEffect)((()=>{a()}),[a]),function(t,e,r){void 0===r&&(r=A);const i=(0,S._q)(e),a=(0,S.Be)(r);(0,n.useEffect)((()=>{const e=new MutationObserver(i);return t&&e.observe(t,a),()=>e.disconnect()}),[t,i,a])}(r,(t=>{t.forEach((t=>{"attributes"===t.type&&"hidden"===t.attributeName&&(e(),a())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}var M=r(71765);const B="codeLine_lJS_",L="codeLineNumber_Tfdd",F="codeLineContent_feaV";function $(t){let{line:e,classNames:r,showLineNumbers:n,getLineProps:i,getTokenProps:a}=t;1===e.length&&"\n"===e[0].content&&(e[0].content="");const s=i({line:e,className:(0,o.A)(r,n&&B)}),l=e.map(((t,e)=>(0,C.jsx)("span",{...a({token:t})},e)));return(0,C.jsxs)("span",{...s,children:[n?(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)("span",{className:L}),(0,C.jsx)("span",{className:F,children:l})]}):l,(0,C.jsx)("br",{})]})}var E=r(23230);function N(t){return(0,C.jsx)("svg",{viewBox:"0 0 24 24",...t,children:(0,C.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function D(t){return(0,C.jsx)("svg",{viewBox:"0 0 24 24",...t,children:(0,C.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const j={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function I(t){let{code:e,className:r}=t;const[i,a]=(0,n.useState)(!1),s=(0,n.useRef)(void 0),l=(0,n.useCallback)((()=>{!function(t,e){let{target:r=document.body}=void 0===e?{}:e;if("string"!=typeof t)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof t}\`.`);const n=document.createElement("textarea"),i=document.activeElement;n.value=t,n.setAttribute("readonly",""),n.style.contain="strict",n.style.position="absolute",n.style.left="-9999px",n.style.fontSize="12pt";const a=document.getSelection(),o=a.rangeCount>0&&a.getRangeAt(0);r.append(n),n.select(),n.selectionStart=0,n.selectionEnd=t.length;let s=!1;try{s=document.execCommand("copy")}catch{}n.remove(),o&&(a.removeAllRanges(),a.addRange(o)),i&&i.focus()}(e),a(!0),s.current=window.setTimeout((()=>{a(!1)}),1e3)}),[e]);return(0,n.useEffect)((()=>()=>window.clearTimeout(s.current)),[]),(0,C.jsx)("button",{type:"button","aria-label":i?(0,E.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,E.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,E.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,o.A)("clean-btn",r,j.copyButton,i&&j.copyButtonCopied),onClick:l,children:(0,C.jsxs)("span",{className:j.copyButtonIcons,"aria-hidden":"true",children:[(0,C.jsx)(N,{className:j.copyButtonIcon}),(0,C.jsx)(D,{className:j.copyButtonSuccessIcon})]})})}function O(t){return(0,C.jsx)("svg",{viewBox:"0 0 24 24",...t,children:(0,C.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const R="wordWrapButtonIcon_Bwma",P="wordWrapButtonEnabled_EoeP";function z(t){let{className:e,onClick:r,isEnabled:n}=t;const i=(0,E.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,C.jsx)("button",{type:"button",onClick:r,className:(0,o.A)("clean-btn",e,n&&P),"aria-label":i,title:i,children:(0,C.jsx)(O,{className:R,"aria-hidden":"true"})})}function K(t){let{children:e,className:r="",metastring:i,title:a,showLineNumbers:s,language:h}=t;const{prism:{defaultLanguage:u,magicComments:d}}=(0,l.p)(),f=function(t){return t?.toLowerCase()}(h??function(t){const e=t.split(" ").find((t=>t.startsWith("language-")));return e?.replace(/language-/,"")}(r)??u),g=c(),m=function(){const[t,e]=(0,n.useState)(!1),[r,i]=(0,n.useState)(!1),a=(0,n.useRef)(null),o=(0,n.useCallback)((()=>{const r=a.current.querySelector("code");t?r.removeAttribute("style"):(r.style.whiteSpace="pre-wrap",r.style.overflowWrap="anywhere"),e((t=>!t))}),[a,t]),s=(0,n.useCallback)((()=>{const{scrollWidth:t,clientWidth:e}=a.current,r=t>e||a.current.querySelector("code").hasAttribute("style");i(r)}),[a]);return T(a,s),(0,n.useEffect)((()=>{s()}),[t,s]),(0,n.useEffect)((()=>(window.addEventListener("resize",s,{passive:!0}),()=>{window.removeEventListener("resize",s)})),[s]),{codeBlockRef:a,isEnabled:t,isCodeScrollable:r,toggle:o}}(),y=function(t){return t?.match(p)?.groups.title??""}(i)||a,{lineClassNames:x,code:k}=b(e,{metastring:i,language:f,magicComments:d}),v=s??function(t){return Boolean(t?.includes("showLineNumbers"))}(i);return(0,C.jsxs)(w,{as:"div",className:(0,o.A)(r,f&&!r.includes(`language-${f}`)&&`language-${f}`),children:[y&&(0,C.jsx)("div",{className:_.codeBlockTitle,children:y}),(0,C.jsxs)("div",{className:_.codeBlockContent,children:[(0,C.jsx)(M.f4,{theme:g,code:k,language:f??"text",children:t=>{let{className:e,style:r,tokens:n,getLineProps:i,getTokenProps:a}=t;return(0,C.jsx)("pre",{tabIndex:0,ref:m.codeBlockRef,className:(0,o.A)(e,_.codeBlock,"thin-scrollbar"),style:r,children:(0,C.jsx)("code",{className:(0,o.A)(_.codeBlockLines,v&&_.codeBlockLinesWithNumbering),children:n.map(((t,e)=>(0,C.jsx)($,{line:t,getLineProps:i,getTokenProps:a,classNames:x[e],showLineNumbers:v},e)))})})}}),(0,C.jsxs)("div",{className:_.buttonGroup,children:[(m.isEnabled||m.isCodeScrollable)&&(0,C.jsx)(z,{className:_.codeButton,onClick:()=>m.toggle(),isEnabled:m.isEnabled}),(0,C.jsx)(I,{className:_.codeButton,code:k})]})]})]})}function q(t){let{children:e,...r}=t;const i=(0,a.A)(),o=function(t){return n.Children.toArray(t).some((t=>(0,n.isValidElement)(t)))?t:Array.isArray(t)?t.join(""):t}(e),s="string"==typeof o?K:v;return(0,C.jsx)(s,{...r,children:o},String(i))}function W(t){return(0,C.jsx)("code",{...t})}var H=r(14783);var U=r(37344),Y=r(94549);const V="details_lb9f",G="isBrowser_bmU9",Z="collapsibleContent_i85q";function X(t){return!!t&&("SUMMARY"===t.tagName||X(t.parentElement))}function Q(t,e){return!!t&&(t===e||Q(t.parentElement,e))}function J(t){let{summary:e,children:r,...i}=t;(0,U.A)().collectAnchor(i.id);const s=(0,a.A)(),l=(0,n.useRef)(null),{collapsed:c,setCollapsed:h}=(0,Y.u)({initialState:!i.open}),[u,d]=(0,n.useState)(i.open),p=n.isValidElement(e)?e:(0,C.jsx)("summary",{children:e??"Details"});return(0,C.jsxs)("details",{...i,ref:l,open:u,"data-collapsed":c,className:(0,o.A)(V,s&&G,i.className),onMouseDown:t=>{X(t.target)&&t.detail>1&&t.preventDefault()},onClick:t=>{t.stopPropagation();const e=t.target;X(e)&&Q(e,l.current)&&(t.preventDefault(),c?(h(!1),d(!0)):h(!0))},children:[p,(0,C.jsx)(Y.N,{lazy:!1,collapsed:c,disableSSRStyle:!0,onCollapseTransitionEnd:t=>{h(t),d(!t)},children:(0,C.jsx)("div",{className:Z,children:r})})]})}const tt="details_b_Ee";function et(t){let{...e}=t;return(0,C.jsx)(J,{...e,className:(0,o.A)("alert alert--info",tt,e.className)})}function rt(t){const e=n.Children.toArray(t.children),r=e.find((t=>n.isValidElement(t)&&"summary"===t.type)),i=(0,C.jsx)(C.Fragment,{children:e.filter((t=>t!==r))});return(0,C.jsx)(et,{...t,summary:r,children:i})}var nt=r(85225);function it(t){return(0,C.jsx)(nt.A,{...t})}const at="containsTaskList_mC6p";function ot(t){if(void 0!==t)return(0,o.A)(t,t?.includes("contains-task-list")&&at)}const st="img_ev3q";var lt=r(54182),ct=r(33832),ht=r(34176),ut=r(59874),dt=r(87308),pt=(r(37938),r(1282),r(64532)),ft=(r(47588),r(33115),r(10483),r(8159)),gt=r(6144),mt=r(77286),yt=r(10009),xt=r(60513),bt=r(20007),kt="comm",Ct="rule",wt="decl",_t=Math.abs,vt=String.fromCharCode;Object.assign;function St(t){return t.trim()}function At(t,e,r){return t.replace(e,r)}function Tt(t,e,r){return t.indexOf(e,r)}function Mt(t,e){return 0|t.charCodeAt(e)}function Bt(t,e,r){return t.slice(e,r)}function Lt(t){return t.length}function Ft(t,e){return e.push(t),t}function $t(t,e){for(var r="",n=0;n<t.length;n++)r+=e(t[n],n,t,e)||"";return r}function Et(t,e,r,n){switch(t.type){case"@layer":if(t.children.length)break;case"@import":case wt:return t.return=t.return||t.value;case kt:return"";case"@keyframes":return t.return=t.value+"{"+$t(t.children,n)+"}";case Ct:if(!Lt(t.value=t.props.join(",")))return""}return Lt(r=$t(t.children,n))?t.return=t.value+"{"+r+"}":""}var Nt=1,Dt=1,jt=0,It=0,Ot=0,Rt="";function Pt(t,e,r,n,i,a,o,s){return{value:t,root:e,parent:r,type:n,props:i,children:a,line:Nt,column:Dt,length:o,return:"",siblings:s}}function zt(){return Ot=It>0?Mt(Rt,--It):0,Dt--,10===Ot&&(Dt=1,Nt--),Ot}function Kt(){return Ot=It<jt?Mt(Rt,It++):0,Dt++,10===Ot&&(Dt=1,Nt++),Ot}function qt(){return Mt(Rt,It)}function Wt(){return It}function Ht(t,e){return Bt(Rt,t,e)}function Ut(t){switch(t){case 0:case 9:case 10:case 13:case 32:return 5;case 33:case 43:case 44:case 47:case 62:case 64:case 126:case 59:case 123:case 125:return 4;case 58:return 3;case 34:case 39:case 40:case 91:return 2;case 41:case 93:return 1}return 0}function Yt(t){return Nt=Dt=1,jt=Lt(Rt=t),It=0,[]}function Vt(t){return Rt="",t}function Gt(t){return St(Ht(It-1,Qt(91===t?t+2:40===t?t+1:t)))}function Zt(t){for(;(Ot=qt())&&Ot<33;)Kt();return Ut(t)>2||Ut(Ot)>3?"":" "}function Xt(t,e){for(;--e&&Kt()&&!(Ot<48||Ot>102||Ot>57&&Ot<65||Ot>70&&Ot<97););return Ht(t,Wt()+(e<6&&32==qt()&&32==Kt()))}function Qt(t){for(;Kt();)switch(Ot){case t:return It;case 34:case 39:34!==t&&39!==t&&Qt(Ot);break;case 40:41===t&&Qt(t);break;case 92:Kt()}return It}function Jt(t,e){for(;Kt()&&t+Ot!==57&&(t+Ot!==84||47!==qt()););return"/*"+Ht(e,It-1)+"*"+vt(47===t?t:Kt())}function te(t){for(;!Ut(qt());)Kt();return Ht(t,It)}function ee(t){return Vt(re("",null,null,null,[""],t=Yt(t),0,[0],t))}function re(t,e,r,n,i,a,o,s,l){for(var c=0,h=0,u=o,d=0,p=0,f=0,g=1,m=1,y=1,x=0,b="",k=i,C=a,w=n,_=b;m;)switch(f=x,x=Kt()){case 40:if(108!=f&&58==Mt(_,u-1)){-1!=Tt(_+=At(Gt(x),"&","&\f"),"&\f",_t(c?s[c-1]:0))&&(y=-1);break}case 34:case 39:case 91:_+=Gt(x);break;case 9:case 10:case 13:case 32:_+=Zt(f);break;case 92:_+=Xt(Wt()-1,7);continue;case 47:switch(qt()){case 42:case 47:Ft(ie(Jt(Kt(),Wt()),e,r,l),l),5!=Ut(f||1)&&5!=Ut(qt()||1)||!Lt(_)||" "===Bt(_,-1,void 0)||(_+=" ");break;default:_+="/"}break;case 123*g:s[c++]=Lt(_)*y;case 125*g:case 59:case 0:switch(x){case 0:case 125:m=0;case 59+h:-1==y&&(_=At(_,/\f/g,"")),p>0&&(Lt(_)-u||0===g&&47===f)&&Ft(p>32?ae(_+";",n,r,u-1,l):ae(At(_," ","")+";",n,r,u-2,l),l);break;case 59:_+=";";default:if(Ft(w=ne(_,e,r,c,h,i,s,b,k=[],C=[],u,a),a),123===x)if(0===h)re(_,e,w,w,k,a,u,s,C);else switch(99===d&&110===Mt(_,3)?100:d){case 100:case 108:case 109:case 115:re(t,w,w,n&&Ft(ne(t,w,w,0,0,i,s,b,i,k=[],u,C),C),i,C,u,s,n?k:C);break;default:re(_,w,w,w,[""],C,0,s,C)}}c=h=p=0,g=y=1,b=_="",u=o;break;case 58:u=1+Lt(_),p=f;default:if(g<1)if(123==x)--g;else if(125==x&&0==g++&&125==zt())continue;switch(_+=vt(x),x*g){case 38:y=h>0?1:(_+="\f",-1);break;case 44:s[c++]=(Lt(_)-1)*y,y=1;break;case 64:45===qt()&&(_+=Gt(Kt())),d=qt(),h=u=Lt(b=_+=te(Wt())),x++;break;case 45:45===f&&2==Lt(_)&&(g=0)}}return a}function ne(t,e,r,n,i,a,o,s,l,c,h,u){for(var d=i-1,p=0===i?a:[""],f=function(t){return t.length}(p),g=0,m=0,y=0;g<n;++g)for(var x=0,b=Bt(t,d+1,d=_t(m=o[g])),k=t;x<f;++x)(k=St(m>0?p[x]+" "+b:At(b,/&\f/g,p[x])))&&(l[y++]=k);return Pt(t,e,r,0===i?Ct:s,l,c,h,u)}function ie(t,e,r,n){return Pt(t,e,r,kt,vt(Ot),Bt(t,2,-2),0,n)}function ae(t,e,r,n,i){return Pt(t,e,r,wt,Bt(t,0,n),Bt(t,n+1,-1),n,i)}var oe=r(99418),se=r(66401),le={id:"c4",detector:(0,yt.K2)((t=>/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(2664).then(r.bind(r,82664));return{id:"c4",diagram:t}}),"loader")},ce="flowchart",he={id:ce,detector:(0,yt.K2)(((t,e)=>"dagre-wrapper"!==e?.flowchart?.defaultRenderer&&"elk"!==e?.flowchart?.defaultRenderer&&/^\s*graph/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(4485).then(r.bind(r,44485));return{id:ce,diagram:t}}),"loader")},ue="flowchart-v2",de={id:ue,detector:(0,yt.K2)(((t,e)=>"dagre-d3"!==e?.flowchart?.defaultRenderer&&("elk"===e?.flowchart?.defaultRenderer&&(e.layout="elk"),!(!/^\s*graph/.test(t)||"dagre-wrapper"!==e?.flowchart?.defaultRenderer)||/^\s*flowchart/.test(t))),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(4485).then(r.bind(r,44485));return{id:ue,diagram:t}}),"loader")},pe={id:"er",detector:(0,yt.K2)((t=>/^\s*erDiagram/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(2334),r.e(7306)]).then(r.bind(r,17306));return{id:"er",diagram:t}}),"loader")},fe="gitGraph",ge={id:fe,detector:(0,yt.K2)((t=>/^\s*gitGraph/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(8731),r.e(5978)]).then(r.bind(r,45978));return{id:fe,diagram:t}}),"loader")},me="gantt",ye={id:me,detector:(0,yt.K2)((t=>/^\s*gantt/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(6244).then(r.bind(r,66244));return{id:me,diagram:t}}),"loader")},xe="info",be={id:xe,detector:(0,yt.K2)((t=>/^\s*info/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(8731),r.e(7354)]).then(r.bind(r,97354));return{id:xe,diagram:t}}),"loader")},ke={id:"pie",detector:(0,yt.K2)((t=>/^\s*pie/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(8731),r.e(1825)]).then(r.bind(r,61825));return{id:"pie",diagram:t}}),"loader")},Ce="quadrantChart",we={id:Ce,detector:(0,yt.K2)((t=>/^\s*quadrantChart/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(4632).then(r.bind(r,14632));return{id:Ce,diagram:t}}),"loader")},_e="xychart",ve={id:_e,detector:(0,yt.K2)((t=>/^\s*xychart-beta/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(545).then(r.bind(r,50545));return{id:_e,diagram:t}}),"loader")},Se="requirement",Ae={id:Se,detector:(0,yt.K2)((t=>/^\s*requirement(Diagram)?/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(2334),r.e(8413)]).then(r.bind(r,88413));return{id:Se,diagram:t}}),"loader")},Te="sequence",Me={id:Te,detector:(0,yt.K2)((t=>/^\s*sequenceDiagram/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(8540).then(r.bind(r,58540));return{id:Te,diagram:t}}),"loader")},Be="class",Le={id:Be,detector:(0,yt.K2)(((t,e)=>"dagre-wrapper"!==e?.class?.defaultRenderer&&/^\s*classDiagram/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(1478),r.e(391)]).then(r.bind(r,90391));return{id:Be,diagram:t}}),"loader")},Fe="classDiagram",$e={id:Fe,detector:(0,yt.K2)(((t,e)=>!(!/^\s*classDiagram/.test(t)||"dagre-wrapper"!==e?.class?.defaultRenderer)||/^\s*classDiagram-v2/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(1478),r.e(3056)]).then(r.bind(r,43056));return{id:Fe,diagram:t}}),"loader")},Ee="state",Ne={id:Ee,detector:(0,yt.K2)(((t,e)=>"dagre-wrapper"!==e?.state?.defaultRenderer&&/^\s*stateDiagram/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(2334),r.e(758),r.e(9732)]).then(r.bind(r,89732));return{id:Ee,diagram:t}}),"loader")},De="stateDiagram",je={id:De,detector:(0,yt.K2)(((t,e)=>!!/^\s*stateDiagram-v2/.test(t)||!(!/^\s*stateDiagram/.test(t)||"dagre-wrapper"!==e?.state?.defaultRenderer)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(758),r.e(5110)]).then(r.bind(r,65110));return{id:De,diagram:t}}),"loader")},Ie="journey",Oe={id:Ie,detector:(0,yt.K2)((t=>/^\s*journey/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(6237).then(r.bind(r,26237));return{id:Ie,diagram:t}}),"loader")},Re={draw:(0,yt.K2)(((t,e,r)=>{yt.Rm.debug("rendering svg for syntax error\n");const n=(0,mt.D)(e),i=n.append("g");n.attr("viewBox","0 0 2412 512"),(0,yt.a$)(n,100,512,!0),i.append("path").attr("class","error-icon").attr("d","m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"),i.append("path").attr("class","error-icon").attr("d","m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"),i.append("path").attr("class","error-icon").attr("d","m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"),i.append("path").attr("class","error-icon").attr("d","m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"),i.append("path").attr("class","error-icon").attr("d","m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"),i.append("path").attr("class","error-icon").attr("d","m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"),i.append("text").attr("class","error-text").attr("x",1440).attr("y",250).attr("font-size","150px").style("text-anchor","middle").text("Syntax error in text"),i.append("text").attr("class","error-text").attr("x",1250).attr("y",400).attr("font-size","100px").style("text-anchor","middle").text(`mermaid version ${r}`)}),"draw")},Pe=Re,ze={db:{},renderer:Re,parser:{parse:(0,yt.K2)((()=>{}),"parse")}},Ke="flowchart-elk",qe={id:Ke,detector:(0,yt.K2)(((t,e={})=>!!(/^\s*flowchart-elk/.test(t)||/^\s*flowchart|graph/.test(t)&&"elk"===e?.flowchart?.defaultRenderer)&&(e.layout="elk",!0)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(4485).then(r.bind(r,44485));return{id:Ke,diagram:t}}),"loader")},We="timeline",He={id:We,detector:(0,yt.K2)((t=>/^\s*timeline/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(7691).then(r.bind(r,17691));return{id:We,diagram:t}}),"loader")},Ue="mindmap",Ye={id:Ue,detector:(0,yt.K2)((t=>/^\s*mindmap/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(165),r.e(6383)]).then(r.bind(r,96383));return{id:Ue,diagram:t}}),"loader")},Ve="kanban",Ge={id:Ve,detector:(0,yt.K2)((t=>/^\s*kanban/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(6355).then(r.bind(r,76355));return{id:Ve,diagram:t}}),"loader")},Ze="sankey",Xe={id:Ze,detector:(0,yt.K2)((t=>/^\s*sankey-beta/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await r.e(4697).then(r.bind(r,34697));return{id:Ze,diagram:t}}),"loader")},Qe="packet",Je={id:Qe,detector:(0,yt.K2)((t=>/^\s*packet-beta/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(8731),r.e(7357)]).then(r.bind(r,57357));return{id:Qe,diagram:t}}),"loader")},tr="block",er={id:tr,detector:(0,yt.K2)((t=>/^\s*block-beta/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(5410)]).then(r.bind(r,65410));return{id:tr,diagram:t}}),"loader")},rr="architecture",nr={id:rr,detector:(0,yt.K2)((t=>/^\s*architecture/.test(t)),"detector"),loader:(0,yt.K2)((async()=>{const{diagram:t}=await Promise.all([r.e(3624),r.e(8731),r.e(165),r.e(3175)]).then(r.bind(r,83175));return{id:rr,diagram:t}}),"loader")},ir=!1,ar=(0,yt.K2)((()=>{ir||(ir=!0,(0,yt.Js)("error",ze,(t=>"error"===t.toLowerCase().trim())),(0,yt.Js)("---",{db:{clear:(0,yt.K2)((()=>{}),"clear")},styles:{},renderer:{draw:(0,yt.K2)((()=>{}),"draw")},parser:{parse:(0,yt.K2)((()=>{throw new Error("Diagrams beginning with --- are not valid. If you were trying to use a YAML front-matter, please ensure that you've correctly opened and closed the YAML front-matter with un-indented `---` blocks")}),"parse")},init:(0,yt.K2)((()=>null),"init")},(t=>t.toLowerCase().trimStart().startsWith("---"))),(0,yt.Xd)(le,Ge,$e,Le,pe,ye,be,ke,Ae,Me,qe,de,he,Ye,He,ge,je,Ne,Oe,we,Xe,Je,ve,er,nr))}),"addDiagrams"),or=(0,yt.K2)((async()=>{yt.Rm.debug("Loading registered diagrams");const t=(await Promise.allSettled(Object.entries(yt.mW).map((async([t,{detector:e,loader:r}])=>{if(r)try{(0,yt.Gs)(t)}catch{try{const{diagram:t,id:n}=await r();(0,yt.Js)(n,t,e)}catch(n){throw yt.Rm.error(`Failed to load external diagram with key ${t}. Removing from detectors.`),delete yt.mW[t],n}}})))).filter((t=>"rejected"===t.status));if(t.length>0){yt.Rm.error(`Failed to load ${t.length} external diagrams`);for(const e of t)yt.Rm.error(e);throw new Error(`Failed to load ${t.length} external diagrams`)}}),"loadRegisteredDiagrams");function sr(t,e){t.attr("role","graphics-document document"),""!==e&&t.attr("aria-roledescription",e)}function lr(t,e,r,n){if(void 0!==t.insert){if(r){const e=`chart-desc-${n}`;t.attr("aria-describedby",e),t.insert("desc",":first-child").attr("id",e).text(r)}if(e){const r=`chart-title-${n}`;t.attr("aria-labelledby",r),t.insert("title",":first-child").attr("id",r).text(e)}}}(0,yt.K2)(sr,"setA11yDiagramInfo"),(0,yt.K2)(lr,"addSVGa11yTitleDescription");var cr=class t{constructor(t,e,r,n,i){this.type=t,this.text=e,this.db=r,this.parser=n,this.renderer=i}static{(0,yt.K2)(this,"Diagram")}static async fromText(e,r={}){const n=(0,yt.zj)(),i=(0,yt.Ch)(e,n);e=(0,ft.C4)(e)+"\n";try{(0,yt.Gs)(i)}catch{const t=(0,yt.J$)(i);if(!t)throw new yt.C0(`Diagram ${i} not found.`);const{id:e,diagram:r}=await t();(0,yt.Js)(e,r)}const{db:a,parser:o,renderer:s,init:l}=(0,yt.Gs)(i);return o.parser&&(o.parser.yy=a),a.clear?.(),l?.(n),r.title&&a.setDiagramTitle?.(r.title),await o.parse(e),new t(i,e,a,o,s)}async render(t,e){await this.renderer.draw(this.text,t,e,this)}getParser(){return this.parser}getType(){return this.type}},hr=[],ur=(0,yt.K2)((()=>{hr.forEach((t=>{t()})),hr=[]}),"attachFunctions"),dr=(0,yt.K2)((t=>t.replace(/^\s*%%(?!{)[^\n]+\n?/gm,"").trimStart()),"cleanupComments");function pr(t){const e=t.match(yt.EJ);if(!e)return{text:t,metadata:{}};let r=(0,ut.H)(e[1],{schema:ut.r})??{};r="object"!=typeof r||Array.isArray(r)?{}:r;const n={};return r.displayMode&&(n.displayMode=r.displayMode.toString()),r.title&&(n.title=r.title.toString()),r.config&&(n.config=r.config),{text:t.slice(e[0].length),metadata:n}}(0,yt.K2)(pr,"extractFrontMatter");var fr=(0,yt.K2)((t=>t.replace(/\r\n?/g,"\n").replace(/<(\w+)([^>]*)>/g,((t,e,r)=>"<"+e+r.replace(/="([^"]*)"/g,"='$1'")+">"))),"cleanupText"),gr=(0,yt.K2)((t=>{const{text:e,metadata:r}=pr(t),{displayMode:n,title:i,config:a={}}=r;return n&&(a.gantt||(a.gantt={}),a.gantt.displayMode=n),{title:i,config:a,text:e}}),"processFrontmatter"),mr=(0,yt.K2)((t=>{const e=ft._K.detectInit(t)??{},r=ft._K.detectDirective(t,"wrap");return Array.isArray(r)?e.wrap=r.some((({type:t})=>"wrap"===t)):"wrap"===r?.type&&(e.wrap=!0),{text:(0,ft.vU)(t),directive:e}}),"processDirectives");function yr(t){const e=fr(t),r=gr(e),n=mr(r.text),i=(0,ft.$t)(r.config,n.directive);return{code:t=dr(n.text),title:r.title,config:i}}function xr(t){const e=(new TextEncoder).encode(t),r=Array.from(e,(t=>String.fromCodePoint(t))).join("");return btoa(r)}(0,yt.K2)(yr,"preprocessDiagram"),(0,yt.K2)(xr,"toBase64");var br=["foreignobject"],kr=["dominant-baseline"];function Cr(t){const e=yr(t);return(0,yt.cL)(),(0,yt.xA)(e.config??{}),e}async function wr(t,e){ar();try{const{code:e,config:r}=Cr(t);return{diagramType:(await Er(e)).type,config:r}}catch(r){if(e?.suppressErrors)return!1;throw r}}(0,yt.K2)(Cr,"processAndSetConfigs"),(0,yt.K2)(wr,"parse");var _r=(0,yt.K2)(((t,e,r=[])=>`\n.${t} ${e} { ${r.join(" !important; ")} !important; }`),"cssImportantStyles"),vr=(0,yt.K2)(((t,e=new Map)=>{let r="";if(void 0!==t.themeCSS&&(r+=`\n${t.themeCSS}`),void 0!==t.fontFamily&&(r+=`\n:root { --mermaid-font-family: ${t.fontFamily}}`),void 0!==t.altFontFamily&&(r+=`\n:root { --mermaid-alt-font-family: ${t.altFontFamily}}`),e instanceof Map){const n=t.htmlLabels??t.flowchart?.htmlLabels?["> *","span"]:["rect","polygon","ellipse","circle","path"];e.forEach((t=>{(0,se.A)(t.styles)||n.forEach((e=>{r+=_r(t.id,e,t.styles)})),(0,se.A)(t.textStyles)||(r+=_r(t.id,"tspan",(t?.textStyles||[]).map((t=>t.replace("color","fill")))))}))}return r}),"createCssStyles"),Sr=(0,yt.K2)(((t,e,r,n)=>{const i=vr(t,r);return $t(ee(`${n}{${(0,yt.tM)(e,i,t.themeVariables)}}`),Et)}),"createUserStyles"),Ar=(0,yt.K2)(((t="",e,r)=>{let n=t;return r||e||(n=n.replace(/marker-end="url\([\d+./:=?A-Za-z-]*?#/g,'marker-end="url(#')),n=(0,ft.Sm)(n),n=n.replace(/<br>/g,"<br/>"),n}),"cleanUpSvgCode"),Tr=(0,yt.K2)(((t="",e)=>`<iframe style="width:100%;height:${e?.viewBox?.baseVal?.height?e.viewBox.baseVal.height+"px":"100%"};border:0;margin:0;" src="data:text/html;charset=UTF-8;base64,${xr(`<body style="margin:0">${t}</body>`)}" sandbox="allow-top-navigation-by-user-activation allow-popups">\n The "iframe" tag is not supported by your browser.\n</iframe>`),"putIntoIFrame"),Mr=(0,yt.K2)(((t,e,r,n,i)=>{const a=t.append("div");a.attr("id",r),n&&a.attr("style",n);const o=a.append("svg").attr("id",e).attr("width","100%").attr("xmlns","http://www.w3.org/2000/svg");return i&&o.attr("xmlns:xlink",i),o.append("g"),t}),"appendDivSvgG");function Br(t,e){return t.append("iframe").attr("id",e).attr("style","width: 100%; height: 100%;").attr("sandbox","")}(0,yt.K2)(Br,"sandboxedIframe");var Lr=(0,yt.K2)(((t,e,r,n)=>{t.getElementById(e)?.remove(),t.getElementById(r)?.remove(),t.getElementById(n)?.remove()}),"removeExistingElements"),Fr=(0,yt.K2)((async function(t,e,r){ar();const n=Cr(e);e=n.code;const i=(0,yt.zj)();yt.Rm.debug(i),e.length>(i?.maxTextSize??5e4)&&(e="graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa");const a="#"+t,o="i"+t,s="#"+o,l="d"+t,c="#"+l,h=(0,yt.K2)((()=>{const t=d?s:c,e=(0,bt.Ltv)(t).node();e&&"remove"in e&&e.remove()}),"removeTempElements");let u=(0,bt.Ltv)("body");const d="sandbox"===i.securityLevel,p="loose"===i.securityLevel,f=i.fontFamily;if(void 0!==r){if(r&&(r.innerHTML=""),d){const t=Br((0,bt.Ltv)(r),o);u=(0,bt.Ltv)(t.nodes()[0].contentDocument.body),u.node().style.margin=0}else u=(0,bt.Ltv)(r);Mr(u,t,l,`font-family: ${f}`,"http://www.w3.org/1999/xlink")}else{if(Lr(document,t,l,o),d){const t=Br((0,bt.Ltv)("body"),o);u=(0,bt.Ltv)(t.nodes()[0].contentDocument.body),u.node().style.margin=0}else u=(0,bt.Ltv)("body");Mr(u,t,l)}let g,m;try{g=await cr.fromText(e,{title:n.title})}catch(M){if(i.suppressErrorRendering)throw h(),M;g=await cr.fromText("error"),m=M}const y=u.select(c).node(),x=g.type,b=y.firstChild,k=b.firstChild,C=g.renderer.getClasses?.(e,g),w=Sr(i,x,C,a),_=document.createElement("style");_.innerHTML=w,b.insertBefore(_,k);try{await g.renderer.draw(e,t,gt.r,g)}catch(B){throw i.suppressErrorRendering?h():Pe.draw(e,t,gt.r),B}const v=u.select(`${c} svg`),S=g.db.getAccTitle?.(),A=g.db.getAccDescription?.();Nr(x,v,S,A),u.select(`[id="${t}"]`).selectAll("foreignobject > *").attr("xmlns","http://www.w3.org/1999/xhtml");let T=u.select(c).node().innerHTML;if(yt.Rm.debug("config.arrowMarkerAbsolute",i.arrowMarkerAbsolute),T=Ar(T,d,(0,yt._3)(i.arrowMarkerAbsolute)),d){const t=u.select(c+" svg").node();T=Tr(T,t)}else p||(T=oe.A.sanitize(T,{ADD_TAGS:br,ADD_ATTR:kr,HTML_INTEGRATION_POINTS:{foreignobject:!0}}));if(ur(),m)throw m;return h(),{diagramType:x,svg:T,bindFunctions:g.db.bindFunctions}}),"render");function $r(t={}){const e=(0,yt.hH)({},t);e?.fontFamily&&!e.themeVariables?.fontFamily&&(e.themeVariables||(e.themeVariables={}),e.themeVariables.fontFamily=e.fontFamily),(0,yt.wZ)(e),e?.theme&&e.theme in yt.H$?e.themeVariables=yt.H$[e.theme].getThemeVariables(e.themeVariables):e&&(e.themeVariables=yt.H$.default.getThemeVariables(e.themeVariables));const r="object"==typeof e?(0,yt.UU)(e):(0,yt.Q2)();(0,yt.He)(r.logLevel),ar()}(0,yt.K2)($r,"initialize");var Er=(0,yt.K2)(((t,e={})=>{const{code:r}=yr(t);return cr.fromText(r,e)}),"getDiagramFromText");function Nr(t,e,r,n){sr(e,t),lr(e,r,n,e.attr("id"))}(0,yt.K2)(Nr,"addA11yInfo");var Dr=Object.freeze({render:Fr,parse:wr,getDiagramFromText:Er,initialize:$r,getConfig:yt.zj,setConfig:yt.Nk,getSiteConfig:yt.Q2,updateSiteConfig:yt.B6,reset:(0,yt.K2)((()=>{(0,yt.cL)()}),"reset"),globalReset:(0,yt.K2)((()=>{(0,yt.cL)(yt.sb)}),"globalReset"),defaultConfig:yt.sb});(0,yt.He)((0,yt.zj)().logLevel),(0,yt.cL)((0,yt.zj)());var jr=(0,yt.K2)(((t,e,r)=>{yt.Rm.warn(t),(0,ft.dq)(t)?(r&&r(t.str,t.hash),e.push({...t,message:t.str,error:t})):(r&&r(t),t instanceof Error&&e.push({str:t.message,message:t.message,hash:t.name,error:t}))}),"handleError"),Ir=(0,yt.K2)((async function(t={querySelector:".mermaid"}){try{await Or(t)}catch(e){if((0,ft.dq)(e)&&yt.Rm.error(e.str),Gr.parseError&&Gr.parseError(e),!t.suppressErrors)throw yt.Rm.error("Use the suppressErrors option to suppress these errors"),e}}),"run"),Or=(0,yt.K2)((async function({postRenderCallback:t,querySelector:e,nodes:r}={querySelector:".mermaid"}){const n=Dr.getConfig();let i;if(yt.Rm.debug((t?"":"No ")+"Callback function found"),r)i=r;else{if(!e)throw new Error("Nodes and querySelector are both undefined");i=document.querySelectorAll(e)}yt.Rm.debug(`Found ${i.length} diagrams`),void 0!==n?.startOnLoad&&(yt.Rm.debug("Start On Load: "+n?.startOnLoad),Dr.updateSiteConfig({startOnLoad:n?.startOnLoad}));const a=new ft._K.InitIDGenerator(n.deterministicIds,n.deterministicIDSeed);let o;const s=[];for(const c of Array.from(i)){if(yt.Rm.info("Rendering diagram: "+c.id),c.getAttribute("data-processed"))continue;c.setAttribute("data-processed","true");const e=`mermaid-${a.next()}`;o=c.innerHTML,o=(0,xt.T)(ft._K.entityDecode(o)).trim().replace(/<br\s*\/?>/gi,"<br/>");const r=ft._K.detectInit(o);r&&yt.Rm.debug("Detected early reinit: ",r);try{const{svg:r,bindFunctions:n}=await Vr(e,o,c);c.innerHTML=r,t&&await t(e),n&&n(c)}catch(l){jr(l,s,Gr.parseError)}}if(s.length>0)throw s[0]}),"runThrowsErrors"),Rr=(0,yt.K2)((function(t){Dr.initialize(t)}),"initialize"),Pr=(0,yt.K2)((async function(t,e,r){yt.Rm.warn("mermaid.init is deprecated. Please use run instead."),t&&Rr(t);const n={postRenderCallback:r,querySelector:".mermaid"};"string"==typeof e?n.querySelector=e:e&&(e instanceof HTMLElement?n.nodes=[e]:n.nodes=e),await Ir(n)}),"init"),zr=(0,yt.K2)((async(t,{lazyLoad:e=!0}={})=>{ar(),(0,yt.Xd)(...t),!1===e&&await or()}),"registerExternalDiagrams"),Kr=(0,yt.K2)((function(){if(Gr.startOnLoad){const{startOnLoad:t}=Dr.getConfig();t&&Gr.run().catch((t=>yt.Rm.error("Mermaid failed to initialize",t)))}}),"contentLoaded");"undefined"!=typeof document&&window.addEventListener("load",Kr,!1);var qr=(0,yt.K2)((function(t){Gr.parseError=t}),"setParseErrorHandler"),Wr=[],Hr=!1,Ur=(0,yt.K2)((async()=>{if(!Hr){for(Hr=!0;Wr.length>0;){const e=Wr.shift();if(e)try{await e()}catch(t){yt.Rm.error("Error executing queue",t)}}Hr=!1}}),"executeQueue"),Yr=(0,yt.K2)((async(t,e)=>new Promise(((r,n)=>{const i=(0,yt.K2)((()=>new Promise(((i,a)=>{Dr.parse(t,e).then((t=>{i(t),r(t)}),(t=>{yt.Rm.error("Error parsing",t),Gr.parseError?.(t),a(t),n(t)}))}))),"performCall");Wr.push(i),Ur().catch(n)}))),"parse"),Vr=(0,yt.K2)(((t,e,r)=>new Promise(((n,i)=>{const a=(0,yt.K2)((()=>new Promise(((a,o)=>{Dr.render(t,e,r).then((t=>{a(t),n(t)}),(t=>{yt.Rm.error("Error parsing",t),Gr.parseError?.(t),o(t),i(t)}))}))),"performCall");Wr.push(a),Ur().catch(i)}))),"render"),Gr={startOnLoad:!0,mermaidAPI:Dr,parse:Yr,render:Vr,init:Pr,run:Ir,registerExternalDiagrams:zr,registerLayoutLoaders:dt.sO,initialize:Rr,parseError:void 0,contentLoaded:Kr,setParseErrorHandler:qr,detectType:yt.Ch,registerIconPacks:pt.pC},Zr=Gr;function Xr(){const{colorMode:t}=(0,s.G)(),e=(0,l.p)().mermaid,r=e.theme[t],{options:i}=e;return(0,n.useMemo)((()=>({startOnLoad:!1,...i,theme:r})),[r,i])}function Qr(t){let{text:e,config:r}=t;const[i,a]=(0,n.useState)(null),o=(0,n.useRef)(`mermaid-svg-${Math.round(1e7*Math.random())}`).current,s=Xr(),l=r??s;return(0,n.useEffect)((()=>{(async function(t){let{id:e,text:r,config:n}=t;Zr.mermaidAPI.initialize(n);try{return await Zr.render(e,r)}catch(i){throw document.querySelector(`#d${e}`)?.remove(),i}})({id:o,text:e,config:l}).then(a).catch((t=>{a((()=>{throw t}))}))}),[o,e,l]),i}const Jr="container_lyt7";function tn(t){let{renderResult:e}=t;const r=(0,n.useRef)(null);return(0,n.useEffect)((()=>{const t=r.current;e.bindFunctions?.(t)}),[e]),(0,C.jsx)("div",{ref:r,className:`docusaurus-mermaid-container ${Jr}`,dangerouslySetInnerHTML:{__html:e.svg}})}function en(t){let{value:e}=t;const r=Qr({text:e});return null===r?null:(0,C.jsx)(tn,{renderResult:r})}const rn={Head:i.A,details:rt,Details:rt,code:function(t){return function(t){return void 0!==t.children&&n.Children.toArray(t.children).every((t=>"string"==typeof t&&!t.includes("\n")))}(t)?(0,C.jsx)(W,{...t}):(0,C.jsx)(q,{...t})},a:function(t){return(0,C.jsx)(H.A,{...t})},pre:function(t){return(0,C.jsx)(C.Fragment,{children:t.children})},ul:function(t){return(0,C.jsx)("ul",{...t,className:ot(t.className)})},li:function(t){return(0,U.A)().collectAnchor(t.id),(0,C.jsx)("li",{...t})},img:function(t){return(0,C.jsx)("img",{decoding:"async",loading:"lazy",...t,className:(e=t.className,(0,o.A)(e,st))});var e},h1:t=>(0,C.jsx)(it,{as:"h1",...t}),h2:t=>(0,C.jsx)(it,{as:"h2",...t}),h3:t=>(0,C.jsx)(it,{as:"h3",...t}),h4:t=>(0,C.jsx)(it,{as:"h4",...t}),h5:t=>(0,C.jsx)(it,{as:"h5",...t}),h6:t=>(0,C.jsx)(it,{as:"h6",...t}),admonition:lt.A,mermaid:function(t){return(0,C.jsx)(ct.A,{fallback:t=>(0,C.jsx)(ht.MN,{...t}),children:(0,C.jsx)(en,{...t})})}}},7227:(t,e,r)=>{"use strict";r.d(e,{A:()=>o});r(96540);var n=r(34164);const i={tabItem:"tabItem_Ymn6"};var a=r(74848);function o(t){let{children:e,hidden:r,className:o}=t;return(0,a.jsx)("div",{role:"tabpanel",className:(0,n.A)(i.tabItem,o),hidden:r,children:e})}},49489:(t,e,r)=>{"use strict";r.d(e,{A:()=>w});var n=r(96540),i=r(34164),a=r(24245),o=r(56347),s=r(36494),l=r(62814),c=r(45167),h=r(69900);function u(t){return n.Children.toArray(t).filter((t=>"\n"!==t)).map((t=>{if(!t||(0,n.isValidElement)(t)&&function(t){const{props:e}=t;return!!e&&"object"==typeof e&&"value"in e}(t))return t;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof t.type?t.type:t.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function d(t){const{values:e,children:r}=t;return(0,n.useMemo)((()=>{const t=e??function(t){return u(t).map((t=>{let{props:{value:e,label:r,attributes:n,default:i}}=t;return{value:e,label:r,attributes:n,default:i}}))}(r);return function(t){const e=(0,c.XI)(t,((t,e)=>t.value===e.value));if(e.length>0)throw new Error(`Docusaurus error: Duplicate values "${e.map((t=>t.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(t),t}),[e,r])}function p(t){let{value:e,tabValues:r}=t;return r.some((t=>t.value===e))}function f(t){let{queryString:e=!1,groupId:r}=t;const i=(0,o.W6)(),a=function(t){let{queryString:e=!1,groupId:r}=t;if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!r)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return r??null}({queryString:e,groupId:r});return[(0,l.aZ)(a),(0,n.useCallback)((t=>{if(!a)return;const e=new URLSearchParams(i.location.search);e.set(a,t),i.replace({...i.location,search:e.toString()})}),[a,i])]}function g(t){const{defaultValue:e,queryString:r=!1,groupId:i}=t,a=d(t),[o,l]=(0,n.useState)((()=>function(t){let{defaultValue:e,tabValues:r}=t;if(0===r.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!p({value:e,tabValues:r}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${r.map((t=>t.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}const n=r.find((t=>t.default))??r[0];if(!n)throw new Error("Unexpected error: 0 tabValues");return n.value}({defaultValue:e,tabValues:a}))),[c,u]=f({queryString:r,groupId:i}),[g,m]=function(t){let{groupId:e}=t;const r=function(t){return t?`docusaurus.tab.${t}`:null}(e),[i,a]=(0,h.Dv)(r);return[i,(0,n.useCallback)((t=>{r&&a.set(t)}),[r,a])]}({groupId:i}),y=(()=>{const t=c??g;return p({value:t,tabValues:a})?t:null})();(0,s.A)((()=>{y&&l(y)}),[y]);return{selectedValue:o,selectValue:(0,n.useCallback)((t=>{if(!p({value:t,tabValues:a}))throw new Error(`Can't select invalid tab value=${t}`);l(t),u(t),m(t)}),[u,m,a]),tabValues:a}}var m=r(11062);const y={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var x=r(74848);function b(t){let{className:e,block:r,selectedValue:n,selectValue:o,tabValues:s}=t;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,a.a_)(),h=t=>{const e=t.currentTarget,r=l.indexOf(e),i=s[r].value;i!==n&&(c(e),o(i))},u=t=>{let e=null;switch(t.key){case"Enter":h(t);break;case"ArrowRight":{const r=l.indexOf(t.currentTarget)+1;e=l[r]??l[0];break}case"ArrowLeft":{const r=l.indexOf(t.currentTarget)-1;e=l[r]??l[l.length-1];break}}e?.focus()};return(0,x.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.A)("tabs",{"tabs--block":r},e),children:s.map((t=>{let{value:e,label:r,attributes:a}=t;return(0,x.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:t=>l.push(t),onKeyDown:u,onClick:h,...a,className:(0,i.A)("tabs__item",y.tabItem,a?.className,{"tabs__item--active":n===e}),children:r??e},e)}))})}function k(t){let{lazy:e,children:r,selectedValue:a}=t;const o=(Array.isArray(r)?r:[r]).filter(Boolean);if(e){const t=o.find((t=>t.props.value===a));return t?(0,n.cloneElement)(t,{className:(0,i.A)("margin-top--md",t.props.className)}):null}return(0,x.jsx)("div",{className:"margin-top--md",children:o.map(((t,e)=>(0,n.cloneElement)(t,{key:e,hidden:t.props.value!==a})))})}function C(t){const e=g(t);return(0,x.jsxs)("div",{className:(0,i.A)("tabs-container",y.tabList),children:[(0,x.jsx)(b,{...e,...t}),(0,x.jsx)(k,{...e,...t})]})}function w(t){const e=(0,m.A)();return(0,x.jsx)(C,{...t,children:u(t.children)},String(e))}},74353:function(t){t.exports=function(){"use strict";var t=1e3,e=6e4,r=36e5,n="millisecond",i="second",a="minute",o="hour",s="day",l="week",c="month",h="quarter",u="year",d="date",p="Invalid Date",f=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,g=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,m={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],r=t%100;return"["+t+(e[(r-20)%10]||e[r]||e[0])+"]"}},y=function(t,e,r){var n=String(t);return!n||n.length>=e?t:""+Array(e+1-n.length).join(r)+t},x={s:y,z:function(t){var e=-t.utcOffset(),r=Math.abs(e),n=Math.floor(r/60),i=r%60;return(e<=0?"+":"-")+y(n,2,"0")+":"+y(i,2,"0")},m:function t(e,r){if(e.date()<r.date())return-t(r,e);var n=12*(r.year()-e.year())+(r.month()-e.month()),i=e.clone().add(n,c),a=r-i<0,o=e.clone().add(n+(a?-1:1),c);return+(-(n+(r-i)/(a?i-o:o-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return{M:c,y:u,w:l,d:s,D:d,h:o,m:a,s:i,ms:n,Q:h}[t]||String(t||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},b="en",k={};k[b]=m;var C="$isDayjsObject",w=function(t){return t instanceof A||!(!t||!t[C])},_=function t(e,r,n){var i;if(!e)return b;if("string"==typeof e){var a=e.toLowerCase();k[a]&&(i=a),r&&(k[a]=r,i=a);var o=e.split("-");if(!i&&o.length>1)return t(o[0])}else{var s=e.name;k[s]=e,i=s}return!n&&i&&(b=i),i||!n&&b},v=function(t,e){if(w(t))return t.clone();var r="object"==typeof e?e:{};return r.date=t,r.args=arguments,new A(r)},S=x;S.l=_,S.i=w,S.w=function(t,e){return v(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var A=function(){function m(t){this.$L=_(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[C]=!0}var y=m.prototype;return y.parse=function(t){this.$d=function(t){var e=t.date,r=t.utc;if(null===e)return new Date(NaN);if(S.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var n=e.match(f);if(n){var i=n[2]-1||0,a=(n[7]||"0").substring(0,3);return r?new Date(Date.UTC(n[1],i,n[3]||1,n[4]||0,n[5]||0,n[6]||0,a)):new Date(n[1],i,n[3]||1,n[4]||0,n[5]||0,n[6]||0,a)}}return new Date(e)}(t),this.init()},y.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},y.$utils=function(){return S},y.isValid=function(){return!(this.$d.toString()===p)},y.isSame=function(t,e){var r=v(t);return this.startOf(e)<=r&&r<=this.endOf(e)},y.isAfter=function(t,e){return v(t)<this.startOf(e)},y.isBefore=function(t,e){return this.endOf(e)<v(t)},y.$g=function(t,e,r){return S.u(t)?this[e]:this.set(r,t)},y.unix=function(){return Math.floor(this.valueOf()/1e3)},y.valueOf=function(){return this.$d.getTime()},y.startOf=function(t,e){var r=this,n=!!S.u(e)||e,h=S.p(t),p=function(t,e){var i=S.w(r.$u?Date.UTC(r.$y,e,t):new Date(r.$y,e,t),r);return n?i:i.endOf(s)},f=function(t,e){return S.w(r.toDate()[t].apply(r.toDate("s"),(n?[0,0,0,0]:[23,59,59,999]).slice(e)),r)},g=this.$W,m=this.$M,y=this.$D,x="set"+(this.$u?"UTC":"");switch(h){case u:return n?p(1,0):p(31,11);case c:return n?p(1,m):p(0,m+1);case l:var b=this.$locale().weekStart||0,k=(g<b?g+7:g)-b;return p(n?y-k:y+(6-k),m);case s:case d:return f(x+"Hours",0);case o:return f(x+"Minutes",1);case a:return f(x+"Seconds",2);case i:return f(x+"Milliseconds",3);default:return this.clone()}},y.endOf=function(t){return this.startOf(t,!1)},y.$set=function(t,e){var r,l=S.p(t),h="set"+(this.$u?"UTC":""),p=(r={},r[s]=h+"Date",r[d]=h+"Date",r[c]=h+"Month",r[u]=h+"FullYear",r[o]=h+"Hours",r[a]=h+"Minutes",r[i]=h+"Seconds",r[n]=h+"Milliseconds",r)[l],f=l===s?this.$D+(e-this.$W):e;if(l===c||l===u){var g=this.clone().set(d,1);g.$d[p](f),g.init(),this.$d=g.set(d,Math.min(this.$D,g.daysInMonth())).$d}else p&&this.$d[p](f);return this.init(),this},y.set=function(t,e){return this.clone().$set(t,e)},y.get=function(t){return this[S.p(t)]()},y.add=function(n,h){var d,p=this;n=Number(n);var f=S.p(h),g=function(t){var e=v(p);return S.w(e.date(e.date()+Math.round(t*n)),p)};if(f===c)return this.set(c,this.$M+n);if(f===u)return this.set(u,this.$y+n);if(f===s)return g(1);if(f===l)return g(7);var m=(d={},d[a]=e,d[o]=r,d[i]=t,d)[f]||1,y=this.$d.getTime()+n*m;return S.w(y,this)},y.subtract=function(t,e){return this.add(-1*t,e)},y.format=function(t){var e=this,r=this.$locale();if(!this.isValid())return r.invalidDate||p;var n=t||"YYYY-MM-DDTHH:mm:ssZ",i=S.z(this),a=this.$H,o=this.$m,s=this.$M,l=r.weekdays,c=r.months,h=r.meridiem,u=function(t,r,i,a){return t&&(t[r]||t(e,n))||i[r].slice(0,a)},d=function(t){return S.s(a%12||12,t,"0")},f=h||function(t,e,r){var n=t<12?"AM":"PM";return r?n.toLowerCase():n};return n.replace(g,(function(t,n){return n||function(t){switch(t){case"YY":return String(e.$y).slice(-2);case"YYYY":return S.s(e.$y,4,"0");case"M":return s+1;case"MM":return S.s(s+1,2,"0");case"MMM":return u(r.monthsShort,s,c,3);case"MMMM":return u(c,s);case"D":return e.$D;case"DD":return S.s(e.$D,2,"0");case"d":return String(e.$W);case"dd":return u(r.weekdaysMin,e.$W,l,2);case"ddd":return u(r.weekdaysShort,e.$W,l,3);case"dddd":return l[e.$W];case"H":return String(a);case"HH":return S.s(a,2,"0");case"h":return d(1);case"hh":return d(2);case"a":return f(a,o,!0);case"A":return f(a,o,!1);case"m":return String(o);case"mm":return S.s(o,2,"0");case"s":return String(e.$s);case"ss":return S.s(e.$s,2,"0");case"SSS":return S.s(e.$ms,3,"0");case"Z":return i}return null}(t)||i.replace(":","")}))},y.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},y.diff=function(n,d,p){var f,g=this,m=S.p(d),y=v(n),x=(y.utcOffset()-this.utcOffset())*e,b=this-y,k=function(){return S.m(g,y)};switch(m){case u:f=k()/12;break;case c:f=k();break;case h:f=k()/3;break;case l:f=(b-x)/6048e5;break;case s:f=(b-x)/864e5;break;case o:f=b/r;break;case a:f=b/e;break;case i:f=b/t;break;default:f=b}return p?f:S.a(f)},y.daysInMonth=function(){return this.endOf(c).$D},y.$locale=function(){return k[this.$L]},y.locale=function(t,e){if(!t)return this.$L;var r=this.clone(),n=_(t,e,!0);return n&&(r.$L=n),r},y.clone=function(){return S.w(this.$d,this)},y.toDate=function(){return new Date(this.valueOf())},y.toJSON=function(){return this.isValid()?this.toISOString():null},y.toISOString=function(){return this.$d.toISOString()},y.toString=function(){return this.$d.toUTCString()},m}(),T=A.prototype;return v.prototype=T,[["$ms",n],["$s",i],["$m",a],["$H",o],["$W",s],["$M",c],["$y",u],["$D",d]].forEach((function(t){T[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),v.extend=function(t,e){return t.$i||(t(e,A,v),t.$i=!0),v},v.locale=_,v.isDayjs=w,v.unix=function(t){return v(1e3*t)},v.en=k[b],v.Ls=k,v.p={},v}()},18426:(t,e)=>{function r(t){let e,r=[];for(let n of t.split(",").map((t=>t.trim())))if(/^-?\d+$/.test(n))r.push(parseInt(n,10));else if(e=n.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[t,n,i,a]=e;if(n&&a){n=parseInt(n),a=parseInt(a);const t=n<a?1:-1;"-"!==i&&".."!==i&&"\u2025"!==i||(a+=t);for(let e=n;e!==a;e+=t)r.push(e)}}return r}e.default=r,t.exports=r},29893:(t,e,r)=>{"use strict";function n(t,e,r){if(t&&t.length){const[n,i]=e,a=Math.PI/180*r,o=Math.cos(a),s=Math.sin(a);for(const e of t){const[t,r]=e;e[0]=(t-n)*o-(r-i)*s+n,e[1]=(t-n)*s+(r-i)*o+i}}}function i(t,e){return t[0]===e[0]&&t[1]===e[1]}function a(t,e,r,a=1){const o=r,s=Math.max(e,.1),l=t[0]&&t[0][0]&&"number"==typeof t[0][0]?[t]:t,c=[0,0];if(o)for(const i of l)n(i,c,o);const h=function(t,e,r){const n=[];for(const h of t){const t=[...h];i(t[0],t[t.length-1])||t.push([t[0][0],t[0][1]]),t.length>2&&n.push(t)}const a=[];e=Math.max(e,.1);const o=[];for(const i of n)for(let t=0;t<i.length-1;t++){const e=i[t],r=i[t+1];if(e[1]!==r[1]){const t=Math.min(e[1],r[1]);o.push({ymin:t,ymax:Math.max(e[1],r[1]),x:t===e[1]?e[0]:r[0],islope:(r[0]-e[0])/(r[1]-e[1])})}}if(o.sort(((t,e)=>t.ymin<e.ymin?-1:t.ymin>e.ymin?1:t.x<e.x?-1:t.x>e.x?1:t.ymax===e.ymax?0:(t.ymax-e.ymax)/Math.abs(t.ymax-e.ymax))),!o.length)return a;let s=[],l=o[0].ymin,c=0;for(;s.length||o.length;){if(o.length){let t=-1;for(let e=0;e<o.length&&!(o[e].ymin>l);e++)t=e;o.splice(0,t+1).forEach((t=>{s.push({s:l,edge:t})}))}if(s=s.filter((t=>!(t.edge.ymax<=l))),s.sort(((t,e)=>t.edge.x===e.edge.x?0:(t.edge.x-e.edge.x)/Math.abs(t.edge.x-e.edge.x))),(1!==r||c%e==0)&&s.length>1)for(let t=0;t<s.length;t+=2){const e=t+1;if(e>=s.length)break;const r=s[t].edge,n=s[e].edge;a.push([[Math.round(r.x),l],[Math.round(n.x),l]])}l+=r,s.forEach((t=>{t.edge.x=t.edge.x+r*t.edge.islope})),c++}return a}(l,s,a);if(o){for(const t of l)n(t,c,-o);!function(t,e,r){const i=[];t.forEach((t=>i.push(...t))),n(i,e,r)}(h,c,-o)}return h}function o(t,e){var r;const n=e.hachureAngle+90;let i=e.hachureGap;i<0&&(i=4*e.strokeWidth),i=Math.round(Math.max(i,.1));let o=1;return e.roughness>=1&&((null===(r=e.randomizer)||void 0===r?void 0:r.next())||Math.random())>.7&&(o=i),a(t,i,n,o||1)}r.d(e,{A:()=>it});class s{constructor(t){this.helper=t}fillPolygons(t,e){return this._fillPolygons(t,e)}_fillPolygons(t,e){const r=o(t,e);return{type:"fillSketch",ops:this.renderLines(r,e)}}renderLines(t,e){const r=[];for(const n of t)r.push(...this.helper.doubleLineOps(n[0][0],n[0][1],n[1][0],n[1][1],e));return r}}function l(t){const e=t[0],r=t[1];return Math.sqrt(Math.pow(e[0]-r[0],2)+Math.pow(e[1]-r[1],2))}class c extends s{fillPolygons(t,e){let r=e.hachureGap;r<0&&(r=4*e.strokeWidth),r=Math.max(r,.1);const n=o(t,Object.assign({},e,{hachureGap:r})),i=Math.PI/180*e.hachureAngle,a=[],s=.5*r*Math.cos(i),c=.5*r*Math.sin(i);for(const[o,h]of n)l([o,h])&&a.push([[o[0]-s,o[1]+c],[...h]],[[o[0]+s,o[1]-c],[...h]]);return{type:"fillSketch",ops:this.renderLines(a,e)}}}class h extends s{fillPolygons(t,e){const r=this._fillPolygons(t,e),n=Object.assign({},e,{hachureAngle:e.hachureAngle+90}),i=this._fillPolygons(t,n);return r.ops=r.ops.concat(i.ops),r}}class u{constructor(t){this.helper=t}fillPolygons(t,e){const r=o(t,e=Object.assign({},e,{hachureAngle:0}));return this.dotsOnLines(r,e)}dotsOnLines(t,e){const r=[];let n=e.hachureGap;n<0&&(n=4*e.strokeWidth),n=Math.max(n,.1);let i=e.fillWeight;i<0&&(i=e.strokeWidth/2);const a=n/4;for(const o of t){const t=l(o),s=t/n,c=Math.ceil(s)-1,h=t-c*n,u=(o[0][0]+o[1][0])/2-n/4,d=Math.min(o[0][1],o[1][1]);for(let o=0;o<c;o++){const t=d+h+o*n,s=u-a+2*Math.random()*a,l=t-a+2*Math.random()*a,c=this.helper.ellipse(s,l,i,i,e);r.push(...c.ops)}}return{type:"fillSketch",ops:r}}}class d{constructor(t){this.helper=t}fillPolygons(t,e){const r=o(t,e);return{type:"fillSketch",ops:this.dashedLine(r,e)}}dashedLine(t,e){const r=e.dashOffset<0?e.hachureGap<0?4*e.strokeWidth:e.hachureGap:e.dashOffset,n=e.dashGap<0?e.hachureGap<0?4*e.strokeWidth:e.hachureGap:e.dashGap,i=[];return t.forEach((t=>{const a=l(t),o=Math.floor(a/(r+n)),s=(a+n-o*(r+n))/2;let c=t[0],h=t[1];c[0]>h[0]&&(c=t[1],h=t[0]);const u=Math.atan((h[1]-c[1])/(h[0]-c[0]));for(let l=0;l<o;l++){const t=l*(r+n),a=t+r,o=[c[0]+t*Math.cos(u)+s*Math.cos(u),c[1]+t*Math.sin(u)+s*Math.sin(u)],h=[c[0]+a*Math.cos(u)+s*Math.cos(u),c[1]+a*Math.sin(u)+s*Math.sin(u)];i.push(...this.helper.doubleLineOps(o[0],o[1],h[0],h[1],e))}})),i}}class p{constructor(t){this.helper=t}fillPolygons(t,e){const r=e.hachureGap<0?4*e.strokeWidth:e.hachureGap,n=e.zigzagOffset<0?r:e.zigzagOffset,i=o(t,e=Object.assign({},e,{hachureGap:r+n}));return{type:"fillSketch",ops:this.zigzagLines(i,n,e)}}zigzagLines(t,e,r){const n=[];return t.forEach((t=>{const i=l(t),a=Math.round(i/(2*e));let o=t[0],s=t[1];o[0]>s[0]&&(o=t[1],s=t[0]);const c=Math.atan((s[1]-o[1])/(s[0]-o[0]));for(let l=0;l<a;l++){const t=2*l*e,i=2*(l+1)*e,a=Math.sqrt(2*Math.pow(e,2)),s=[o[0]+t*Math.cos(c),o[1]+t*Math.sin(c)],h=[o[0]+i*Math.cos(c),o[1]+i*Math.sin(c)],u=[s[0]+a*Math.cos(c+Math.PI/4),s[1]+a*Math.sin(c+Math.PI/4)];n.push(...this.helper.doubleLineOps(s[0],s[1],u[0],u[1],r),...this.helper.doubleLineOps(u[0],u[1],h[0],h[1],r))}})),n}}const f={};class g{constructor(t){this.seed=t}next(){return this.seed?(2**31-1&(this.seed=Math.imul(48271,this.seed)))/2**31:Math.random()}}const m={A:7,a:7,C:6,c:6,H:1,h:1,L:2,l:2,M:2,m:2,Q:4,q:4,S:4,s:4,T:2,t:2,V:1,v:1,Z:0,z:0};function y(t,e){return t.type===e}function x(t){const e=[],r=function(t){const e=new Array;for(;""!==t;)if(t.match(/^([ \t\r\n,]+)/))t=t.substr(RegExp.$1.length);else if(t.match(/^([aAcChHlLmMqQsStTvVzZ])/))e[e.length]={type:0,text:RegExp.$1},t=t.substr(RegExp.$1.length);else{if(!t.match(/^(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)/))return[];e[e.length]={type:1,text:`${parseFloat(RegExp.$1)}`},t=t.substr(RegExp.$1.length)}return e[e.length]={type:2,text:""},e}(t);let n="BOD",i=0,a=r[i];for(;!y(a,2);){let o=0;const s=[];if("BOD"===n){if("M"!==a.text&&"m"!==a.text)return x("M0,0"+t);i++,o=m[a.text],n=a.text}else y(a,1)?o=m[n]:(i++,o=m[a.text],n=a.text);if(!(i+o<r.length))throw new Error("Path data ended short");for(let t=i;t<i+o;t++){const e=r[t];if(!y(e,1))throw new Error("Param not a number: "+n+","+e.text);s[s.length]=+e.text}if("number"!=typeof m[n])throw new Error("Bad segment: "+n);{const t={key:n,data:s};e.push(t),i+=o,a=r[i],"M"===n&&(n="L"),"m"===n&&(n="l")}}return e}function b(t){let e=0,r=0,n=0,i=0;const a=[];for(const{key:o,data:s}of t)switch(o){case"M":a.push({key:"M",data:[...s]}),[e,r]=s,[n,i]=s;break;case"m":e+=s[0],r+=s[1],a.push({key:"M",data:[e,r]}),n=e,i=r;break;case"L":a.push({key:"L",data:[...s]}),[e,r]=s;break;case"l":e+=s[0],r+=s[1],a.push({key:"L",data:[e,r]});break;case"C":a.push({key:"C",data:[...s]}),e=s[4],r=s[5];break;case"c":{const t=s.map(((t,n)=>n%2?t+r:t+e));a.push({key:"C",data:t}),e=t[4],r=t[5];break}case"Q":a.push({key:"Q",data:[...s]}),e=s[2],r=s[3];break;case"q":{const t=s.map(((t,n)=>n%2?t+r:t+e));a.push({key:"Q",data:t}),e=t[2],r=t[3];break}case"A":a.push({key:"A",data:[...s]}),e=s[5],r=s[6];break;case"a":e+=s[5],r+=s[6],a.push({key:"A",data:[s[0],s[1],s[2],s[3],s[4],e,r]});break;case"H":a.push({key:"H",data:[...s]}),e=s[0];break;case"h":e+=s[0],a.push({key:"H",data:[e]});break;case"V":a.push({key:"V",data:[...s]}),r=s[0];break;case"v":r+=s[0],a.push({key:"V",data:[r]});break;case"S":a.push({key:"S",data:[...s]}),e=s[2],r=s[3];break;case"s":{const t=s.map(((t,n)=>n%2?t+r:t+e));a.push({key:"S",data:t}),e=t[2],r=t[3];break}case"T":a.push({key:"T",data:[...s]}),e=s[0],r=s[1];break;case"t":e+=s[0],r+=s[1],a.push({key:"T",data:[e,r]});break;case"Z":case"z":a.push({key:"Z",data:[]}),e=n,r=i}return a}function k(t){const e=[];let r="",n=0,i=0,a=0,o=0,s=0,l=0;for(const{key:c,data:h}of t){switch(c){case"M":e.push({key:"M",data:[...h]}),[n,i]=h,[a,o]=h;break;case"C":e.push({key:"C",data:[...h]}),n=h[4],i=h[5],s=h[2],l=h[3];break;case"L":e.push({key:"L",data:[...h]}),[n,i]=h;break;case"H":n=h[0],e.push({key:"L",data:[n,i]});break;case"V":i=h[0],e.push({key:"L",data:[n,i]});break;case"S":{let t=0,a=0;"C"===r||"S"===r?(t=n+(n-s),a=i+(i-l)):(t=n,a=i),e.push({key:"C",data:[t,a,...h]}),s=h[0],l=h[1],n=h[2],i=h[3];break}case"T":{const[t,a]=h;let o=0,c=0;"Q"===r||"T"===r?(o=n+(n-s),c=i+(i-l)):(o=n,c=i);const u=n+2*(o-n)/3,d=i+2*(c-i)/3,p=t+2*(o-t)/3,f=a+2*(c-a)/3;e.push({key:"C",data:[u,d,p,f,t,a]}),s=o,l=c,n=t,i=a;break}case"Q":{const[t,r,a,o]=h,c=n+2*(t-n)/3,u=i+2*(r-i)/3,d=a+2*(t-a)/3,p=o+2*(r-o)/3;e.push({key:"C",data:[c,u,d,p,a,o]}),s=t,l=r,n=a,i=o;break}case"A":{const t=Math.abs(h[0]),r=Math.abs(h[1]),a=h[2],o=h[3],s=h[4],l=h[5],c=h[6];0===t||0===r?(e.push({key:"C",data:[n,i,l,c,l,c]}),n=l,i=c):n===l&&i===c||(w(n,i,l,c,t,r,a,o,s).forEach((function(t){e.push({key:"C",data:t})})),n=l,i=c);break}case"Z":e.push({key:"Z",data:[]}),n=a,i=o}r=c}return e}function C(t,e,r){return[t*Math.cos(r)-e*Math.sin(r),t*Math.sin(r)+e*Math.cos(r)]}function w(t,e,r,n,i,a,o,s,l,c){const h=(u=o,Math.PI*u/180);var u;let d=[],p=0,f=0,g=0,m=0;if(c)[p,f,g,m]=c;else{[t,e]=C(t,e,-h),[r,n]=C(r,n,-h);const o=(t-r)/2,c=(e-n)/2;let u=o*o/(i*i)+c*c/(a*a);u>1&&(u=Math.sqrt(u),i*=u,a*=u);const d=i*i,y=a*a,x=d*y-d*c*c-y*o*o,b=d*c*c+y*o*o,k=(s===l?-1:1)*Math.sqrt(Math.abs(x/b));g=k*i*c/a+(t+r)/2,m=k*-a*o/i+(e+n)/2,p=Math.asin(parseFloat(((e-m)/a).toFixed(9))),f=Math.asin(parseFloat(((n-m)/a).toFixed(9))),t<g&&(p=Math.PI-p),r<g&&(f=Math.PI-f),p<0&&(p=2*Math.PI+p),f<0&&(f=2*Math.PI+f),l&&p>f&&(p-=2*Math.PI),!l&&f>p&&(f-=2*Math.PI)}let y=f-p;if(Math.abs(y)>120*Math.PI/180){const t=f,e=r,s=n;f=l&&f>p?p+120*Math.PI/180*1:p+120*Math.PI/180*-1,d=w(r=g+i*Math.cos(f),n=m+a*Math.sin(f),e,s,i,a,o,0,l,[f,t,g,m])}y=f-p;const x=Math.cos(p),b=Math.sin(p),k=Math.cos(f),_=Math.sin(f),v=Math.tan(y/4),S=4/3*i*v,A=4/3*a*v,T=[t,e],M=[t+S*b,e-A*x],B=[r+S*_,n-A*k],L=[r,n];if(M[0]=2*T[0]-M[0],M[1]=2*T[1]-M[1],c)return[M,B,L].concat(d);{d=[M,B,L].concat(d);const t=[];for(let e=0;e<d.length;e+=3){const r=C(d[e][0],d[e][1],h),n=C(d[e+1][0],d[e+1][1],h),i=C(d[e+2][0],d[e+2][1],h);t.push([r[0],r[1],n[0],n[1],i[0],i[1]])}return t}}const _={randOffset:function(t,e){return j(t,e)},randOffsetWithRange:function(t,e,r){return D(t,e,r)},ellipse:function(t,e,r,n,i){return M(t,e,i,T(r,n,i)).opset},doubleLineOps:function(t,e,r,n,i){return I(t,e,r,n,i,!0)}};function v(t,e,r,n,i){return{type:"path",ops:I(t,e,r,n,i)}}function S(t,e,r){const n=(t||[]).length;if(n>2){const i=[];for(let e=0;e<n-1;e++)i.push(...I(t[e][0],t[e][1],t[e+1][0],t[e+1][1],r));return e&&i.push(...I(t[n-1][0],t[n-1][1],t[0][0],t[0][1],r)),{type:"path",ops:i}}return 2===n?v(t[0][0],t[0][1],t[1][0],t[1][1],r):{type:"path",ops:[]}}function A(t,e){if(t.length){const r="number"==typeof t[0][0]?[t]:t,n=R(r[0],1*(1+.2*e.roughness),e),i=e.disableMultiStroke?[]:R(r[0],1.5*(1+.22*e.roughness),E(e));for(let t=1;t<r.length;t++){const a=r[t];if(a.length){const t=R(a,1*(1+.2*e.roughness),e),r=e.disableMultiStroke?[]:R(a,1.5*(1+.22*e.roughness),E(e));for(const e of t)"move"!==e.op&&n.push(e);for(const e of r)"move"!==e.op&&i.push(e)}}return{type:"path",ops:n.concat(i)}}return{type:"path",ops:[]}}function T(t,e,r){const n=Math.sqrt(2*Math.PI*Math.sqrt((Math.pow(t/2,2)+Math.pow(e/2,2))/2)),i=Math.ceil(Math.max(r.curveStepCount,r.curveStepCount/Math.sqrt(200)*n)),a=2*Math.PI/i;let o=Math.abs(t/2),s=Math.abs(e/2);const l=1-r.curveFitting;return o+=j(o*l,r),s+=j(s*l,r),{increment:a,rx:o,ry:s}}function M(t,e,r,n){const[i,a]=z(n.increment,t,e,n.rx,n.ry,1,n.increment*D(.1,D(.4,1,r),r),r);let o=P(i,null,r);if(!r.disableMultiStroke&&0!==r.roughness){const[i]=z(n.increment,t,e,n.rx,n.ry,1.5,0,r),a=P(i,null,r);o=o.concat(a)}return{estimatedPoints:a,opset:{type:"path",ops:o}}}function B(t,e,r,n,i,a,o,s,l){const c=t,h=e;let u=Math.abs(r/2),d=Math.abs(n/2);u+=j(.01*u,l),d+=j(.01*d,l);let p=i,f=a;for(;p<0;)p+=2*Math.PI,f+=2*Math.PI;f-p>2*Math.PI&&(p=0,f=2*Math.PI);const g=2*Math.PI/l.curveStepCount,m=Math.min(g/2,(f-p)/2),y=K(m,c,h,u,d,p,f,1,l);if(!l.disableMultiStroke){const t=K(m,c,h,u,d,p,f,1.5,l);y.push(...t)}return o&&(s?y.push(...I(c,h,c+u*Math.cos(p),h+d*Math.sin(p),l),...I(c,h,c+u*Math.cos(f),h+d*Math.sin(f),l)):y.push({op:"lineTo",data:[c,h]},{op:"lineTo",data:[c+u*Math.cos(p),h+d*Math.sin(p)]})),{type:"path",ops:y}}function L(t,e){const r=k(b(x(t))),n=[];let i=[0,0],a=[0,0];for(const{key:o,data:s}of r)switch(o){case"M":a=[s[0],s[1]],i=[s[0],s[1]];break;case"L":n.push(...I(a[0],a[1],s[0],s[1],e)),a=[s[0],s[1]];break;case"C":{const[t,r,i,o,l,c]=s;n.push(...q(t,r,i,o,l,c,a,e)),a=[l,c];break}case"Z":n.push(...I(a[0],a[1],i[0],i[1],e)),a=[i[0],i[1]]}return{type:"path",ops:n}}function F(t,e){const r=[];for(const n of t)if(n.length){const t=e.maxRandomnessOffset||0,i=n.length;if(i>2){r.push({op:"move",data:[n[0][0]+j(t,e),n[0][1]+j(t,e)]});for(let a=1;a<i;a++)r.push({op:"lineTo",data:[n[a][0]+j(t,e),n[a][1]+j(t,e)]})}}return{type:"fillPath",ops:r}}function $(t,e){return function(t,e){let r=t.fillStyle||"hachure";if(!f[r])switch(r){case"zigzag":f[r]||(f[r]=new c(e));break;case"cross-hatch":f[r]||(f[r]=new h(e));break;case"dots":f[r]||(f[r]=new u(e));break;case"dashed":f[r]||(f[r]=new d(e));break;case"zigzag-line":f[r]||(f[r]=new p(e));break;default:r="hachure",f[r]||(f[r]=new s(e))}return f[r]}(e,_).fillPolygons(t,e)}function E(t){const e=Object.assign({},t);return e.randomizer=void 0,t.seed&&(e.seed=t.seed+1),e}function N(t){return t.randomizer||(t.randomizer=new g(t.seed||0)),t.randomizer.next()}function D(t,e,r,n=1){return r.roughness*n*(N(r)*(e-t)+t)}function j(t,e,r=1){return D(-t,t,e,r)}function I(t,e,r,n,i,a=!1){const o=a?i.disableMultiStrokeFill:i.disableMultiStroke,s=O(t,e,r,n,i,!0,!1);if(o)return s;const l=O(t,e,r,n,i,!0,!0);return s.concat(l)}function O(t,e,r,n,i,a,o){const s=Math.pow(t-r,2)+Math.pow(e-n,2),l=Math.sqrt(s);let c=1;c=l<200?1:l>500?.4:-.0016668*l+1.233334;let h=i.maxRandomnessOffset||0;h*h*100>s&&(h=l/10);const u=h/2,d=.2+.2*N(i);let p=i.bowing*i.maxRandomnessOffset*(n-e)/200,f=i.bowing*i.maxRandomnessOffset*(t-r)/200;p=j(p,i,c),f=j(f,i,c);const g=[],m=()=>j(u,i,c),y=()=>j(h,i,c),x=i.preserveVertices;return a&&(o?g.push({op:"move",data:[t+(x?0:m()),e+(x?0:m())]}):g.push({op:"move",data:[t+(x?0:j(h,i,c)),e+(x?0:j(h,i,c))]})),o?g.push({op:"bcurveTo",data:[p+t+(r-t)*d+m(),f+e+(n-e)*d+m(),p+t+2*(r-t)*d+m(),f+e+2*(n-e)*d+m(),r+(x?0:m()),n+(x?0:m())]}):g.push({op:"bcurveTo",data:[p+t+(r-t)*d+y(),f+e+(n-e)*d+y(),p+t+2*(r-t)*d+y(),f+e+2*(n-e)*d+y(),r+(x?0:y()),n+(x?0:y())]}),g}function R(t,e,r){if(!t.length)return[];const n=[];n.push([t[0][0]+j(e,r),t[0][1]+j(e,r)]),n.push([t[0][0]+j(e,r),t[0][1]+j(e,r)]);for(let i=1;i<t.length;i++)n.push([t[i][0]+j(e,r),t[i][1]+j(e,r)]),i===t.length-1&&n.push([t[i][0]+j(e,r),t[i][1]+j(e,r)]);return P(n,null,r)}function P(t,e,r){const n=t.length,i=[];if(n>3){const a=[],o=1-r.curveTightness;i.push({op:"move",data:[t[1][0],t[1][1]]});for(let e=1;e+2<n;e++){const r=t[e];a[0]=[r[0],r[1]],a[1]=[r[0]+(o*t[e+1][0]-o*t[e-1][0])/6,r[1]+(o*t[e+1][1]-o*t[e-1][1])/6],a[2]=[t[e+1][0]+(o*t[e][0]-o*t[e+2][0])/6,t[e+1][1]+(o*t[e][1]-o*t[e+2][1])/6],a[3]=[t[e+1][0],t[e+1][1]],i.push({op:"bcurveTo",data:[a[1][0],a[1][1],a[2][0],a[2][1],a[3][0],a[3][1]]})}if(e&&2===e.length){const t=r.maxRandomnessOffset;i.push({op:"lineTo",data:[e[0]+j(t,r),e[1]+j(t,r)]})}}else 3===n?(i.push({op:"move",data:[t[1][0],t[1][1]]}),i.push({op:"bcurveTo",data:[t[1][0],t[1][1],t[2][0],t[2][1],t[2][0],t[2][1]]})):2===n&&i.push(...O(t[0][0],t[0][1],t[1][0],t[1][1],r,!0,!0));return i}function z(t,e,r,n,i,a,o,s){const l=[],c=[];if(0===s.roughness){t/=4,c.push([e+n*Math.cos(-t),r+i*Math.sin(-t)]);for(let a=0;a<=2*Math.PI;a+=t){const t=[e+n*Math.cos(a),r+i*Math.sin(a)];l.push(t),c.push(t)}c.push([e+n*Math.cos(0),r+i*Math.sin(0)]),c.push([e+n*Math.cos(t),r+i*Math.sin(t)])}else{const h=j(.5,s)-Math.PI/2;c.push([j(a,s)+e+.9*n*Math.cos(h-t),j(a,s)+r+.9*i*Math.sin(h-t)]);const u=2*Math.PI+h-.01;for(let o=h;o<u;o+=t){const t=[j(a,s)+e+n*Math.cos(o),j(a,s)+r+i*Math.sin(o)];l.push(t),c.push(t)}c.push([j(a,s)+e+n*Math.cos(h+2*Math.PI+.5*o),j(a,s)+r+i*Math.sin(h+2*Math.PI+.5*o)]),c.push([j(a,s)+e+.98*n*Math.cos(h+o),j(a,s)+r+.98*i*Math.sin(h+o)]),c.push([j(a,s)+e+.9*n*Math.cos(h+.5*o),j(a,s)+r+.9*i*Math.sin(h+.5*o)])}return[c,l]}function K(t,e,r,n,i,a,o,s,l){const c=a+j(.1,l),h=[];h.push([j(s,l)+e+.9*n*Math.cos(c-t),j(s,l)+r+.9*i*Math.sin(c-t)]);for(let u=c;u<=o;u+=t)h.push([j(s,l)+e+n*Math.cos(u),j(s,l)+r+i*Math.sin(u)]);return h.push([e+n*Math.cos(o),r+i*Math.sin(o)]),h.push([e+n*Math.cos(o),r+i*Math.sin(o)]),P(h,null,l)}function q(t,e,r,n,i,a,o,s){const l=[],c=[s.maxRandomnessOffset||1,(s.maxRandomnessOffset||1)+.3];let h=[0,0];const u=s.disableMultiStroke?1:2,d=s.preserveVertices;for(let p=0;p<u;p++)0===p?l.push({op:"move",data:[o[0],o[1]]}):l.push({op:"move",data:[o[0]+(d?0:j(c[0],s)),o[1]+(d?0:j(c[0],s))]}),h=d?[i,a]:[i+j(c[p],s),a+j(c[p],s)],l.push({op:"bcurveTo",data:[t+j(c[p],s),e+j(c[p],s),r+j(c[p],s),n+j(c[p],s),h[0],h[1]]});return l}function W(t){return[...t]}function H(t,e=0){const r=t.length;if(r<3)throw new Error("A curve must have at least three points.");const n=[];if(3===r)n.push(W(t[0]),W(t[1]),W(t[2]),W(t[2]));else{const r=[];r.push(t[0],t[0]);for(let e=1;e<t.length;e++)r.push(t[e]),e===t.length-1&&r.push(t[e]);const i=[],a=1-e;n.push(W(r[0]));for(let t=1;t+2<r.length;t++){const e=r[t];i[0]=[e[0],e[1]],i[1]=[e[0]+(a*r[t+1][0]-a*r[t-1][0])/6,e[1]+(a*r[t+1][1]-a*r[t-1][1])/6],i[2]=[r[t+1][0]+(a*r[t][0]-a*r[t+2][0])/6,r[t+1][1]+(a*r[t][1]-a*r[t+2][1])/6],i[3]=[r[t+1][0],r[t+1][1]],n.push(i[1],i[2],i[3])}}return n}function U(t,e){return Math.pow(t[0]-e[0],2)+Math.pow(t[1]-e[1],2)}function Y(t,e,r){const n=U(e,r);if(0===n)return U(t,e);let i=((t[0]-e[0])*(r[0]-e[0])+(t[1]-e[1])*(r[1]-e[1]))/n;return i=Math.max(0,Math.min(1,i)),U(t,V(e,r,i))}function V(t,e,r){return[t[0]+(e[0]-t[0])*r,t[1]+(e[1]-t[1])*r]}function G(t,e,r,n){const i=n||[];if(function(t,e){const r=t[e+0],n=t[e+1],i=t[e+2],a=t[e+3];let o=3*n[0]-2*r[0]-a[0];o*=o;let s=3*n[1]-2*r[1]-a[1];s*=s;let l=3*i[0]-2*a[0]-r[0];l*=l;let c=3*i[1]-2*a[1]-r[1];return c*=c,o<l&&(o=l),s<c&&(s=c),o+s}(t,e)<r){const r=t[e+0];i.length?(a=i[i.length-1],o=r,Math.sqrt(U(a,o))>1&&i.push(r)):i.push(r),i.push(t[e+3])}else{const n=.5,a=t[e+0],o=t[e+1],s=t[e+2],l=t[e+3],c=V(a,o,n),h=V(o,s,n),u=V(s,l,n),d=V(c,h,n),p=V(h,u,n),f=V(d,p,n);G([a,c,d,f],0,r,i),G([f,p,u,l],0,r,i)}var a,o;return i}function Z(t,e){return X(t,0,t.length,e)}function X(t,e,r,n,i){const a=i||[],o=t[e],s=t[r-1];let l=0,c=1;for(let h=e+1;h<r-1;++h){const e=Y(t[h],o,s);e>l&&(l=e,c=h)}return Math.sqrt(l)>n?(X(t,e,c+1,n,a),X(t,c,r,n,a)):(a.length||a.push(o),a.push(s)),a}function Q(t,e=.15,r){const n=[],i=(t.length-1)/3;for(let a=0;a<i;a++)G(t,3*a,e,n);return r&&r>0?X(n,0,n.length,r):n}const J="none";class tt{constructor(t){this.defaultOptions={maxRandomnessOffset:2,roughness:1,bowing:1,stroke:"#000",strokeWidth:1,curveTightness:0,curveFitting:.95,curveStepCount:9,fillStyle:"hachure",fillWeight:-1,hachureAngle:-41,hachureGap:-1,dashOffset:-1,dashGap:-1,zigzagOffset:-1,seed:0,disableMultiStroke:!1,disableMultiStrokeFill:!1,preserveVertices:!1,fillShapeRoughnessGain:.8},this.config=t||{},this.config.options&&(this.defaultOptions=this._o(this.config.options))}static newSeed(){return Math.floor(Math.random()*2**31)}_o(t){return t?Object.assign({},this.defaultOptions,t):this.defaultOptions}_d(t,e,r){return{shape:t,sets:e||[],options:r||this.defaultOptions}}line(t,e,r,n,i){const a=this._o(i);return this._d("line",[v(t,e,r,n,a)],a)}rectangle(t,e,r,n,i){const a=this._o(i),o=[],s=function(t,e,r,n,i){return function(t,e){return S(t,!0,e)}([[t,e],[t+r,e],[t+r,e+n],[t,e+n]],i)}(t,e,r,n,a);if(a.fill){const i=[[t,e],[t+r,e],[t+r,e+n],[t,e+n]];"solid"===a.fillStyle?o.push(F([i],a)):o.push($([i],a))}return a.stroke!==J&&o.push(s),this._d("rectangle",o,a)}ellipse(t,e,r,n,i){const a=this._o(i),o=[],s=T(r,n,a),l=M(t,e,a,s);if(a.fill)if("solid"===a.fillStyle){const r=M(t,e,a,s).opset;r.type="fillPath",o.push(r)}else o.push($([l.estimatedPoints],a));return a.stroke!==J&&o.push(l.opset),this._d("ellipse",o,a)}circle(t,e,r,n){const i=this.ellipse(t,e,r,r,n);return i.shape="circle",i}linearPath(t,e){const r=this._o(e);return this._d("linearPath",[S(t,!1,r)],r)}arc(t,e,r,n,i,a,o=!1,s){const l=this._o(s),c=[],h=B(t,e,r,n,i,a,o,!0,l);if(o&&l.fill)if("solid"===l.fillStyle){const o=Object.assign({},l);o.disableMultiStroke=!0;const s=B(t,e,r,n,i,a,!0,!1,o);s.type="fillPath",c.push(s)}else c.push(function(t,e,r,n,i,a,o){const s=t,l=e;let c=Math.abs(r/2),h=Math.abs(n/2);c+=j(.01*c,o),h+=j(.01*h,o);let u=i,d=a;for(;u<0;)u+=2*Math.PI,d+=2*Math.PI;d-u>2*Math.PI&&(u=0,d=2*Math.PI);const p=(d-u)/o.curveStepCount,f=[];for(let g=u;g<=d;g+=p)f.push([s+c*Math.cos(g),l+h*Math.sin(g)]);return f.push([s+c*Math.cos(d),l+h*Math.sin(d)]),f.push([s,l]),$([f],o)}(t,e,r,n,i,a,l));return l.stroke!==J&&c.push(h),this._d("arc",c,l)}curve(t,e){const r=this._o(e),n=[],i=A(t,r);if(r.fill&&r.fill!==J)if("solid"===r.fillStyle){const e=A(t,Object.assign(Object.assign({},r),{disableMultiStroke:!0,roughness:r.roughness?r.roughness+r.fillShapeRoughnessGain:0}));n.push({type:"fillPath",ops:this._mergedShape(e.ops)})}else{const e=[],i=t;if(i.length){const t="number"==typeof i[0][0]?[i]:i;for(const n of t)n.length<3?e.push(...n):3===n.length?e.push(...Q(H([n[0],n[0],n[1],n[2]]),10,(1+r.roughness)/2)):e.push(...Q(H(n),10,(1+r.roughness)/2))}e.length&&n.push($([e],r))}return r.stroke!==J&&n.push(i),this._d("curve",n,r)}polygon(t,e){const r=this._o(e),n=[],i=S(t,!0,r);return r.fill&&("solid"===r.fillStyle?n.push(F([t],r)):n.push($([t],r))),r.stroke!==J&&n.push(i),this._d("polygon",n,r)}path(t,e){const r=this._o(e),n=[];if(!t)return this._d("path",n,r);t=(t||"").replace(/\n/g," ").replace(/(-\s)/g,"-").replace("/(ss)/g"," ");const i=r.fill&&"transparent"!==r.fill&&r.fill!==J,a=r.stroke!==J,o=!!(r.simplification&&r.simplification<1),s=function(t,e,r){const n=k(b(x(t))),i=[];let a=[],o=[0,0],s=[];const l=()=>{s.length>=4&&a.push(...Q(s,1)),s=[]},c=()=>{l(),a.length&&(i.push(a),a=[])};for(const{key:u,data:d}of n)switch(u){case"M":c(),o=[d[0],d[1]],a.push(o);break;case"L":l(),a.push([d[0],d[1]]);break;case"C":if(!s.length){const t=a.length?a[a.length-1]:o;s.push([t[0],t[1]])}s.push([d[0],d[1]]),s.push([d[2],d[3]]),s.push([d[4],d[5]]);break;case"Z":l(),a.push([o[0],o[1]])}if(c(),!r)return i;const h=[];for(const u of i){const t=Z(u,r);t.length&&h.push(t)}return h}(t,0,o?4-4*(r.simplification||1):(1+r.roughness)/2),l=L(t,r);if(i)if("solid"===r.fillStyle)if(1===s.length){const e=L(t,Object.assign(Object.assign({},r),{disableMultiStroke:!0,roughness:r.roughness?r.roughness+r.fillShapeRoughnessGain:0}));n.push({type:"fillPath",ops:this._mergedShape(e.ops)})}else n.push(F(s,r));else n.push($(s,r));return a&&(o?s.forEach((t=>{n.push(S(t,!1,r))})):n.push(l)),this._d("path",n,r)}opsToPath(t,e){let r="";for(const n of t.ops){const t="number"==typeof e&&e>=0?n.data.map((t=>+t.toFixed(e))):n.data;switch(n.op){case"move":r+=`M${t[0]} ${t[1]} `;break;case"bcurveTo":r+=`C${t[0]} ${t[1]}, ${t[2]} ${t[3]}, ${t[4]} ${t[5]} `;break;case"lineTo":r+=`L${t[0]} ${t[1]} `}}return r.trim()}toPaths(t){const e=t.sets||[],r=t.options||this.defaultOptions,n=[];for(const i of e){let t=null;switch(i.type){case"path":t={d:this.opsToPath(i),stroke:r.stroke,strokeWidth:r.strokeWidth,fill:J};break;case"fillPath":t={d:this.opsToPath(i),stroke:J,strokeWidth:0,fill:r.fill||J};break;case"fillSketch":t=this.fillSketch(i,r)}t&&n.push(t)}return n}fillSketch(t,e){let r=e.fillWeight;return r<0&&(r=e.strokeWidth/2),{d:this.opsToPath(t),stroke:e.fill||J,strokeWidth:r,fill:J}}_mergedShape(t){return t.filter(((t,e)=>0===e||"move"!==t.op))}}class et{constructor(t,e){this.canvas=t,this.ctx=this.canvas.getContext("2d"),this.gen=new tt(e)}draw(t){const e=t.sets||[],r=t.options||this.getDefaultOptions(),n=this.ctx,i=t.options.fixedDecimalPlaceDigits;for(const a of e)switch(a.type){case"path":n.save(),n.strokeStyle="none"===r.stroke?"transparent":r.stroke,n.lineWidth=r.strokeWidth,r.strokeLineDash&&n.setLineDash(r.strokeLineDash),r.strokeLineDashOffset&&(n.lineDashOffset=r.strokeLineDashOffset),this._drawToContext(n,a,i),n.restore();break;case"fillPath":{n.save(),n.fillStyle=r.fill||"";const e="curve"===t.shape||"polygon"===t.shape||"path"===t.shape?"evenodd":"nonzero";this._drawToContext(n,a,i,e),n.restore();break}case"fillSketch":this.fillSketch(n,a,r)}}fillSketch(t,e,r){let n=r.fillWeight;n<0&&(n=r.strokeWidth/2),t.save(),r.fillLineDash&&t.setLineDash(r.fillLineDash),r.fillLineDashOffset&&(t.lineDashOffset=r.fillLineDashOffset),t.strokeStyle=r.fill||"",t.lineWidth=n,this._drawToContext(t,e,r.fixedDecimalPlaceDigits),t.restore()}_drawToContext(t,e,r,n="nonzero"){t.beginPath();for(const i of e.ops){const e="number"==typeof r&&r>=0?i.data.map((t=>+t.toFixed(r))):i.data;switch(i.op){case"move":t.moveTo(e[0],e[1]);break;case"bcurveTo":t.bezierCurveTo(e[0],e[1],e[2],e[3],e[4],e[5]);break;case"lineTo":t.lineTo(e[0],e[1])}}"fillPath"===e.type?t.fill(n):t.stroke()}get generator(){return this.gen}getDefaultOptions(){return this.gen.defaultOptions}line(t,e,r,n,i){const a=this.gen.line(t,e,r,n,i);return this.draw(a),a}rectangle(t,e,r,n,i){const a=this.gen.rectangle(t,e,r,n,i);return this.draw(a),a}ellipse(t,e,r,n,i){const a=this.gen.ellipse(t,e,r,n,i);return this.draw(a),a}circle(t,e,r,n){const i=this.gen.circle(t,e,r,n);return this.draw(i),i}linearPath(t,e){const r=this.gen.linearPath(t,e);return this.draw(r),r}polygon(t,e){const r=this.gen.polygon(t,e);return this.draw(r),r}arc(t,e,r,n,i,a,o=!1,s){const l=this.gen.arc(t,e,r,n,i,a,o,s);return this.draw(l),l}curve(t,e){const r=this.gen.curve(t,e);return this.draw(r),r}path(t,e){const r=this.gen.path(t,e);return this.draw(r),r}}const rt="http://www.w3.org/2000/svg";class nt{constructor(t,e){this.svg=t,this.gen=new tt(e)}draw(t){const e=t.sets||[],r=t.options||this.getDefaultOptions(),n=this.svg.ownerDocument||window.document,i=n.createElementNS(rt,"g"),a=t.options.fixedDecimalPlaceDigits;for(const o of e){let e=null;switch(o.type){case"path":e=n.createElementNS(rt,"path"),e.setAttribute("d",this.opsToPath(o,a)),e.setAttribute("stroke",r.stroke),e.setAttribute("stroke-width",r.strokeWidth+""),e.setAttribute("fill","none"),r.strokeLineDash&&e.setAttribute("stroke-dasharray",r.strokeLineDash.join(" ").trim()),r.strokeLineDashOffset&&e.setAttribute("stroke-dashoffset",`${r.strokeLineDashOffset}`);break;case"fillPath":e=n.createElementNS(rt,"path"),e.setAttribute("d",this.opsToPath(o,a)),e.setAttribute("stroke","none"),e.setAttribute("stroke-width","0"),e.setAttribute("fill",r.fill||""),"curve"!==t.shape&&"polygon"!==t.shape||e.setAttribute("fill-rule","evenodd");break;case"fillSketch":e=this.fillSketch(n,o,r)}e&&i.appendChild(e)}return i}fillSketch(t,e,r){let n=r.fillWeight;n<0&&(n=r.strokeWidth/2);const i=t.createElementNS(rt,"path");return i.setAttribute("d",this.opsToPath(e,r.fixedDecimalPlaceDigits)),i.setAttribute("stroke",r.fill||""),i.setAttribute("stroke-width",n+""),i.setAttribute("fill","none"),r.fillLineDash&&i.setAttribute("stroke-dasharray",r.fillLineDash.join(" ").trim()),r.fillLineDashOffset&&i.setAttribute("stroke-dashoffset",`${r.fillLineDashOffset}`),i}get generator(){return this.gen}getDefaultOptions(){return this.gen.defaultOptions}opsToPath(t,e){return this.gen.opsToPath(t,e)}line(t,e,r,n,i){const a=this.gen.line(t,e,r,n,i);return this.draw(a)}rectangle(t,e,r,n,i){const a=this.gen.rectangle(t,e,r,n,i);return this.draw(a)}ellipse(t,e,r,n,i){const a=this.gen.ellipse(t,e,r,n,i);return this.draw(a)}circle(t,e,r,n){const i=this.gen.circle(t,e,r,n);return this.draw(i)}linearPath(t,e){const r=this.gen.linearPath(t,e);return this.draw(r)}polygon(t,e){const r=this.gen.polygon(t,e);return this.draw(r)}arc(t,e,r,n,i,a,o=!1,s){const l=this.gen.arc(t,e,r,n,i,a,o,s);return this.draw(l)}curve(t,e){const r=this.gen.curve(t,e);return this.draw(r)}path(t,e){const r=this.gen.path(t,e);return this.draw(r)}}var it={canvas:(t,e)=>new et(t,e),svg:(t,e)=>new nt(t,e),generator:t=>new tt(t),newSeed:()=>tt.newSeed()}},60513:(t,e,r)=>{"use strict";function n(t){for(var e=[],r=1;r<arguments.length;r++)e[r-1]=arguments[r];var n=Array.from("string"==typeof t?[t]:t);n[n.length-1]=n[n.length-1].replace(/\r?\n([\t ]*)$/,"");var i=n.reduce((function(t,e){var r=e.match(/\n([\t ]+|(?!\s).)/g);return r?t.concat(r.map((function(t){var e,r;return null!==(r=null===(e=t.match(/[\t ]/g))||void 0===e?void 0:e.length)&&void 0!==r?r:0}))):t}),[]);if(i.length){var a=new RegExp("\n[\t ]{"+Math.min.apply(Math,i)+"}","g");n=n.map((function(t){return t.replace(a,"\n")}))}n[0]=n[0].replace(/^\r?\n/,"");var o=n[0];return e.forEach((function(t,e){var r=o.match(/(?:^|\n)( *)$/),i=r?r[1]:"",a=t;"string"==typeof t&&t.includes("\n")&&(a=String(t).split("\n").map((function(t,e){return 0===e?t:""+i+t})).join("\n")),o+=a+n[e+1]})),o}r.d(e,{T:()=>n})},28453:(t,e,r)=>{"use strict";r.d(e,{R:()=>o,x:()=>s});var n=r(96540);const i={},a=n.createContext(i);function o(t){const e=n.useContext(a);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function s(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(i):t.components||i:o(t.components),n.createElement(a.Provider,{value:e},t.children)}},20007:(t,e,r)=>{"use strict";function n(t,e){let r;if(void 0===e)for(const n of t)null!=n&&(r<n||void 0===r&&n>=n)&&(r=n);else{let n=-1;for(let i of t)null!=(i=e(i,++n,t))&&(r<i||void 0===r&&i>=i)&&(r=i)}return r}function i(t,e){let r;if(void 0===e)for(const n of t)null!=n&&(r>n||void 0===r&&n>=n)&&(r=n);else{let n=-1;for(let i of t)null!=(i=e(i,++n,t))&&(r>i||void 0===r&&i>=i)&&(r=i)}return r}function a(t){return t}r.d(e,{JLW:()=>Zo,l78:()=>x,tlR:()=>y,qrM:()=>cs,Yu4:()=>us,IA3:()=>ps,Wi0:()=>gs,PGM:()=>ms,OEq:()=>xs,y8u:()=>Cs,olC:()=>_s,IrU:()=>Ss,oDi:()=>Ms,Q7f:()=>Ls,cVp:()=>$s,lUB:()=>Jo,Lx9:()=>Ns,nVG:()=>Ks,uxU:()=>qs,Xf2:()=>Us,GZz:()=>Vs,UPb:()=>Zs,dyv:()=>Gs,bEH:()=>rn,n8j:()=>rs,T9B:()=>n,jkA:()=>i,rLf:()=>as,WH:()=>dn,m4Y:()=>ii,UMr:()=>un,w7C:()=>Co,zt:()=>wo,Ltv:()=>_o,UAC:()=>Ci,DCK:()=>Ji,TUC:()=>Li,Agd:()=>bi,t6C:()=>gi,wXd:()=>yi,ABi:()=>Ai,Ui6:()=>Pi,rGn:()=>Fi,ucG:()=>mi,YPH:()=>Si,Mol:()=>Bi,PGu:()=>Ti,GuW:()=>Mi});var o=1,s=2,l=3,c=4,h=1e-6;function u(t){return"translate("+t+",0)"}function d(t){return"translate(0,"+t+")"}function p(t){return e=>+t(e)}function f(t,e){return e=Math.max(0,t.bandwidth()-2*e)/2,t.round()&&(e=Math.round(e)),r=>+t(r)+e}function g(){return!this.__axis}function m(t,e){var r=[],n=null,i=null,m=6,y=6,x=3,b="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,k=t===o||t===c?-1:1,C=t===c||t===s?"x":"y",w=t===o||t===l?u:d;function _(u){var d=null==n?e.ticks?e.ticks.apply(e,r):e.domain():n,_=null==i?e.tickFormat?e.tickFormat.apply(e,r):a:i,v=Math.max(m,0)+x,S=e.range(),A=+S[0]+b,T=+S[S.length-1]+b,M=(e.bandwidth?f:p)(e.copy(),b),B=u.selection?u.selection():u,L=B.selectAll(".domain").data([null]),F=B.selectAll(".tick").data(d,e).order(),$=F.exit(),E=F.enter().append("g").attr("class","tick"),N=F.select("line"),D=F.select("text");L=L.merge(L.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),F=F.merge(E),N=N.merge(E.append("line").attr("stroke","currentColor").attr(C+"2",k*m)),D=D.merge(E.append("text").attr("fill","currentColor").attr(C,k*v).attr("dy",t===o?"0em":t===l?"0.71em":"0.32em")),u!==B&&(L=L.transition(u),F=F.transition(u),N=N.transition(u),D=D.transition(u),$=$.transition(u).attr("opacity",h).attr("transform",(function(t){return isFinite(t=M(t))?w(t+b):this.getAttribute("transform")})),E.attr("opacity",h).attr("transform",(function(t){var e=this.parentNode.__axis;return w((e&&isFinite(e=e(t))?e:M(t))+b)}))),$.remove(),L.attr("d",t===c||t===s?y?"M"+k*y+","+A+"H"+b+"V"+T+"H"+k*y:"M"+b+","+A+"V"+T:y?"M"+A+","+k*y+"V"+b+"H"+T+"V"+k*y:"M"+A+","+b+"H"+T),F.attr("opacity",1).attr("transform",(function(t){return w(M(t)+b)})),N.attr(C+"2",k*m),D.attr(C,k*v).text(_),B.filter(g).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===s?"start":t===c?"end":"middle"),B.each((function(){this.__axis=M}))}return _.scale=function(t){return arguments.length?(e=t,_):e},_.ticks=function(){return r=Array.from(arguments),_},_.tickArguments=function(t){return arguments.length?(r=null==t?[]:Array.from(t),_):r.slice()},_.tickValues=function(t){return arguments.length?(n=null==t?null:Array.from(t),_):n&&n.slice()},_.tickFormat=function(t){return arguments.length?(i=t,_):i},_.tickSize=function(t){return arguments.length?(m=y=+t,_):m},_.tickSizeInner=function(t){return arguments.length?(m=+t,_):m},_.tickSizeOuter=function(t){return arguments.length?(y=+t,_):y},_.tickPadding=function(t){return arguments.length?(x=+t,_):x},_.offset=function(t){return arguments.length?(b=+t,_):b},_}function y(t){return m(o,t)}function x(t){return m(l,t)}function b(){}function k(t){return null==t?b:function(){return this.querySelector(t)}}function C(){return[]}function w(t){return null==t?C:function(){return this.querySelectorAll(t)}}function _(t){return function(){return null==(e=t.apply(this,arguments))?[]:Array.isArray(e)?e:Array.from(e);var e}}function v(t){return function(){return this.matches(t)}}function S(t){return function(e){return e.matches(t)}}var A=Array.prototype.find;function T(){return this.firstElementChild}var M=Array.prototype.filter;function B(){return Array.from(this.children)}function L(t){return new Array(t.length)}function F(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function $(t,e,r,n,i,a){for(var o,s=0,l=e.length,c=a.length;s<c;++s)(o=e[s])?(o.__data__=a[s],n[s]=o):r[s]=new F(t,a[s]);for(;s<l;++s)(o=e[s])&&(i[s]=o)}function E(t,e,r,n,i,a,o){var s,l,c,h=new Map,u=e.length,d=a.length,p=new Array(u);for(s=0;s<u;++s)(l=e[s])&&(p[s]=c=o.call(l,l.__data__,s,e)+"",h.has(c)?i[s]=l:h.set(c,l));for(s=0;s<d;++s)c=o.call(t,a[s],s,a)+"",(l=h.get(c))?(n[s]=l,l.__data__=a[s],h.delete(c)):r[s]=new F(t,a[s]);for(s=0;s<u;++s)(l=e[s])&&h.get(p[s])===l&&(i[s]=l)}function N(t){return t.__data__}function D(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function j(t,e){return t<e?-1:t>e?1:t>=e?0:NaN}F.prototype={constructor:F,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var I="http://www.w3.org/1999/xhtml";const O={svg:"http://www.w3.org/2000/svg",xhtml:I,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function R(t){var e=t+="",r=e.indexOf(":");return r>=0&&"xmlns"!==(e=t.slice(0,r))&&(t=t.slice(r+1)),O.hasOwnProperty(e)?{space:O[e],local:t}:t}function P(t){return function(){this.removeAttribute(t)}}function z(t){return function(){this.removeAttributeNS(t.space,t.local)}}function K(t,e){return function(){this.setAttribute(t,e)}}function q(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function W(t,e){return function(){var r=e.apply(this,arguments);null==r?this.removeAttribute(t):this.setAttribute(t,r)}}function H(t,e){return function(){var r=e.apply(this,arguments);null==r?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,r)}}function U(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function Y(t){return function(){this.style.removeProperty(t)}}function V(t,e,r){return function(){this.style.setProperty(t,e,r)}}function G(t,e,r){return function(){var n=e.apply(this,arguments);null==n?this.style.removeProperty(t):this.style.setProperty(t,n,r)}}function Z(t,e){return t.style.getPropertyValue(e)||U(t).getComputedStyle(t,null).getPropertyValue(e)}function X(t){return function(){delete this[t]}}function Q(t,e){return function(){this[t]=e}}function J(t,e){return function(){var r=e.apply(this,arguments);null==r?delete this[t]:this[t]=r}}function tt(t){return t.trim().split(/^|\s+/)}function et(t){return t.classList||new rt(t)}function rt(t){this._node=t,this._names=tt(t.getAttribute("class")||"")}function nt(t,e){for(var r=et(t),n=-1,i=e.length;++n<i;)r.add(e[n])}function it(t,e){for(var r=et(t),n=-1,i=e.length;++n<i;)r.remove(e[n])}function at(t){return function(){nt(this,t)}}function ot(t){return function(){it(this,t)}}function st(t,e){return function(){(e.apply(this,arguments)?nt:it)(this,t)}}function lt(){this.textContent=""}function ct(t){return function(){this.textContent=t}}function ht(t){return function(){var e=t.apply(this,arguments);this.textContent=null==e?"":e}}function ut(){this.innerHTML=""}function dt(t){return function(){this.innerHTML=t}}function pt(t){return function(){var e=t.apply(this,arguments);this.innerHTML=null==e?"":e}}function ft(){this.nextSibling&&this.parentNode.appendChild(this)}function gt(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function mt(t){return function(){var e=this.ownerDocument,r=this.namespaceURI;return r===I&&e.documentElement.namespaceURI===I?e.createElement(t):e.createElementNS(r,t)}}function yt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function xt(t){var e=R(t);return(e.local?yt:mt)(e)}function bt(){return null}function kt(){var t=this.parentNode;t&&t.removeChild(this)}function Ct(){var t=this.cloneNode(!1),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function wt(){var t=this.cloneNode(!0),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function _t(t){return function(){var e=this.__on;if(e){for(var r,n=0,i=-1,a=e.length;n<a;++n)r=e[n],t.type&&r.type!==t.type||r.name!==t.name?e[++i]=r:this.removeEventListener(r.type,r.listener,r.options);++i?e.length=i:delete this.__on}}}function vt(t,e,r){return function(){var n,i=this.__on,a=function(t){return function(e){t.call(this,e,this.__data__)}}(e);if(i)for(var o=0,s=i.length;o<s;++o)if((n=i[o]).type===t.type&&n.name===t.name)return this.removeEventListener(n.type,n.listener,n.options),this.addEventListener(n.type,n.listener=a,n.options=r),void(n.value=e);this.addEventListener(t.type,a,r),n={type:t.type,name:t.name,value:e,listener:a,options:r},i?i.push(n):this.__on=[n]}}function St(t,e,r){var n=U(t),i=n.CustomEvent;"function"==typeof i?i=new i(e,r):(i=n.document.createEvent("Event"),r?(i.initEvent(e,r.bubbles,r.cancelable),i.detail=r.detail):i.initEvent(e,!1,!1)),t.dispatchEvent(i)}function At(t,e){return function(){return St(this,t,e)}}function Tt(t,e){return function(){return St(this,t,e.apply(this,arguments))}}rt.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var e=this._names.indexOf(t);e>=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Mt=[null];function Bt(t,e){this._groups=t,this._parents=e}function Lt(){return new Bt([[document.documentElement]],Mt)}Bt.prototype=Lt.prototype={constructor:Bt,select:function(t){"function"!=typeof t&&(t=k(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i<r;++i)for(var a,o,s=e[i],l=s.length,c=n[i]=new Array(l),h=0;h<l;++h)(a=s[h])&&(o=t.call(a,a.__data__,h,s))&&("__data__"in a&&(o.__data__=a.__data__),c[h]=o);return new Bt(n,this._parents)},selectAll:function(t){t="function"==typeof t?_(t):w(t);for(var e=this._groups,r=e.length,n=[],i=[],a=0;a<r;++a)for(var o,s=e[a],l=s.length,c=0;c<l;++c)(o=s[c])&&(n.push(t.call(o,o.__data__,c,s)),i.push(o));return new Bt(n,i)},selectChild:function(t){return this.select(null==t?T:function(t){return function(){return A.call(this.children,t)}}("function"==typeof t?t:S(t)))},selectChildren:function(t){return this.selectAll(null==t?B:function(t){return function(){return M.call(this.children,t)}}("function"==typeof t?t:S(t)))},filter:function(t){"function"!=typeof t&&(t=v(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i<r;++i)for(var a,o=e[i],s=o.length,l=n[i]=[],c=0;c<s;++c)(a=o[c])&&t.call(a,a.__data__,c,o)&&l.push(a);return new Bt(n,this._parents)},data:function(t,e){if(!arguments.length)return Array.from(this,N);var r,n=e?E:$,i=this._parents,a=this._groups;"function"!=typeof t&&(r=t,t=function(){return r});for(var o=a.length,s=new Array(o),l=new Array(o),c=new Array(o),h=0;h<o;++h){var u=i[h],d=a[h],p=d.length,f=D(t.call(u,u&&u.__data__,h,i)),g=f.length,m=l[h]=new Array(g),y=s[h]=new Array(g);n(u,d,m,y,c[h]=new Array(p),f,e);for(var x,b,k=0,C=0;k<g;++k)if(x=m[k]){for(k>=C&&(C=k+1);!(b=y[C])&&++C<g;);x._next=b||null}}return(s=new Bt(s,i))._enter=l,s._exit=c,s},enter:function(){return new Bt(this._enter||this._groups.map(L),this._parents)},exit:function(){return new Bt(this._exit||this._groups.map(L),this._parents)},join:function(t,e,r){var n=this.enter(),i=this,a=this.exit();return"function"==typeof t?(n=t(n))&&(n=n.selection()):n=n.append(t+""),null!=e&&(i=e(i))&&(i=i.selection()),null==r?a.remove():r(a),n&&i?n.merge(i).order():i},merge:function(t){for(var e=t.selection?t.selection():t,r=this._groups,n=e._groups,i=r.length,a=n.length,o=Math.min(i,a),s=new Array(i),l=0;l<o;++l)for(var c,h=r[l],u=n[l],d=h.length,p=s[l]=new Array(d),f=0;f<d;++f)(c=h[f]||u[f])&&(p[f]=c);for(;l<i;++l)s[l]=r[l];return new Bt(s,this._parents)},selection:function(){return this},order:function(){for(var t=this._groups,e=-1,r=t.length;++e<r;)for(var n,i=t[e],a=i.length-1,o=i[a];--a>=0;)(n=i[a])&&(o&&4^n.compareDocumentPosition(o)&&o.parentNode.insertBefore(n,o),o=n);return this},sort:function(t){function e(e,r){return e&&r?t(e.__data__,r.__data__):!e-!r}t||(t=j);for(var r=this._groups,n=r.length,i=new Array(n),a=0;a<n;++a){for(var o,s=r[a],l=s.length,c=i[a]=new Array(l),h=0;h<l;++h)(o=s[h])&&(c[h]=o);c.sort(e)}return new Bt(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){return Array.from(this)},node:function(){for(var t=this._groups,e=0,r=t.length;e<r;++e)for(var n=t[e],i=0,a=n.length;i<a;++i){var o=n[i];if(o)return o}return null},size:function(){let t=0;for(const e of this)++t;return t},empty:function(){return!this.node()},each:function(t){for(var e=this._groups,r=0,n=e.length;r<n;++r)for(var i,a=e[r],o=0,s=a.length;o<s;++o)(i=a[o])&&t.call(i,i.__data__,o,a);return this},attr:function(t,e){var r=R(t);if(arguments.length<2){var n=this.node();return r.local?n.getAttributeNS(r.space,r.local):n.getAttribute(r)}return this.each((null==e?r.local?z:P:"function"==typeof e?r.local?H:W:r.local?q:K)(r,e))},style:function(t,e,r){return arguments.length>1?this.each((null==e?Y:"function"==typeof e?G:V)(t,e,null==r?"":r)):Z(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?X:"function"==typeof e?J:Q)(t,e)):this.node()[t]},classed:function(t,e){var r=tt(t+"");if(arguments.length<2){for(var n=et(this.node()),i=-1,a=r.length;++i<a;)if(!n.contains(r[i]))return!1;return!0}return this.each(("function"==typeof e?st:e?at:ot)(r,e))},text:function(t){return arguments.length?this.each(null==t?lt:("function"==typeof t?ht:ct)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?ut:("function"==typeof t?pt:dt)(t)):this.node().innerHTML},raise:function(){return this.each(ft)},lower:function(){return this.each(gt)},append:function(t){var e="function"==typeof t?t:xt(t);return this.select((function(){return this.appendChild(e.apply(this,arguments))}))},insert:function(t,e){var r="function"==typeof t?t:xt(t),n=null==e?bt:"function"==typeof e?e:k(e);return this.select((function(){return this.insertBefore(r.apply(this,arguments),n.apply(this,arguments)||null)}))},remove:function(){return this.each(kt)},clone:function(t){return this.select(t?wt:Ct)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,e,r){var n,i,a=function(t){return t.trim().split(/^|\s+/).map((function(t){var e="",r=t.indexOf(".");return r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),{type:t,name:e}}))}(t+""),o=a.length;if(!(arguments.length<2)){for(s=e?vt:_t,n=0;n<o;++n)this.each(s(a[n],e,r));return this}var s=this.node().__on;if(s)for(var l,c=0,h=s.length;c<h;++c)for(n=0,l=s[c];n<o;++n)if((i=a[n]).type===l.type&&i.name===l.name)return l.value},dispatch:function(t,e){return this.each(("function"==typeof e?Tt:At)(t,e))},[Symbol.iterator]:function*(){for(var t=this._groups,e=0,r=t.length;e<r;++e)for(var n,i=t[e],a=0,o=i.length;a<o;++a)(n=i[a])&&(yield n)}};const Ft=Lt;var $t={value:()=>{}};function Et(){for(var t,e=0,r=arguments.length,n={};e<r;++e){if(!(t=arguments[e]+"")||t in n||/[\s.]/.test(t))throw new Error("illegal type: "+t);n[t]=[]}return new Nt(n)}function Nt(t){this._=t}function Dt(t,e){for(var r,n=0,i=t.length;n<i;++n)if((r=t[n]).name===e)return r.value}function jt(t,e,r){for(var n=0,i=t.length;n<i;++n)if(t[n].name===e){t[n]=$t,t=t.slice(0,n).concat(t.slice(n+1));break}return null!=r&&t.push({name:e,value:r}),t}Nt.prototype=Et.prototype={constructor:Nt,on:function(t,e){var r,n,i=this._,a=(n=i,(t+"").trim().split(/^|\s+/).map((function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}}))),o=-1,s=a.length;if(!(arguments.length<2)){if(null!=e&&"function"!=typeof e)throw new Error("invalid callback: "+e);for(;++o<s;)if(r=(t=a[o]).type)i[r]=jt(i[r],t.name,e);else if(null==e)for(r in i)i[r]=jt(i[r],t.name,null);return this}for(;++o<s;)if((r=(t=a[o]).type)&&(r=Dt(i[r],t.name)))return r},copy:function(){var t={},e=this._;for(var r in e)t[r]=e[r].slice();return new Nt(t)},call:function(t,e){if((r=arguments.length-2)>0)for(var r,n,i=new Array(r),a=0;a<r;++a)i[a]=arguments[a+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(a=0,r=(n=this._[t]).length;a<r;++a)n[a].value.apply(e,i)},apply:function(t,e,r){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var n=this._[t],i=0,a=n.length;i<a;++i)n[i].value.apply(e,r)}};const It=Et;var Ot,Rt,Pt=0,zt=0,Kt=0,qt=0,Wt=0,Ht=0,Ut="object"==typeof performance&&performance.now?performance:Date,Yt="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function Vt(){return Wt||(Yt(Gt),Wt=Ut.now()+Ht)}function Gt(){Wt=0}function Zt(){this._call=this._time=this._next=null}function Xt(t,e,r){var n=new Zt;return n.restart(t,e,r),n}function Qt(){Wt=(qt=Ut.now())+Ht,Pt=zt=0;try{!function(){Vt(),++Pt;for(var t,e=Ot;e;)(t=Wt-e._time)>=0&&e._call.call(void 0,t),e=e._next;--Pt}()}finally{Pt=0,function(){var t,e,r=Ot,n=1/0;for(;r;)r._call?(n>r._time&&(n=r._time),t=r,r=r._next):(e=r._next,r._next=null,r=t?t._next=e:Ot=e);Rt=t,te(n)}(),Wt=0}}function Jt(){var t=Ut.now(),e=t-qt;e>1e3&&(Ht-=e,qt=t)}function te(t){Pt||(zt&&(zt=clearTimeout(zt)),t-Wt>24?(t<1/0&&(zt=setTimeout(Qt,t-Ut.now()-Ht)),Kt&&(Kt=clearInterval(Kt))):(Kt||(qt=Ut.now(),Kt=setInterval(Jt,1e3)),Pt=1,Yt(Qt)))}function ee(t,e,r){var n=new Zt;return e=null==e?0:+e,n.restart((r=>{n.stop(),t(r+e)}),e,r),n}Zt.prototype=Xt.prototype={constructor:Zt,restart:function(t,e,r){if("function"!=typeof t)throw new TypeError("callback is not a function");r=(null==r?Vt():+r)+(null==e?0:+e),this._next||Rt===this||(Rt?Rt._next=this:Ot=this,Rt=this),this._call=t,this._time=r,te()},stop:function(){this._call&&(this._call=null,this._time=1/0,te())}};var re=It("start","end","cancel","interrupt"),ne=[];function ie(t,e,r,n,i,a){var o=t.__transition;if(o){if(r in o)return}else t.__transition={};!function(t,e,r){var n,i=t.__transition;function a(t){r.state=1,r.timer.restart(o,r.delay,r.time),r.delay<=t&&o(t-r.delay)}function o(a){var c,h,u,d;if(1!==r.state)return l();for(c in i)if((d=i[c]).name===r.name){if(3===d.state)return ee(o);4===d.state?(d.state=6,d.timer.stop(),d.on.call("interrupt",t,t.__data__,d.index,d.group),delete i[c]):+c<e&&(d.state=6,d.timer.stop(),d.on.call("cancel",t,t.__data__,d.index,d.group),delete i[c])}if(ee((function(){3===r.state&&(r.state=4,r.timer.restart(s,r.delay,r.time),s(a))})),r.state=2,r.on.call("start",t,t.__data__,r.index,r.group),2===r.state){for(r.state=3,n=new Array(u=r.tween.length),c=0,h=-1;c<u;++c)(d=r.tween[c].value.call(t,t.__data__,r.index,r.group))&&(n[++h]=d);n.length=h+1}}function s(e){for(var i=e<r.duration?r.ease.call(null,e/r.duration):(r.timer.restart(l),r.state=5,1),a=-1,o=n.length;++a<o;)n[a].call(t,i);5===r.state&&(r.on.call("end",t,t.__data__,r.index,r.group),l())}function l(){for(var n in r.state=6,r.timer.stop(),delete i[e],i)return;delete t.__transition}i[e]=r,r.timer=Xt(a,0,r.time)}(t,r,{name:e,index:n,group:i,on:re,tween:ne,time:a.time,delay:a.delay,duration:a.duration,ease:a.ease,timer:null,state:0})}function ae(t,e){var r=se(t,e);if(r.state>0)throw new Error("too late; already scheduled");return r}function oe(t,e){var r=se(t,e);if(r.state>3)throw new Error("too late; already running");return r}function se(t,e){var r=t.__transition;if(!r||!(r=r[e]))throw new Error("transition not found");return r}function le(t,e){return t=+t,e=+e,function(r){return t*(1-r)+e*r}}var ce,he=180/Math.PI,ue={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function de(t,e,r,n,i,a){var o,s,l;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(l=t*r+e*n)&&(r-=t*l,n-=e*l),(s=Math.sqrt(r*r+n*n))&&(r/=s,n/=s,l/=s),t*n<e*r&&(t=-t,e=-e,l=-l,o=-o),{translateX:i,translateY:a,rotate:Math.atan2(e,t)*he,skewX:Math.atan(l)*he,scaleX:o,scaleY:s}}function pe(t,e,r,n){function i(t){return t.length?t.pop()+" ":""}return function(a,o){var s=[],l=[];return a=t(a),o=t(o),function(t,n,i,a,o,s){if(t!==i||n!==a){var l=o.push("translate(",null,e,null,r);s.push({i:l-4,x:le(t,i)},{i:l-2,x:le(n,a)})}else(i||a)&&o.push("translate("+i+e+a+r)}(a.translateX,a.translateY,o.translateX,o.translateY,s,l),function(t,e,r,a){t!==e?(t-e>180?e+=360:e-t>180&&(t+=360),a.push({i:r.push(i(r)+"rotate(",null,n)-2,x:le(t,e)})):e&&r.push(i(r)+"rotate("+e+n)}(a.rotate,o.rotate,s,l),function(t,e,r,a){t!==e?a.push({i:r.push(i(r)+"skewX(",null,n)-2,x:le(t,e)}):e&&r.push(i(r)+"skewX("+e+n)}(a.skewX,o.skewX,s,l),function(t,e,r,n,a,o){if(t!==r||e!==n){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:le(t,r)},{i:s-2,x:le(e,n)})}else 1===r&&1===n||a.push(i(a)+"scale("+r+","+n+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,l),a=o=null,function(t){for(var e,r=-1,n=l.length;++r<n;)s[(e=l[r]).i]=e.x(t);return s.join("")}}}var fe=pe((function(t){const e=new("function"==typeof DOMMatrix?DOMMatrix:WebKitCSSMatrix)(t+"");return e.isIdentity?ue:de(e.a,e.b,e.c,e.d,e.e,e.f)}),"px, ","px)","deg)"),ge=pe((function(t){return null==t?ue:(ce||(ce=document.createElementNS("http://www.w3.org/2000/svg","g")),ce.setAttribute("transform",t),(t=ce.transform.baseVal.consolidate())?de((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):ue)}),", ",")",")");function me(t,e){var r,n;return function(){var i=oe(this,t),a=i.tween;if(a!==r)for(var o=0,s=(n=r=a).length;o<s;++o)if(n[o].name===e){(n=n.slice()).splice(o,1);break}i.tween=n}}function ye(t,e,r){var n,i;if("function"!=typeof r)throw new Error;return function(){var a=oe(this,t),o=a.tween;if(o!==n){i=(n=o).slice();for(var s={name:e,value:r},l=0,c=i.length;l<c;++l)if(i[l].name===e){i[l]=s;break}l===c&&i.push(s)}a.tween=i}}function xe(t,e,r){var n=t._id;return t.each((function(){var t=oe(this,n);(t.value||(t.value={}))[e]=r.apply(this,arguments)})),function(t){return se(t,n).value[e]}}function be(t,e,r){t.prototype=e.prototype=r,r.constructor=t}function ke(t,e){var r=Object.create(t.prototype);for(var n in e)r[n]=e[n];return r}function Ce(){}var we=.7,_e=1/we,ve="\\s*([+-]?\\d+)\\s*",Se="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",Ae="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",Te=/^#([0-9a-f]{3,8})$/,Me=new RegExp(`^rgb\\(${ve},${ve},${ve}\\)$`),Be=new RegExp(`^rgb\\(${Ae},${Ae},${Ae}\\)$`),Le=new RegExp(`^rgba\\(${ve},${ve},${ve},${Se}\\)$`),Fe=new RegExp(`^rgba\\(${Ae},${Ae},${Ae},${Se}\\)$`),$e=new RegExp(`^hsl\\(${Se},${Ae},${Ae}\\)$`),Ee=new RegExp(`^hsla\\(${Se},${Ae},${Ae},${Se}\\)$`),Ne={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function De(){return this.rgb().formatHex()}function je(){return this.rgb().formatRgb()}function Ie(t){var e,r;return t=(t+"").trim().toLowerCase(),(e=Te.exec(t))?(r=e[1].length,e=parseInt(e[1],16),6===r?Oe(e):3===r?new Ke(e>>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===r?Re(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===r?Re(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Me.exec(t))?new Ke(e[1],e[2],e[3],1):(e=Be.exec(t))?new Ke(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Le.exec(t))?Re(e[1],e[2],e[3],e[4]):(e=Fe.exec(t))?Re(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=$e.exec(t))?Ve(e[1],e[2]/100,e[3]/100,1):(e=Ee.exec(t))?Ve(e[1],e[2]/100,e[3]/100,e[4]):Ne.hasOwnProperty(t)?Oe(Ne[t]):"transparent"===t?new Ke(NaN,NaN,NaN,0):null}function Oe(t){return new Ke(t>>16&255,t>>8&255,255&t,1)}function Re(t,e,r,n){return n<=0&&(t=e=r=NaN),new Ke(t,e,r,n)}function Pe(t){return t instanceof Ce||(t=Ie(t)),t?new Ke((t=t.rgb()).r,t.g,t.b,t.opacity):new Ke}function ze(t,e,r,n){return 1===arguments.length?Pe(t):new Ke(t,e,r,null==n?1:n)}function Ke(t,e,r,n){this.r=+t,this.g=+e,this.b=+r,this.opacity=+n}function qe(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}`}function We(){const t=He(this.opacity);return`${1===t?"rgb(":"rgba("}${Ue(this.r)}, ${Ue(this.g)}, ${Ue(this.b)}${1===t?")":`, ${t})`}`}function He(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Ue(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Ye(t){return((t=Ue(t))<16?"0":"")+t.toString(16)}function Ve(t,e,r,n){return n<=0?t=e=r=NaN:r<=0||r>=1?t=e=NaN:e<=0&&(t=NaN),new Ze(t,e,r,n)}function Ge(t){if(t instanceof Ze)return new Ze(t.h,t.s,t.l,t.opacity);if(t instanceof Ce||(t=Ie(t)),!t)return new Ze;if(t instanceof Ze)return t;var e=(t=t.rgb()).r/255,r=t.g/255,n=t.b/255,i=Math.min(e,r,n),a=Math.max(e,r,n),o=NaN,s=a-i,l=(a+i)/2;return s?(o=e===a?(r-n)/s+6*(r<n):r===a?(n-e)/s+2:(e-r)/s+4,s/=l<.5?a+i:2-a-i,o*=60):s=l>0&&l<1?0:o,new Ze(o,s,l,t.opacity)}function Ze(t,e,r,n){this.h=+t,this.s=+e,this.l=+r,this.opacity=+n}function Xe(t){return(t=(t||0)%360)<0?t+360:t}function Qe(t){return Math.max(0,Math.min(1,t||0))}function Je(t,e,r){return 255*(t<60?e+(r-e)*t/60:t<180?r:t<240?e+(r-e)*(240-t)/60:e)}function tr(t,e,r,n,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*r+(1+3*t+3*a-3*o)*n+o*i)/6}be(Ce,Ie,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:De,formatHex:De,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return Ge(this).formatHsl()},formatRgb:je,toString:je}),be(Ke,ze,ke(Ce,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new Ke(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?we:Math.pow(we,t),new Ke(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new Ke(Ue(this.r),Ue(this.g),Ue(this.b),He(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:qe,formatHex:qe,formatHex8:function(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}${Ye(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:We,toString:We})),be(Ze,(function(t,e,r,n){return 1===arguments.length?Ge(t):new Ze(t,e,r,null==n?1:n)}),ke(Ce,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new Ze(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?we:Math.pow(we,t),new Ze(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,r=this.l,n=r+(r<.5?r:1-r)*e,i=2*r-n;return new Ke(Je(t>=240?t-240:t+120,i,n),Je(t,i,n),Je(t<120?t+240:t-120,i,n),this.opacity)},clamp(){return new Ze(Xe(this.h),Qe(this.s),Qe(this.l),He(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=He(this.opacity);return`${1===t?"hsl(":"hsla("}${Xe(this.h)}, ${100*Qe(this.s)}%, ${100*Qe(this.l)}%${1===t?")":`, ${t})`}`}}));const er=t=>()=>t;function rr(t,e){return function(r){return t+r*e}}function nr(t){return 1==(t=+t)?ir:function(e,r){return r-e?function(t,e,r){return t=Math.pow(t,r),e=Math.pow(e,r)-t,r=1/r,function(n){return Math.pow(t+n*e,r)}}(e,r,t):er(isNaN(e)?r:e)}}function ir(t,e){var r=e-t;return r?rr(t,r):er(isNaN(t)?e:t)}const ar=function t(e){var r=nr(e);function n(t,e){var n=r((t=ze(t)).r,(e=ze(e)).r),i=r(t.g,e.g),a=r(t.b,e.b),o=ir(t.opacity,e.opacity);return function(e){return t.r=n(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return n.gamma=t,n}(1);function or(t){return function(e){var r,n,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(r=0;r<i;++r)n=ze(e[r]),a[r]=n.r||0,o[r]=n.g||0,s[r]=n.b||0;return a=t(a),o=t(o),s=t(s),n.opacity=1,function(t){return n.r=a(t),n.g=o(t),n.b=s(t),n+""}}}or((function(t){var e=t.length-1;return function(r){var n=r<=0?r=0:r>=1?(r=1,e-1):Math.floor(r*e),i=t[n],a=t[n+1],o=n>0?t[n-1]:2*i-a,s=n<e-1?t[n+2]:2*a-i;return tr((r-n/e)*e,o,i,a,s)}})),or((function(t){var e=t.length;return function(r){var n=Math.floor(((r%=1)<0?++r:r)*e),i=t[(n+e-1)%e],a=t[n%e],o=t[(n+1)%e],s=t[(n+2)%e];return tr((r-n/e)*e,i,a,o,s)}}));var sr=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,lr=new RegExp(sr.source,"g");function cr(t,e){var r,n,i,a=sr.lastIndex=lr.lastIndex=0,o=-1,s=[],l=[];for(t+="",e+="";(r=sr.exec(t))&&(n=lr.exec(e));)(i=n.index)>a&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(r=r[0])===(n=n[0])?s[o]?s[o]+=n:s[++o]=n:(s[++o]=null,l.push({i:o,x:le(r,n)})),a=lr.lastIndex;return a<e.length&&(i=e.slice(a),s[o]?s[o]+=i:s[++o]=i),s.length<2?l[0]?function(t){return function(e){return t(e)+""}}(l[0].x):function(t){return function(){return t}}(e):(e=l.length,function(t){for(var r,n=0;n<e;++n)s[(r=l[n]).i]=r.x(t);return s.join("")})}function hr(t,e){var r;return("number"==typeof e?le:e instanceof Ie?ar:(r=Ie(e))?(e=r,ar):cr)(t,e)}function ur(t){return function(){this.removeAttribute(t)}}function dr(t){return function(){this.removeAttributeNS(t.space,t.local)}}function pr(t,e,r){var n,i,a=r+"";return function(){var o=this.getAttribute(t);return o===a?null:o===n?i:i=e(n=o,r)}}function fr(t,e,r){var n,i,a=r+"";return function(){var o=this.getAttributeNS(t.space,t.local);return o===a?null:o===n?i:i=e(n=o,r)}}function gr(t,e,r){var n,i,a;return function(){var o,s,l=r(this);if(null!=l)return(o=this.getAttribute(t))===(s=l+"")?null:o===n&&s===i?a:(i=s,a=e(n=o,l));this.removeAttribute(t)}}function mr(t,e,r){var n,i,a;return function(){var o,s,l=r(this);if(null!=l)return(o=this.getAttributeNS(t.space,t.local))===(s=l+"")?null:o===n&&s===i?a:(i=s,a=e(n=o,l));this.removeAttributeNS(t.space,t.local)}}function yr(t,e){var r,n;function i(){var i=e.apply(this,arguments);return i!==n&&(r=(n=i)&&function(t,e){return function(r){this.setAttributeNS(t.space,t.local,e.call(this,r))}}(t,i)),r}return i._value=e,i}function xr(t,e){var r,n;function i(){var i=e.apply(this,arguments);return i!==n&&(r=(n=i)&&function(t,e){return function(r){this.setAttribute(t,e.call(this,r))}}(t,i)),r}return i._value=e,i}function br(t,e){return function(){ae(this,t).delay=+e.apply(this,arguments)}}function kr(t,e){return e=+e,function(){ae(this,t).delay=e}}function Cr(t,e){return function(){oe(this,t).duration=+e.apply(this,arguments)}}function wr(t,e){return e=+e,function(){oe(this,t).duration=e}}var _r=Ft.prototype.constructor;function vr(t){return function(){this.style.removeProperty(t)}}var Sr=0;function Ar(t,e,r,n){this._groups=t,this._parents=e,this._name=r,this._id=n}function Tr(){return++Sr}var Mr=Ft.prototype;Ar.prototype=function(t){return Ft().transition(t)}.prototype={constructor:Ar,select:function(t){var e=this._name,r=this._id;"function"!=typeof t&&(t=k(t));for(var n=this._groups,i=n.length,a=new Array(i),o=0;o<i;++o)for(var s,l,c=n[o],h=c.length,u=a[o]=new Array(h),d=0;d<h;++d)(s=c[d])&&(l=t.call(s,s.__data__,d,c))&&("__data__"in s&&(l.__data__=s.__data__),u[d]=l,ie(u[d],e,r,d,u,se(s,r)));return new Ar(a,this._parents,e,r)},selectAll:function(t){var e=this._name,r=this._id;"function"!=typeof t&&(t=w(t));for(var n=this._groups,i=n.length,a=[],o=[],s=0;s<i;++s)for(var l,c=n[s],h=c.length,u=0;u<h;++u)if(l=c[u]){for(var d,p=t.call(l,l.__data__,u,c),f=se(l,r),g=0,m=p.length;g<m;++g)(d=p[g])&&ie(d,e,r,g,p,f);a.push(p),o.push(l)}return new Ar(a,o,e,r)},selectChild:Mr.selectChild,selectChildren:Mr.selectChildren,filter:function(t){"function"!=typeof t&&(t=v(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i<r;++i)for(var a,o=e[i],s=o.length,l=n[i]=[],c=0;c<s;++c)(a=o[c])&&t.call(a,a.__data__,c,o)&&l.push(a);return new Ar(n,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var e=this._groups,r=t._groups,n=e.length,i=r.length,a=Math.min(n,i),o=new Array(n),s=0;s<a;++s)for(var l,c=e[s],h=r[s],u=c.length,d=o[s]=new Array(u),p=0;p<u;++p)(l=c[p]||h[p])&&(d[p]=l);for(;s<n;++s)o[s]=e[s];return new Ar(o,this._parents,this._name,this._id)},selection:function(){return new _r(this._groups,this._parents)},transition:function(){for(var t=this._name,e=this._id,r=Tr(),n=this._groups,i=n.length,a=0;a<i;++a)for(var o,s=n[a],l=s.length,c=0;c<l;++c)if(o=s[c]){var h=se(o,e);ie(o,t,r,c,s,{time:h.time+h.delay+h.duration,delay:0,duration:h.duration,ease:h.ease})}return new Ar(n,this._parents,t,r)},call:Mr.call,nodes:Mr.nodes,node:Mr.node,size:Mr.size,empty:Mr.empty,each:Mr.each,on:function(t,e){var r=this._id;return arguments.length<2?se(this.node(),r).on.on(t):this.each(function(t,e,r){var n,i,a=function(t){return(t+"").trim().split(/^|\s+/).every((function(t){var e=t.indexOf(".");return e>=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?ae:oe;return function(){var o=a(this,t),s=o.on;s!==n&&(i=(n=s).copy()).on(e,r),o.on=i}}(r,t,e))},attr:function(t,e){var r=R(t),n="transform"===r?ge:hr;return this.attrTween(t,"function"==typeof e?(r.local?mr:gr)(r,n,xe(this,"attr."+t,e)):null==e?(r.local?dr:ur)(r):(r.local?fr:pr)(r,n,e))},attrTween:function(t,e){var r="attr."+t;if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==e)return this.tween(r,null);if("function"!=typeof e)throw new Error;var n=R(t);return this.tween(r,(n.local?yr:xr)(n,e))},style:function(t,e,r){var n="transform"==(t+="")?fe:hr;return null==e?this.styleTween(t,function(t,e){var r,n,i;return function(){var a=Z(this,t),o=(this.style.removeProperty(t),Z(this,t));return a===o?null:a===r&&o===n?i:i=e(r=a,n=o)}}(t,n)).on("end.style."+t,vr(t)):"function"==typeof e?this.styleTween(t,function(t,e,r){var n,i,a;return function(){var o=Z(this,t),s=r(this),l=s+"";return null==s&&(this.style.removeProperty(t),l=s=Z(this,t)),o===l?null:o===n&&l===i?a:(i=l,a=e(n=o,s))}}(t,n,xe(this,"style."+t,e))).each(function(t,e){var r,n,i,a,o="style."+e,s="end."+o;return function(){var l=oe(this,t),c=l.on,h=null==l.value[o]?a||(a=vr(e)):void 0;c===r&&i===h||(n=(r=c).copy()).on(s,i=h),l.on=n}}(this._id,t)):this.styleTween(t,function(t,e,r){var n,i,a=r+"";return function(){var o=Z(this,t);return o===a?null:o===n?i:i=e(n=o,r)}}(t,n,e),r).on("end.style."+t,null)},styleTween:function(t,e,r){var n="style."+(t+="");if(arguments.length<2)return(n=this.tween(n))&&n._value;if(null==e)return this.tween(n,null);if("function"!=typeof e)throw new Error;return this.tween(n,function(t,e,r){var n,i;function a(){var a=e.apply(this,arguments);return a!==i&&(n=(i=a)&&function(t,e,r){return function(n){this.style.setProperty(t,e.call(this,n),r)}}(t,a,r)),n}return a._value=e,a}(t,e,null==r?"":r))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var e=t(this);this.textContent=null==e?"":e}}(xe(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var e="text";if(arguments.length<1)return(e=this.tween(e))&&e._value;if(null==t)return this.tween(e,null);if("function"!=typeof t)throw new Error;return this.tween(e,function(t){var e,r;function n(){var n=t.apply(this,arguments);return n!==r&&(e=(r=n)&&function(t){return function(e){this.textContent=t.call(this,e)}}(n)),e}return n._value=t,n}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var e=this.parentNode;for(var r in this.__transition)if(+r!==t)return;e&&e.removeChild(this)}}(this._id))},tween:function(t,e){var r=this._id;if(t+="",arguments.length<2){for(var n,i=se(this.node(),r).tween,a=0,o=i.length;a<o;++a)if((n=i[a]).name===t)return n.value;return null}return this.each((null==e?me:ye)(r,t,e))},delay:function(t){var e=this._id;return arguments.length?this.each(("function"==typeof t?br:kr)(e,t)):se(this.node(),e).delay},duration:function(t){var e=this._id;return arguments.length?this.each(("function"==typeof t?Cr:wr)(e,t)):se(this.node(),e).duration},ease:function(t){var e=this._id;return arguments.length?this.each(function(t,e){if("function"!=typeof e)throw new Error;return function(){oe(this,t).ease=e}}(e,t)):se(this.node(),e).ease},easeVarying:function(t){if("function"!=typeof t)throw new Error;return this.each(function(t,e){return function(){var r=e.apply(this,arguments);if("function"!=typeof r)throw new Error;oe(this,t).ease=r}}(this._id,t))},end:function(){var t,e,r=this,n=r._id,i=r.size();return new Promise((function(a,o){var s={value:o},l={value:function(){0==--i&&a()}};r.each((function(){var r=oe(this,n),i=r.on;i!==t&&((e=(t=i).copy())._.cancel.push(s),e._.interrupt.push(s),e._.end.push(l)),r.on=e})),0===i&&a()}))},[Symbol.iterator]:Mr[Symbol.iterator]};var Br={time:null,delay:0,duration:250,ease:function(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}};function Lr(t,e){for(var r;!(r=t.__transition)||!(r=r[e]);)if(!(t=t.parentNode))throw new Error(`transition ${e} not found`);return r}Ft.prototype.interrupt=function(t){return this.each((function(){!function(t,e){var r,n,i,a=t.__transition,o=!0;if(a){for(i in e=null==e?null:e+"",a)(r=a[i]).name===e?(n=r.state>2&&r.state<5,r.state=6,r.timer.stop(),r.on.call(n?"interrupt":"cancel",t,t.__data__,r.index,r.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},Ft.prototype.transition=function(t){var e,r;t instanceof Ar?(e=t._id,t=t._name):(e=Tr(),(r=Br).time=Vt(),t=null==t?null:t+"");for(var n=this._groups,i=n.length,a=0;a<i;++a)for(var o,s=n[a],l=s.length,c=0;c<l;++c)(o=s[c])&&ie(o,t,e,c,s,r||Lr(o,e));return new Ar(n,this._parents,t,e)};const{abs:Fr,max:$r,min:Er}=Math;function Nr(t){return[+t[0],+t[1]]}function Dr(t){return[Nr(t[0]),Nr(t[1])]}["w","e"].map(jr),["n","s"].map(jr),["n","w","e","s","nw","ne","sw","se"].map(jr);function jr(t){return{type:t}}const Ir=Math.PI/180,Or=180/Math.PI,Rr=.96422,Pr=.82521,zr=4/29,Kr=6/29,qr=3*Kr*Kr,Wr=Kr*Kr*Kr;function Hr(t){if(t instanceof Ur)return new Ur(t.l,t.a,t.b,t.opacity);if(t instanceof Jr)return tn(t);t instanceof Ke||(t=Pe(t));var e,r,n=Zr(t.r),i=Zr(t.g),a=Zr(t.b),o=Yr((.2225045*n+.7168786*i+.0606169*a)/1);return n===i&&i===a?e=r=o:(e=Yr((.4360747*n+.3850649*i+.1430804*a)/Rr),r=Yr((.0139322*n+.0971045*i+.7141733*a)/Pr)),new Ur(116*o-16,500*(e-o),200*(o-r),t.opacity)}function Ur(t,e,r,n){this.l=+t,this.a=+e,this.b=+r,this.opacity=+n}function Yr(t){return t>Wr?Math.pow(t,1/3):t/qr+zr}function Vr(t){return t>Kr?t*t*t:qr*(t-zr)}function Gr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Zr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Xr(t){if(t instanceof Jr)return new Jr(t.h,t.c,t.l,t.opacity);if(t instanceof Ur||(t=Hr(t)),0===t.a&&0===t.b)return new Jr(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var e=Math.atan2(t.b,t.a)*Or;return new Jr(e<0?e+360:e,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Qr(t,e,r,n){return 1===arguments.length?Xr(t):new Jr(t,e,r,null==n?1:n)}function Jr(t,e,r,n){this.h=+t,this.c=+e,this.l=+r,this.opacity=+n}function tn(t){if(isNaN(t.h))return new Ur(t.l,0,0,t.opacity);var e=t.h*Ir;return new Ur(t.l,Math.cos(e)*t.c,Math.sin(e)*t.c,t.opacity)}function en(t){return function(e,r){var n=t((e=Qr(e)).h,(r=Qr(r)).h),i=ir(e.c,r.c),a=ir(e.l,r.l),o=ir(e.opacity,r.opacity);return function(t){return e.h=n(t),e.c=i(t),e.l=a(t),e.opacity=o(t),e+""}}}be(Ur,(function(t,e,r,n){return 1===arguments.length?Hr(t):new Ur(t,e,r,null==n?1:n)}),ke(Ce,{brighter(t){return new Ur(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker(t){return new Ur(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,e=isNaN(this.a)?t:t+this.a/500,r=isNaN(this.b)?t:t-this.b/200;return new Ke(Gr(3.1338561*(e=Rr*Vr(e))-1.6168667*(t=1*Vr(t))-.4906146*(r=Pr*Vr(r))),Gr(-.9787684*e+1.9161415*t+.033454*r),Gr(.0719453*e-.2289914*t+1.4052427*r),this.opacity)}})),be(Jr,Qr,ke(Ce,{brighter(t){return new Jr(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker(t){return new Jr(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb(){return tn(this).rgb()}}));const rn=en((function(t,e){var r=e-t;return r?rr(t,r>180||r<-180?r-360*Math.round(r/360):r):er(isNaN(t)?e:t)}));en(ir);function nn(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t)}return this}class an extends Map{constructor(t,e=cn){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:e}}),null!=t)for(const[r,n]of t)this.set(r,n)}get(t){return super.get(on(this,t))}has(t){return super.has(on(this,t))}set(t,e){return super.set(sn(this,t),e)}delete(t){return super.delete(ln(this,t))}}Set;function on({_intern:t,_key:e},r){const n=e(r);return t.has(n)?t.get(n):r}function sn({_intern:t,_key:e},r){const n=e(r);return t.has(n)?t.get(n):(t.set(n,r),r)}function ln({_intern:t,_key:e},r){const n=e(r);return t.has(n)&&(r=t.get(n),t.delete(n)),r}function cn(t){return null!==t&&"object"==typeof t?t.valueOf():t}const hn=Symbol("implicit");function un(){var t=new an,e=[],r=[],n=hn;function i(i){let a=t.get(i);if(void 0===a){if(n!==hn)return n;t.set(i,a=e.push(i)-1)}return r[a%r.length]}return i.domain=function(r){if(!arguments.length)return e.slice();e=[],t=new an;for(const n of r)t.has(n)||t.set(n,e.push(n)-1);return i},i.range=function(t){return arguments.length?(r=Array.from(t),i):r.slice()},i.unknown=function(t){return arguments.length?(n=t,i):n},i.copy=function(){return un(e,r).unknown(n)},nn.apply(i,arguments),i}function dn(){var t,e,r=un().unknown(void 0),n=r.domain,i=r.range,a=0,o=1,s=!1,l=0,c=0,h=.5;function u(){var r=n().length,u=o<a,d=u?o:a,p=u?a:o;t=(p-d)/Math.max(1,r-l+2*c),s&&(t=Math.floor(t)),d+=(p-d-t*(r-l))*h,e=t*(1-l),s&&(d=Math.round(d),e=Math.round(e));var f=function(t,e,r){t=+t,e=+e,r=(i=arguments.length)<2?(e=t,t=0,1):i<3?1:+r;for(var n=-1,i=0|Math.max(0,Math.ceil((e-t)/r)),a=new Array(i);++n<i;)a[n]=t+n*r;return a}(r).map((function(e){return d+t*e}));return i(u?f.reverse():f)}return delete r.unknown,r.domain=function(t){return arguments.length?(n(t),u()):n()},r.range=function(t){return arguments.length?([a,o]=t,a=+a,o=+o,u()):[a,o]},r.rangeRound=function(t){return[a,o]=t,a=+a,o=+o,s=!0,u()},r.bandwidth=function(){return e},r.step=function(){return t},r.round=function(t){return arguments.length?(s=!!t,u()):s},r.padding=function(t){return arguments.length?(l=Math.min(1,c=+t),u()):l},r.paddingInner=function(t){return arguments.length?(l=Math.min(1,t),u()):l},r.paddingOuter=function(t){return arguments.length?(c=+t,u()):c},r.align=function(t){return arguments.length?(h=Math.max(0,Math.min(1,t)),u()):h},r.copy=function(){return dn(n(),[a,o]).round(s).paddingInner(l).paddingOuter(c).align(h)},nn.apply(u(),arguments)}const pn=Math.sqrt(50),fn=Math.sqrt(10),gn=Math.sqrt(2);function mn(t,e,r){const n=(e-t)/Math.max(0,r),i=Math.floor(Math.log10(n)),a=n/Math.pow(10,i),o=a>=pn?10:a>=fn?5:a>=gn?2:1;let s,l,c;return i<0?(c=Math.pow(10,-i)/o,s=Math.round(t*c),l=Math.round(e*c),s/c<t&&++s,l/c>e&&--l,c=-c):(c=Math.pow(10,i)*o,s=Math.round(t/c),l=Math.round(e/c),s*c<t&&++s,l*c>e&&--l),l<s&&.5<=r&&r<2?mn(t,e,2*r):[s,l,c]}function yn(t,e,r){return mn(t=+t,e=+e,r=+r)[2]}function xn(t,e,r){r=+r;const n=(e=+e)<(t=+t),i=n?yn(e,t,r):yn(t,e,r);return(n?-1:1)*(i<0?1/-i:i)}function bn(t,e){return null==t||null==e?NaN:t<e?-1:t>e?1:t>=e?0:NaN}function kn(t,e){return null==t||null==e?NaN:e<t?-1:e>t?1:e>=t?0:NaN}function Cn(t){let e,r,n;function i(t,n,i=0,a=t.length){if(i<a){if(0!==e(n,n))return a;do{const e=i+a>>>1;r(t[e],n)<0?i=e+1:a=e}while(i<a)}return i}return 2!==t.length?(e=bn,r=(e,r)=>bn(t(e),r),n=(e,r)=>t(e)-r):(e=t===bn||t===kn?t:wn,r=t,n=t),{left:i,center:function(t,e,r=0,a=t.length){const o=i(t,e,r,a-1);return o>r&&n(t[o-1],e)>-n(t[o],e)?o-1:o},right:function(t,n,i=0,a=t.length){if(i<a){if(0!==e(n,n))return a;do{const e=i+a>>>1;r(t[e],n)<=0?i=e+1:a=e}while(i<a)}return i}}}function wn(){return 0}const _n=Cn(bn),vn=_n.right,Sn=(_n.left,Cn((function(t){return null===t?NaN:+t})).center,vn);function An(t,e){var r,n=e?e.length:0,i=t?Math.min(n,t.length):0,a=new Array(i),o=new Array(n);for(r=0;r<i;++r)a[r]=Ln(t[r],e[r]);for(;r<n;++r)o[r]=e[r];return function(t){for(r=0;r<i;++r)o[r]=a[r](t);return o}}function Tn(t,e){var r=new Date;return t=+t,e=+e,function(n){return r.setTime(t*(1-n)+e*n),r}}function Mn(t,e){var r,n={},i={};for(r in null!==t&&"object"==typeof t||(t={}),null!==e&&"object"==typeof e||(e={}),e)r in t?n[r]=Ln(t[r],e[r]):i[r]=e[r];return function(t){for(r in n)i[r]=n[r](t);return i}}function Bn(t,e){e||(e=[]);var r,n=t?Math.min(e.length,t.length):0,i=e.slice();return function(a){for(r=0;r<n;++r)i[r]=t[r]*(1-a)+e[r]*a;return i}}function Ln(t,e){var r,n,i=typeof e;return null==e||"boolean"===i?er(e):("number"===i?le:"string"===i?(r=Ie(e))?(e=r,ar):cr:e instanceof Ie?ar:e instanceof Date?Tn:(n=e,!ArrayBuffer.isView(n)||n instanceof DataView?Array.isArray(e)?An:"function"!=typeof e.valueOf&&"function"!=typeof e.toString||isNaN(e)?Mn:le:Bn))(t,e)}function Fn(t,e){return t=+t,e=+e,function(r){return Math.round(t*(1-r)+e*r)}}function $n(t){return+t}var En=[0,1];function Nn(t){return t}function Dn(t,e){return(e-=t=+t)?function(r){return(r-t)/e}:(r=isNaN(e)?NaN:.5,function(){return r});var r}function jn(t,e,r){var n=t[0],i=t[1],a=e[0],o=e[1];return i<n?(n=Dn(i,n),a=r(o,a)):(n=Dn(n,i),a=r(a,o)),function(t){return a(n(t))}}function In(t,e,r){var n=Math.min(t.length,e.length)-1,i=new Array(n),a=new Array(n),o=-1;for(t[n]<t[0]&&(t=t.slice().reverse(),e=e.slice().reverse());++o<n;)i[o]=Dn(t[o],t[o+1]),a[o]=r(e[o],e[o+1]);return function(e){var r=Sn(t,e,1,n)-1;return a[r](i[r](e))}}function On(t,e){return e.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Rn(){var t,e,r,n,i,a,o=En,s=En,l=Ln,c=Nn;function h(){var t,e,r,l=Math.min(o.length,s.length);return c!==Nn&&(t=o[0],e=o[l-1],t>e&&(r=t,t=e,e=r),c=function(r){return Math.max(t,Math.min(e,r))}),n=l>2?In:jn,i=a=null,u}function u(e){return null==e||isNaN(e=+e)?r:(i||(i=n(o.map(t),s,l)))(t(c(e)))}return u.invert=function(r){return c(e((a||(a=n(s,o.map(t),le)))(r)))},u.domain=function(t){return arguments.length?(o=Array.from(t,$n),h()):o.slice()},u.range=function(t){return arguments.length?(s=Array.from(t),h()):s.slice()},u.rangeRound=function(t){return s=Array.from(t),l=Fn,h()},u.clamp=function(t){return arguments.length?(c=!!t||Nn,h()):c!==Nn},u.interpolate=function(t){return arguments.length?(l=t,h()):l},u.unknown=function(t){return arguments.length?(r=t,u):r},function(r,n){return t=r,e=n,h()}}function Pn(){return Rn()(Nn,Nn)}var zn,Kn=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function qn(t){if(!(e=Kn.exec(t)))throw new Error("invalid format: "+t);var e;return new Wn({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function Wn(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Hn(t,e){if((r=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var r,n=t.slice(0,r);return[n.length>1?n[0]+n.slice(2):n,+t.slice(r+1)]}function Un(t){return(t=Hn(Math.abs(t)))?t[1]:NaN}function Yn(t,e){var r=Hn(t,e);if(!r)return t+"";var n=r[0],i=r[1];return i<0?"0."+new Array(-i).join("0")+n:n.length>i+1?n.slice(0,i+1)+"."+n.slice(i+1):n+new Array(i-n.length+2).join("0")}qn.prototype=Wn.prototype,Wn.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const Vn={"%":(t,e)=>(100*t).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>Yn(100*t,e),r:Yn,s:function(t,e){var r=Hn(t,e);if(!r)return t+"";var n=r[0],i=r[1],a=i-(zn=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,o=n.length;return a===o?n:a>o?n+new Array(a-o+1).join("0"):a>0?n.slice(0,a)+"."+n.slice(a):"0."+new Array(1-a).join("0")+Hn(t,Math.max(0,e+a-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function Gn(t){return t}var Zn,Xn,Qn,Jn=Array.prototype.map,ti=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"];function ei(t){var e,r,n=void 0===t.grouping||void 0===t.thousands?Gn:(e=Jn.call(t.grouping,Number),r=t.thousands+"",function(t,n){for(var i=t.length,a=[],o=0,s=e[0],l=0;i>0&&s>0&&(l+s+1>n&&(s=Math.max(1,n-l)),a.push(t.substring(i-=s,i+s)),!((l+=s+1)>n));)s=e[o=(o+1)%e.length];return a.reverse().join(r)}),i=void 0===t.currency?"":t.currency[0]+"",a=void 0===t.currency?"":t.currency[1]+"",o=void 0===t.decimal?".":t.decimal+"",s=void 0===t.numerals?Gn:function(t){return function(e){return e.replace(/[0-9]/g,(function(e){return t[+e]}))}}(Jn.call(t.numerals,String)),l=void 0===t.percent?"%":t.percent+"",c=void 0===t.minus?"\u2212":t.minus+"",h=void 0===t.nan?"NaN":t.nan+"";function u(t){var e=(t=qn(t)).fill,r=t.align,u=t.sign,d=t.symbol,p=t.zero,f=t.width,g=t.comma,m=t.precision,y=t.trim,x=t.type;"n"===x?(g=!0,x="g"):Vn[x]||(void 0===m&&(m=12),y=!0,x="g"),(p||"0"===e&&"="===r)&&(p=!0,e="0",r="=");var b="$"===d?i:"#"===d&&/[boxX]/.test(x)?"0"+x.toLowerCase():"",k="$"===d?a:/[%p]/.test(x)?l:"",C=Vn[x],w=/[defgprs%]/.test(x);function _(t){var i,a,l,d=b,_=k;if("c"===x)_=C(t)+_,t="";else{var v=(t=+t)<0||1/t<0;if(t=isNaN(t)?h:C(Math.abs(t),m),y&&(t=function(t){t:for(var e,r=t.length,n=1,i=-1;n<r;++n)switch(t[n]){case".":i=e=n;break;case"0":0===i&&(i=n),e=n;break;default:if(!+t[n])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),v&&0==+t&&"+"!==u&&(v=!1),d=(v?"("===u?u:c:"-"===u||"("===u?"":u)+d,_=("s"===x?ti[8+zn/3]:"")+_+(v&&"("===u?")":""),w)for(i=-1,a=t.length;++i<a;)if(48>(l=t.charCodeAt(i))||l>57){_=(46===l?o+t.slice(i+1):t.slice(i))+_,t=t.slice(0,i);break}}g&&!p&&(t=n(t,1/0));var S=d.length+t.length+_.length,A=S<f?new Array(f-S+1).join(e):"";switch(g&&p&&(t=n(A+t,A.length?f-_.length:1/0),A=""),r){case"<":t=d+t+_+A;break;case"=":t=d+A+t+_;break;case"^":t=A.slice(0,S=A.length>>1)+d+t+_+A.slice(S);break;default:t=A+d+t+_}return s(t)}return m=void 0===m?6:/[gprs]/.test(x)?Math.max(1,Math.min(21,m)):Math.max(0,Math.min(20,m)),_.toString=function(){return t+""},_}return{format:u,formatPrefix:function(t,e){var r=u(((t=qn(t)).type="f",t)),n=3*Math.max(-8,Math.min(8,Math.floor(Un(e)/3))),i=Math.pow(10,-n),a=ti[8+n/3];return function(t){return r(i*t)+a}}}}function ri(t,e,r,n){var i,a=xn(t,e,r);switch((n=qn(null==n?",f":n)).type){case"s":var o=Math.max(Math.abs(t),Math.abs(e));return null!=n.precision||isNaN(i=function(t,e){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Un(e)/3)))-Un(Math.abs(t)))}(a,o))||(n.precision=i),Qn(n,o);case"":case"e":case"g":case"p":case"r":null!=n.precision||isNaN(i=function(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,Un(e)-Un(t))+1}(a,Math.max(Math.abs(t),Math.abs(e))))||(n.precision=i-("e"===n.type));break;case"f":case"%":null!=n.precision||isNaN(i=function(t){return Math.max(0,-Un(Math.abs(t)))}(a))||(n.precision=i-2*("%"===n.type))}return Xn(n)}function ni(t){var e=t.domain;return t.ticks=function(t){var r=e();return function(t,e,r){if(!((r=+r)>0))return[];if((t=+t)==(e=+e))return[t];const n=e<t,[i,a,o]=n?mn(e,t,r):mn(t,e,r);if(!(a>=i))return[];const s=a-i+1,l=new Array(s);if(n)if(o<0)for(let c=0;c<s;++c)l[c]=(a-c)/-o;else for(let c=0;c<s;++c)l[c]=(a-c)*o;else if(o<0)for(let c=0;c<s;++c)l[c]=(i+c)/-o;else for(let c=0;c<s;++c)l[c]=(i+c)*o;return l}(r[0],r[r.length-1],null==t?10:t)},t.tickFormat=function(t,r){var n=e();return ri(n[0],n[n.length-1],null==t?10:t,r)},t.nice=function(r){null==r&&(r=10);var n,i,a=e(),o=0,s=a.length-1,l=a[o],c=a[s],h=10;for(c<l&&(i=l,l=c,c=i,i=o,o=s,s=i);h-- >0;){if((i=yn(l,c,r))===n)return a[o]=l,a[s]=c,e(a);if(i>0)l=Math.floor(l/i)*i,c=Math.ceil(c/i)*i;else{if(!(i<0))break;l=Math.ceil(l*i)/i,c=Math.floor(c*i)/i}n=i}return t},t}function ii(){var t=Pn();return t.copy=function(){return On(t,ii())},nn.apply(t,arguments),ni(t)}Zn=ei({thousands:",",grouping:[3],currency:["$",""]}),Xn=Zn.format,Qn=Zn.formatPrefix;const ai=1e3,oi=6e4,si=36e5,li=864e5,ci=6048e5,hi=2592e6,ui=31536e6,di=new Date,pi=new Date;function fi(t,e,r,n){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=e=>(t(e=new Date(+e)),e),i.ceil=r=>(t(r=new Date(r-1)),e(r,1),t(r),r),i.round=t=>{const e=i(t),r=i.ceil(t);return t-e<r-t?e:r},i.offset=(t,r)=>(e(t=new Date(+t),null==r?1:Math.floor(r)),t),i.range=(r,n,a)=>{const o=[];if(r=i.ceil(r),a=null==a?1:Math.floor(a),!(r<n&&a>0))return o;let s;do{o.push(s=new Date(+r)),e(r,a),t(r)}while(s<r&&r<n);return o},i.filter=r=>fi((e=>{if(e>=e)for(;t(e),!r(e);)e.setTime(e-1)}),((t,n)=>{if(t>=t)if(n<0)for(;++n<=0;)for(;e(t,-1),!r(t););else for(;--n>=0;)for(;e(t,1),!r(t););})),r&&(i.count=(e,n)=>(di.setTime(+e),pi.setTime(+n),t(di),t(pi),Math.floor(r(di,pi))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(n?e=>n(e)%t==0:e=>i.count(0,e)%t==0):i:null)),i}const gi=fi((()=>{}),((t,e)=>{t.setTime(+t+e)}),((t,e)=>e-t));gi.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?fi((e=>{e.setTime(Math.floor(e/t)*t)}),((e,r)=>{e.setTime(+e+r*t)}),((e,r)=>(r-e)/t)):gi:null);gi.range;const mi=fi((t=>{t.setTime(t-t.getMilliseconds())}),((t,e)=>{t.setTime(+t+e*ai)}),((t,e)=>(e-t)/ai),(t=>t.getUTCSeconds())),yi=(mi.range,fi((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*ai)}),((t,e)=>{t.setTime(+t+e*oi)}),((t,e)=>(e-t)/oi),(t=>t.getMinutes()))),xi=(yi.range,fi((t=>{t.setUTCSeconds(0,0)}),((t,e)=>{t.setTime(+t+e*oi)}),((t,e)=>(e-t)/oi),(t=>t.getUTCMinutes()))),bi=(xi.range,fi((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*ai-t.getMinutes()*oi)}),((t,e)=>{t.setTime(+t+e*si)}),((t,e)=>(e-t)/si),(t=>t.getHours()))),ki=(bi.range,fi((t=>{t.setUTCMinutes(0,0,0)}),((t,e)=>{t.setTime(+t+e*si)}),((t,e)=>(e-t)/si),(t=>t.getUTCHours()))),Ci=(ki.range,fi((t=>t.setHours(0,0,0,0)),((t,e)=>t.setDate(t.getDate()+e)),((t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*oi)/li),(t=>t.getDate()-1))),wi=(Ci.range,fi((t=>{t.setUTCHours(0,0,0,0)}),((t,e)=>{t.setUTCDate(t.getUTCDate()+e)}),((t,e)=>(e-t)/li),(t=>t.getUTCDate()-1))),_i=(wi.range,fi((t=>{t.setUTCHours(0,0,0,0)}),((t,e)=>{t.setUTCDate(t.getUTCDate()+e)}),((t,e)=>(e-t)/li),(t=>Math.floor(t/li))));_i.range;function vi(t){return fi((e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),((t,e)=>{t.setDate(t.getDate()+7*e)}),((t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*oi)/ci))}const Si=vi(0),Ai=vi(1),Ti=vi(2),Mi=vi(3),Bi=vi(4),Li=vi(5),Fi=vi(6);Si.range,Ai.range,Ti.range,Mi.range,Bi.range,Li.range,Fi.range;function $i(t){return fi((e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),((t,e)=>{t.setUTCDate(t.getUTCDate()+7*e)}),((t,e)=>(e-t)/ci))}const Ei=$i(0),Ni=$i(1),Di=$i(2),ji=$i(3),Ii=$i(4),Oi=$i(5),Ri=$i(6),Pi=(Ei.range,Ni.range,Di.range,ji.range,Ii.range,Oi.range,Ri.range,fi((t=>{t.setDate(1),t.setHours(0,0,0,0)}),((t,e)=>{t.setMonth(t.getMonth()+e)}),((t,e)=>e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear())),(t=>t.getMonth()))),zi=(Pi.range,fi((t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),((t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)}),((t,e)=>e.getUTCMonth()-t.getUTCMonth()+12*(e.getUTCFullYear()-t.getUTCFullYear())),(t=>t.getUTCMonth()))),Ki=(zi.range,fi((t=>{t.setMonth(0,1),t.setHours(0,0,0,0)}),((t,e)=>{t.setFullYear(t.getFullYear()+e)}),((t,e)=>e.getFullYear()-t.getFullYear()),(t=>t.getFullYear())));Ki.every=t=>isFinite(t=Math.floor(t))&&t>0?fi((e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),((e,r)=>{e.setFullYear(e.getFullYear()+r*t)})):null;Ki.range;const qi=fi((t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),((t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)}),((t,e)=>e.getUTCFullYear()-t.getUTCFullYear()),(t=>t.getUTCFullYear()));qi.every=t=>isFinite(t=Math.floor(t))&&t>0?fi((e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),((e,r)=>{e.setUTCFullYear(e.getUTCFullYear()+r*t)})):null;qi.range;function Wi(t,e,r,n,i,a){const o=[[mi,1,ai],[mi,5,5e3],[mi,15,15e3],[mi,30,3e4],[a,1,oi],[a,5,3e5],[a,15,9e5],[a,30,18e5],[i,1,si],[i,3,108e5],[i,6,216e5],[i,12,432e5],[n,1,li],[n,2,1728e5],[r,1,ci],[e,1,hi],[e,3,7776e6],[t,1,ui]];function s(e,r,n){const i=Math.abs(r-e)/n,a=Cn((([,,t])=>t)).right(o,i);if(a===o.length)return t.every(xn(e/ui,r/ui,n));if(0===a)return gi.every(Math.max(xn(e,r,n),1));const[s,l]=o[i/o[a-1][2]<o[a][2]/i?a-1:a];return s.every(l)}return[function(t,e,r){const n=e<t;n&&([t,e]=[e,t]);const i=r&&"function"==typeof r.range?r:s(t,e,r),a=i?i.range(t,+e+1):[];return n?a.reverse():a},s]}const[Hi,Ui]=Wi(qi,zi,Ei,_i,ki,xi),[Yi,Vi]=Wi(Ki,Pi,Si,Ci,bi,yi);function Gi(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Zi(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Xi(t,e,r){return{y:t,m:e,d:r,H:0,M:0,S:0,L:0}}var Qi,Ji,ta={"-":"",_:" ",0:"0"},ea=/^\s*\d+/,ra=/^%/,na=/[\\^$*+?|[\]().{}]/g;function ia(t,e,r){var n=t<0?"-":"",i=(n?-t:t)+"",a=i.length;return n+(a<r?new Array(r-a+1).join(e)+i:i)}function aa(t){return t.replace(na,"\\$&")}function oa(t){return new RegExp("^(?:"+t.map(aa).join("|")+")","i")}function sa(t){return new Map(t.map(((t,e)=>[t.toLowerCase(),e])))}function la(t,e,r){var n=ea.exec(e.slice(r,r+1));return n?(t.w=+n[0],r+n[0].length):-1}function ca(t,e,r){var n=ea.exec(e.slice(r,r+1));return n?(t.u=+n[0],r+n[0].length):-1}function ha(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.U=+n[0],r+n[0].length):-1}function ua(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.V=+n[0],r+n[0].length):-1}function da(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.W=+n[0],r+n[0].length):-1}function pa(t,e,r){var n=ea.exec(e.slice(r,r+4));return n?(t.y=+n[0],r+n[0].length):-1}function fa(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.y=+n[0]+(+n[0]>68?1900:2e3),r+n[0].length):-1}function ga(t,e,r){var n=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(r,r+6));return n?(t.Z=n[1]?0:-(n[2]+(n[3]||"00")),r+n[0].length):-1}function ma(t,e,r){var n=ea.exec(e.slice(r,r+1));return n?(t.q=3*n[0]-3,r+n[0].length):-1}function ya(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.m=n[0]-1,r+n[0].length):-1}function xa(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.d=+n[0],r+n[0].length):-1}function ba(t,e,r){var n=ea.exec(e.slice(r,r+3));return n?(t.m=0,t.d=+n[0],r+n[0].length):-1}function ka(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.H=+n[0],r+n[0].length):-1}function Ca(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.M=+n[0],r+n[0].length):-1}function wa(t,e,r){var n=ea.exec(e.slice(r,r+2));return n?(t.S=+n[0],r+n[0].length):-1}function _a(t,e,r){var n=ea.exec(e.slice(r,r+3));return n?(t.L=+n[0],r+n[0].length):-1}function va(t,e,r){var n=ea.exec(e.slice(r,r+6));return n?(t.L=Math.floor(n[0]/1e3),r+n[0].length):-1}function Sa(t,e,r){var n=ra.exec(e.slice(r,r+1));return n?r+n[0].length:-1}function Aa(t,e,r){var n=ea.exec(e.slice(r));return n?(t.Q=+n[0],r+n[0].length):-1}function Ta(t,e,r){var n=ea.exec(e.slice(r));return n?(t.s=+n[0],r+n[0].length):-1}function Ma(t,e){return ia(t.getDate(),e,2)}function Ba(t,e){return ia(t.getHours(),e,2)}function La(t,e){return ia(t.getHours()%12||12,e,2)}function Fa(t,e){return ia(1+Ci.count(Ki(t),t),e,3)}function $a(t,e){return ia(t.getMilliseconds(),e,3)}function Ea(t,e){return $a(t,e)+"000"}function Na(t,e){return ia(t.getMonth()+1,e,2)}function Da(t,e){return ia(t.getMinutes(),e,2)}function ja(t,e){return ia(t.getSeconds(),e,2)}function Ia(t){var e=t.getDay();return 0===e?7:e}function Oa(t,e){return ia(Si.count(Ki(t)-1,t),e,2)}function Ra(t){var e=t.getDay();return e>=4||0===e?Bi(t):Bi.ceil(t)}function Pa(t,e){return t=Ra(t),ia(Bi.count(Ki(t),t)+(4===Ki(t).getDay()),e,2)}function za(t){return t.getDay()}function Ka(t,e){return ia(Ai.count(Ki(t)-1,t),e,2)}function qa(t,e){return ia(t.getFullYear()%100,e,2)}function Wa(t,e){return ia((t=Ra(t)).getFullYear()%100,e,2)}function Ha(t,e){return ia(t.getFullYear()%1e4,e,4)}function Ua(t,e){var r=t.getDay();return ia((t=r>=4||0===r?Bi(t):Bi.ceil(t)).getFullYear()%1e4,e,4)}function Ya(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+ia(e/60|0,"0",2)+ia(e%60,"0",2)}function Va(t,e){return ia(t.getUTCDate(),e,2)}function Ga(t,e){return ia(t.getUTCHours(),e,2)}function Za(t,e){return ia(t.getUTCHours()%12||12,e,2)}function Xa(t,e){return ia(1+wi.count(qi(t),t),e,3)}function Qa(t,e){return ia(t.getUTCMilliseconds(),e,3)}function Ja(t,e){return Qa(t,e)+"000"}function to(t,e){return ia(t.getUTCMonth()+1,e,2)}function eo(t,e){return ia(t.getUTCMinutes(),e,2)}function ro(t,e){return ia(t.getUTCSeconds(),e,2)}function no(t){var e=t.getUTCDay();return 0===e?7:e}function io(t,e){return ia(Ei.count(qi(t)-1,t),e,2)}function ao(t){var e=t.getUTCDay();return e>=4||0===e?Ii(t):Ii.ceil(t)}function oo(t,e){return t=ao(t),ia(Ii.count(qi(t),t)+(4===qi(t).getUTCDay()),e,2)}function so(t){return t.getUTCDay()}function lo(t,e){return ia(Ni.count(qi(t)-1,t),e,2)}function co(t,e){return ia(t.getUTCFullYear()%100,e,2)}function ho(t,e){return ia((t=ao(t)).getUTCFullYear()%100,e,2)}function uo(t,e){return ia(t.getUTCFullYear()%1e4,e,4)}function po(t,e){var r=t.getUTCDay();return ia((t=r>=4||0===r?Ii(t):Ii.ceil(t)).getUTCFullYear()%1e4,e,4)}function fo(){return"+0000"}function go(){return"%"}function mo(t){return+t}function yo(t){return Math.floor(+t/1e3)}function xo(t){return new Date(t)}function bo(t){return t instanceof Date?+t:+new Date(+t)}function ko(t,e,r,n,i,a,o,s,l,c){var h=Pn(),u=h.invert,d=h.domain,p=c(".%L"),f=c(":%S"),g=c("%I:%M"),m=c("%I %p"),y=c("%a %d"),x=c("%b %d"),b=c("%B"),k=c("%Y");function C(t){return(l(t)<t?p:s(t)<t?f:o(t)<t?g:a(t)<t?m:n(t)<t?i(t)<t?y:x:r(t)<t?b:k)(t)}return h.invert=function(t){return new Date(u(t))},h.domain=function(t){return arguments.length?d(Array.from(t,bo)):d().map(xo)},h.ticks=function(e){var r=d();return t(r[0],r[r.length-1],null==e?10:e)},h.tickFormat=function(t,e){return null==e?C:c(e)},h.nice=function(t){var r=d();return t&&"function"==typeof t.range||(t=e(r[0],r[r.length-1],null==t?10:t)),t?d(function(t,e){var r,n=0,i=(t=t.slice()).length-1,a=t[n],o=t[i];return o<a&&(r=n,n=i,i=r,r=a,a=o,o=r),t[n]=e.floor(a),t[i]=e.ceil(o),t}(r,t)):h},h.copy=function(){return On(h,ko(t,e,r,n,i,a,o,s,l,c))},h}function Co(){return nn.apply(ko(Yi,Vi,Ki,Pi,Si,Ci,bi,yi,mi,Ji).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)}!function(t){Qi=function(t){var e=t.dateTime,r=t.date,n=t.time,i=t.periods,a=t.days,o=t.shortDays,s=t.months,l=t.shortMonths,c=oa(i),h=sa(i),u=oa(a),d=sa(a),p=oa(o),f=sa(o),g=oa(s),m=sa(s),y=oa(l),x=sa(l),b={a:function(t){return o[t.getDay()]},A:function(t){return a[t.getDay()]},b:function(t){return l[t.getMonth()]},B:function(t){return s[t.getMonth()]},c:null,d:Ma,e:Ma,f:Ea,g:Wa,G:Ua,H:Ba,I:La,j:Fa,L:$a,m:Na,M:Da,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:mo,s:yo,S:ja,u:Ia,U:Oa,V:Pa,w:za,W:Ka,x:null,X:null,y:qa,Y:Ha,Z:Ya,"%":go},k={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:Va,e:Va,f:Ja,g:ho,G:po,H:Ga,I:Za,j:Xa,L:Qa,m:to,M:eo,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:mo,s:yo,S:ro,u:no,U:io,V:oo,w:so,W:lo,x:null,X:null,y:co,Y:uo,Z:fo,"%":go},C={a:function(t,e,r){var n=p.exec(e.slice(r));return n?(t.w=f.get(n[0].toLowerCase()),r+n[0].length):-1},A:function(t,e,r){var n=u.exec(e.slice(r));return n?(t.w=d.get(n[0].toLowerCase()),r+n[0].length):-1},b:function(t,e,r){var n=y.exec(e.slice(r));return n?(t.m=x.get(n[0].toLowerCase()),r+n[0].length):-1},B:function(t,e,r){var n=g.exec(e.slice(r));return n?(t.m=m.get(n[0].toLowerCase()),r+n[0].length):-1},c:function(t,r,n){return v(t,e,r,n)},d:xa,e:xa,f:va,g:fa,G:pa,H:ka,I:ka,j:ba,L:_a,m:ya,M:Ca,p:function(t,e,r){var n=c.exec(e.slice(r));return n?(t.p=h.get(n[0].toLowerCase()),r+n[0].length):-1},q:ma,Q:Aa,s:Ta,S:wa,u:ca,U:ha,V:ua,w:la,W:da,x:function(t,e,n){return v(t,r,e,n)},X:function(t,e,r){return v(t,n,e,r)},y:fa,Y:pa,Z:ga,"%":Sa};function w(t,e){return function(r){var n,i,a,o=[],s=-1,l=0,c=t.length;for(r instanceof Date||(r=new Date(+r));++s<c;)37===t.charCodeAt(s)&&(o.push(t.slice(l,s)),null!=(i=ta[n=t.charAt(++s)])?n=t.charAt(++s):i="e"===n?" ":"0",(a=e[n])&&(n=a(r,i)),o.push(n),l=s+1);return o.push(t.slice(l,s)),o.join("")}}function _(t,e){return function(r){var n,i,a=Xi(1900,void 0,1);if(v(a,t,r+="",0)!=r.length)return null;if("Q"in a)return new Date(a.Q);if("s"in a)return new Date(1e3*a.s+("L"in a?a.L:0));if(e&&!("Z"in a)&&(a.Z=0),"p"in a&&(a.H=a.H%12+12*a.p),void 0===a.m&&(a.m="q"in a?a.q:0),"V"in a){if(a.V<1||a.V>53)return null;"w"in a||(a.w=1),"Z"in a?(i=(n=Zi(Xi(a.y,0,1))).getUTCDay(),n=i>4||0===i?Ni.ceil(n):Ni(n),n=wi.offset(n,7*(a.V-1)),a.y=n.getUTCFullYear(),a.m=n.getUTCMonth(),a.d=n.getUTCDate()+(a.w+6)%7):(i=(n=Gi(Xi(a.y,0,1))).getDay(),n=i>4||0===i?Ai.ceil(n):Ai(n),n=Ci.offset(n,7*(a.V-1)),a.y=n.getFullYear(),a.m=n.getMonth(),a.d=n.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?Zi(Xi(a.y,0,1)).getUTCDay():Gi(Xi(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,Zi(a)):Gi(a)}}function v(t,e,r,n){for(var i,a,o=0,s=e.length,l=r.length;o<s;){if(n>=l)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=C[i in ta?e.charAt(o++):i])||(n=a(t,r,n))<0)return-1}else if(i!=r.charCodeAt(n++))return-1}return n}return b.x=w(r,b),b.X=w(n,b),b.c=w(e,b),k.x=w(r,k),k.X=w(n,k),k.c=w(e,k),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=_(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",k);return e.toString=function(){return t},e},utcParse:function(t){var e=_(t+="",!0);return e.toString=function(){return t},e}}}(t),Ji=Qi.format,Qi.parse,Qi.utcFormat,Qi.utcParse}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});const wo=function(t){for(var e=t.length/6|0,r=new Array(e),n=0;n<e;)r[n]="#"+t.slice(6*n,6*++n);return r}("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");function _o(t){return"string"==typeof t?new Bt([[document.querySelector(t)]],[document.documentElement]):new Bt([[t]],Mt)}function vo(t){return function(){return t}}const So=Math.abs,Ao=Math.atan2,To=Math.cos,Mo=Math.max,Bo=Math.min,Lo=Math.sin,Fo=Math.sqrt,$o=1e-12,Eo=Math.PI,No=Eo/2,Do=2*Eo;function jo(t){return t>=1?No:t<=-1?-No:Math.asin(t)}const Io=Math.PI,Oo=2*Io,Ro=1e-6,Po=Oo-Ro;function zo(t){this._+=t[0];for(let e=1,r=t.length;e<r;++e)this._+=arguments[e]+t[e]}class Ko{constructor(t){this._x0=this._y0=this._x1=this._y1=null,this._="",this._append=null==t?zo:function(t){let e=Math.floor(t);if(!(e>=0))throw new Error(`invalid digits: ${t}`);if(e>15)return zo;const r=10**e;return function(t){this._+=t[0];for(let e=1,n=t.length;e<n;++e)this._+=Math.round(arguments[e]*r)/r+t[e]}}(t)}moveTo(t,e){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+e}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._append`Z`)}lineTo(t,e){this._append`L${this._x1=+t},${this._y1=+e}`}quadraticCurveTo(t,e,r,n){this._append`Q${+t},${+e},${this._x1=+r},${this._y1=+n}`}bezierCurveTo(t,e,r,n,i,a){this._append`C${+t},${+e},${+r},${+n},${this._x1=+i},${this._y1=+a}`}arcTo(t,e,r,n,i){if(t=+t,e=+e,r=+r,n=+n,(i=+i)<0)throw new Error(`negative radius: ${i}`);let a=this._x1,o=this._y1,s=r-t,l=n-e,c=a-t,h=o-e,u=c*c+h*h;if(null===this._x1)this._append`M${this._x1=t},${this._y1=e}`;else if(u>Ro)if(Math.abs(h*s-l*c)>Ro&&i){let d=r-a,p=n-o,f=s*s+l*l,g=d*d+p*p,m=Math.sqrt(f),y=Math.sqrt(u),x=i*Math.tan((Io-Math.acos((f+u-g)/(2*m*y)))/2),b=x/y,k=x/m;Math.abs(b-1)>Ro&&this._append`L${t+b*c},${e+b*h}`,this._append`A${i},${i},0,0,${+(h*d>c*p)},${this._x1=t+k*s},${this._y1=e+k*l}`}else this._append`L${this._x1=t},${this._y1=e}`;else;}arc(t,e,r,n,i,a){if(t=+t,e=+e,a=!!a,(r=+r)<0)throw new Error(`negative radius: ${r}`);let o=r*Math.cos(n),s=r*Math.sin(n),l=t+o,c=e+s,h=1^a,u=a?n-i:i-n;null===this._x1?this._append`M${l},${c}`:(Math.abs(this._x1-l)>Ro||Math.abs(this._y1-c)>Ro)&&this._append`L${l},${c}`,r&&(u<0&&(u=u%Oo+Oo),u>Po?this._append`A${r},${r},0,1,${h},${t-o},${e-s}A${r},${r},0,1,${h},${this._x1=l},${this._y1=c}`:u>Ro&&this._append`A${r},${r},0,${+(u>=Io)},${h},${this._x1=t+r*Math.cos(i)},${this._y1=e+r*Math.sin(i)}`)}rect(t,e,r,n){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+e}h${r=+r}v${+n}h${-r}Z`}toString(){return this._}}function qo(t){let e=3;return t.digits=function(r){if(!arguments.length)return e;if(null==r)e=null;else{const t=Math.floor(r);if(!(t>=0))throw new RangeError(`invalid digits: ${r}`);e=t}return t},()=>new Ko(e)}function Wo(t){return t.innerRadius}function Ho(t){return t.outerRadius}function Uo(t){return t.startAngle}function Yo(t){return t.endAngle}function Vo(t){return t&&t.padAngle}function Go(t,e,r,n,i,a,o){var s=t-r,l=e-n,c=(o?a:-a)/Fo(s*s+l*l),h=c*l,u=-c*s,d=t+h,p=e+u,f=r+h,g=n+u,m=(d+f)/2,y=(p+g)/2,x=f-d,b=g-p,k=x*x+b*b,C=i-a,w=d*g-f*p,_=(b<0?-1:1)*Fo(Mo(0,C*C*k-w*w)),v=(w*b-x*_)/k,S=(-w*x-b*_)/k,A=(w*b+x*_)/k,T=(-w*x+b*_)/k,M=v-m,B=S-y,L=A-m,F=T-y;return M*M+B*B>L*L+F*F&&(v=A,S=T),{cx:v,cy:S,x01:-h,y01:-u,x11:v*(i/C-1),y11:S*(i/C-1)}}function Zo(){var t=Wo,e=Ho,r=vo(0),n=null,i=Uo,a=Yo,o=Vo,s=null,l=qo(c);function c(){var c,h,u,d=+t.apply(this,arguments),p=+e.apply(this,arguments),f=i.apply(this,arguments)-No,g=a.apply(this,arguments)-No,m=So(g-f),y=g>f;if(s||(s=c=l()),p<d&&(h=p,p=d,d=h),p>$o)if(m>Do-$o)s.moveTo(p*To(f),p*Lo(f)),s.arc(0,0,p,f,g,!y),d>$o&&(s.moveTo(d*To(g),d*Lo(g)),s.arc(0,0,d,g,f,y));else{var x,b,k=f,C=g,w=f,_=g,v=m,S=m,A=o.apply(this,arguments)/2,T=A>$o&&(n?+n.apply(this,arguments):Fo(d*d+p*p)),M=Bo(So(p-d)/2,+r.apply(this,arguments)),B=M,L=M;if(T>$o){var F=jo(T/d*Lo(A)),$=jo(T/p*Lo(A));(v-=2*F)>$o?(w+=F*=y?1:-1,_-=F):(v=0,w=_=(f+g)/2),(S-=2*$)>$o?(k+=$*=y?1:-1,C-=$):(S=0,k=C=(f+g)/2)}var E=p*To(k),N=p*Lo(k),D=d*To(_),j=d*Lo(_);if(M>$o){var I,O=p*To(C),R=p*Lo(C),P=d*To(w),z=d*Lo(w);if(m<Eo)if(I=function(t,e,r,n,i,a,o,s){var l=r-t,c=n-e,h=o-i,u=s-a,d=u*l-h*c;if(!(d*d<$o))return[t+(d=(h*(e-a)-u*(t-i))/d)*l,e+d*c]}(E,N,P,z,O,R,D,j)){var K=E-I[0],q=N-I[1],W=O-I[0],H=R-I[1],U=1/Lo(((u=(K*W+q*H)/(Fo(K*K+q*q)*Fo(W*W+H*H)))>1?0:u<-1?Eo:Math.acos(u))/2),Y=Fo(I[0]*I[0]+I[1]*I[1]);B=Bo(M,(d-Y)/(U-1)),L=Bo(M,(p-Y)/(U+1))}else B=L=0}S>$o?L>$o?(x=Go(P,z,E,N,p,L,y),b=Go(O,R,D,j,p,L,y),s.moveTo(x.cx+x.x01,x.cy+x.y01),L<M?s.arc(x.cx,x.cy,L,Ao(x.y01,x.x01),Ao(b.y01,b.x01),!y):(s.arc(x.cx,x.cy,L,Ao(x.y01,x.x01),Ao(x.y11,x.x11),!y),s.arc(0,0,p,Ao(x.cy+x.y11,x.cx+x.x11),Ao(b.cy+b.y11,b.cx+b.x11),!y),s.arc(b.cx,b.cy,L,Ao(b.y11,b.x11),Ao(b.y01,b.x01),!y))):(s.moveTo(E,N),s.arc(0,0,p,k,C,!y)):s.moveTo(E,N),d>$o&&v>$o?B>$o?(x=Go(D,j,O,R,d,-B,y),b=Go(E,N,P,z,d,-B,y),s.lineTo(x.cx+x.x01,x.cy+x.y01),B<M?s.arc(x.cx,x.cy,B,Ao(x.y01,x.x01),Ao(b.y01,b.x01),!y):(s.arc(x.cx,x.cy,B,Ao(x.y01,x.x01),Ao(x.y11,x.x11),!y),s.arc(0,0,d,Ao(x.cy+x.y11,x.cx+x.x11),Ao(b.cy+b.y11,b.cx+b.x11),y),s.arc(b.cx,b.cy,B,Ao(b.y11,b.x11),Ao(b.y01,b.x01),!y))):s.arc(0,0,d,_,w,y):s.lineTo(D,j)}else s.moveTo(0,0);if(s.closePath(),c)return s=null,c+""||null}return c.centroid=function(){var r=(+t.apply(this,arguments)+ +e.apply(this,arguments))/2,n=(+i.apply(this,arguments)+ +a.apply(this,arguments))/2-Eo/2;return[To(n)*r,Lo(n)*r]},c.innerRadius=function(e){return arguments.length?(t="function"==typeof e?e:vo(+e),c):t},c.outerRadius=function(t){return arguments.length?(e="function"==typeof t?t:vo(+t),c):e},c.cornerRadius=function(t){return arguments.length?(r="function"==typeof t?t:vo(+t),c):r},c.padRadius=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:vo(+t),c):n},c.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:vo(+t),c):i},c.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:vo(+t),c):a},c.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:vo(+t),c):o},c.context=function(t){return arguments.length?(s=null==t?null:t,c):s},c}Ko.prototype;Array.prototype.slice;function Xo(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function Qo(t){this._context=t}function Jo(t){return new Qo(t)}function ts(t){return t[0]}function es(t){return t[1]}function rs(t,e){var r=vo(!0),n=null,i=Jo,a=null,o=qo(s);function s(s){var l,c,h,u=(s=Xo(s)).length,d=!1;for(null==n&&(a=i(h=o())),l=0;l<=u;++l)!(l<u&&r(c=s[l],l,s))===d&&((d=!d)?a.lineStart():a.lineEnd()),d&&a.point(+t(c,l,s),+e(c,l,s));if(h)return a=null,h+""||null}return t="function"==typeof t?t:void 0===t?ts:vo(t),e="function"==typeof e?e:void 0===e?es:vo(e),s.x=function(e){return arguments.length?(t="function"==typeof e?e:vo(+e),s):t},s.y=function(t){return arguments.length?(e="function"==typeof t?t:vo(+t),s):e},s.defined=function(t){return arguments.length?(r="function"==typeof t?t:vo(!!t),s):r},s.curve=function(t){return arguments.length?(i=t,null!=n&&(a=i(n)),s):i},s.context=function(t){return arguments.length?(null==t?n=a=null:a=i(n=t),s):n},s}function ns(t,e){return e<t?-1:e>t?1:e>=t?0:NaN}function is(t){return t}function as(){var t=is,e=ns,r=null,n=vo(0),i=vo(Do),a=vo(0);function o(o){var s,l,c,h,u,d=(o=Xo(o)).length,p=0,f=new Array(d),g=new Array(d),m=+n.apply(this,arguments),y=Math.min(Do,Math.max(-Do,i.apply(this,arguments)-m)),x=Math.min(Math.abs(y)/d,a.apply(this,arguments)),b=x*(y<0?-1:1);for(s=0;s<d;++s)(u=g[f[s]=s]=+t(o[s],s,o))>0&&(p+=u);for(null!=e?f.sort((function(t,r){return e(g[t],g[r])})):null!=r&&f.sort((function(t,e){return r(o[t],o[e])})),s=0,c=p?(y-d*b)/p:0;s<d;++s,m=h)l=f[s],h=m+((u=g[l])>0?u*c:0)+b,g[l]={data:o[l],index:s,value:u,startAngle:m,endAngle:h,padAngle:x};return g}return o.value=function(e){return arguments.length?(t="function"==typeof e?e:vo(+e),o):t},o.sortValues=function(t){return arguments.length?(e=t,r=null,o):e},o.sort=function(t){return arguments.length?(r=t,e=null,o):r},o.startAngle=function(t){return arguments.length?(n="function"==typeof t?t:vo(+t),o):n},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:vo(+t),o):i},o.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:vo(+t),o):a},o}function os(){}function ss(t,e,r){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+r)/6)}function ls(t){this._context=t}function cs(t){return new ls(t)}function hs(t){this._context=t}function us(t){return new hs(t)}function ds(t){this._context=t}function ps(t){return new ds(t)}Qo.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._context.lineTo(t,e)}}},ls.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:ss(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:ss(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},hs.prototype={areaStart:os,areaEnd:os,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:ss(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},ds.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var r=(this._x0+4*this._x1+t)/6,n=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(r,n):this._context.moveTo(r,n);break;case 3:this._point=4;default:ss(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};class fs{constructor(t,e){this._context=t,this._x=e}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,e,t,e):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+e)/2,t,this._y0,t,e)}this._x0=t,this._y0=e}}function gs(t){return new fs(t,!0)}function ms(t){return new fs(t,!1)}function ys(t,e){this._basis=new ls(t),this._beta=e}ys.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,e=this._y,r=t.length-1;if(r>0)for(var n,i=t[0],a=e[0],o=t[r]-i,s=e[r]-a,l=-1;++l<=r;)n=l/r,this._basis.point(this._beta*t[l]+(1-this._beta)*(i+n*o),this._beta*e[l]+(1-this._beta)*(a+n*s));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};const xs=function t(e){function r(t){return 1===e?new ls(t):new ys(t,e)}return r.beta=function(e){return t(+e)},r}(.85);function bs(t,e,r){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-r),t._x2,t._y2)}function ks(t,e){this._context=t,this._k=(1-e)/6}ks.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:bs(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:bs(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const Cs=function t(e){function r(t){return new ks(t,e)}return r.tension=function(e){return t(+e)},r}(0);function ws(t,e){this._context=t,this._k=(1-e)/6}ws.prototype={areaStart:os,areaEnd:os,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:bs(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const _s=function t(e){function r(t){return new ws(t,e)}return r.tension=function(e){return t(+e)},r}(0);function vs(t,e){this._context=t,this._k=(1-e)/6}vs.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:bs(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const Ss=function t(e){function r(t){return new vs(t,e)}return r.tension=function(e){return t(+e)},r}(0);function As(t,e,r){var n=t._x1,i=t._y1,a=t._x2,o=t._y2;if(t._l01_a>$o){var s=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,l=3*t._l01_a*(t._l01_a+t._l12_a);n=(n*s-t._x0*t._l12_2a+t._x2*t._l01_2a)/l,i=(i*s-t._y0*t._l12_2a+t._y2*t._l01_2a)/l}if(t._l23_a>$o){var c=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,h=3*t._l23_a*(t._l23_a+t._l12_a);a=(a*c+t._x1*t._l23_2a-e*t._l12_2a)/h,o=(o*c+t._y1*t._l23_2a-r*t._l12_2a)/h}t._context.bezierCurveTo(n,i,a,o,t._x2,t._y2)}function Ts(t,e){this._context=t,this._alpha=e}Ts.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var r=this._x2-t,n=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(r*r+n*n,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:As(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const Ms=function t(e){function r(t){return e?new Ts(t,e):new ks(t,0)}return r.alpha=function(e){return t(+e)},r}(.5);function Bs(t,e){this._context=t,this._alpha=e}Bs.prototype={areaStart:os,areaEnd:os,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){if(t=+t,e=+e,this._point){var r=this._x2-t,n=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(r*r+n*n,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:As(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const Ls=function t(e){function r(t){return e?new Bs(t,e):new ws(t,0)}return r.alpha=function(e){return t(+e)},r}(.5);function Fs(t,e){this._context=t,this._alpha=e}Fs.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var r=this._x2-t,n=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(r*r+n*n,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:As(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const $s=function t(e){function r(t){return e?new Fs(t,e):new vs(t,0)}return r.alpha=function(e){return t(+e)},r}(.5);function Es(t){this._context=t}function Ns(t){return new Es(t)}function Ds(t){return t<0?-1:1}function js(t,e,r){var n=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(n||i<0&&-0),o=(r-t._y1)/(i||n<0&&-0),s=(a*i+o*n)/(n+i);return(Ds(a)+Ds(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function Is(t,e){var r=t._x1-t._x0;return r?(3*(t._y1-t._y0)/r-e)/2:e}function Os(t,e,r){var n=t._x0,i=t._y0,a=t._x1,o=t._y1,s=(a-n)/3;t._context.bezierCurveTo(n+s,i+s*e,a-s,o-s*r,a,o)}function Rs(t){this._context=t}function Ps(t){this._context=new zs(t)}function zs(t){this._context=t}function Ks(t){return new Rs(t)}function qs(t){return new Ps(t)}function Ws(t){this._context=t}function Hs(t){var e,r,n=t.length-1,i=new Array(n),a=new Array(n),o=new Array(n);for(i[0]=0,a[0]=2,o[0]=t[0]+2*t[1],e=1;e<n-1;++e)i[e]=1,a[e]=4,o[e]=4*t[e]+2*t[e+1];for(i[n-1]=2,a[n-1]=7,o[n-1]=8*t[n-1]+t[n],e=1;e<n;++e)r=i[e]/a[e-1],a[e]-=r,o[e]-=r*o[e-1];for(i[n-1]=o[n-1]/a[n-1],e=n-2;e>=0;--e)i[e]=(o[e]-i[e+1])/a[e];for(a[n-1]=(t[n]+i[n-1])/2,e=0;e<n-1;++e)a[e]=2*t[e+1]-i[e+1];return[i,a]}function Us(t){return new Ws(t)}function Ys(t,e){this._context=t,this._t=e}function Vs(t){return new Ys(t,.5)}function Gs(t){return new Ys(t,0)}function Zs(t){return new Ys(t,1)}function Xs(t,e,r){this.k=t,this.x=e,this.y=r}Es.prototype={areaStart:os,areaEnd:os,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,e){t=+t,e=+e,this._point?this._context.lineTo(t,e):(this._point=1,this._context.moveTo(t,e))}},Rs.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:Os(this,this._t0,Is(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){var r=NaN;if(e=+e,(t=+t)!==this._x1||e!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,Os(this,Is(this,r=js(this,t,e)),r);break;default:Os(this,this._t0,r=js(this,t,e))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e,this._t0=r}}},(Ps.prototype=Object.create(Rs.prototype)).point=function(t,e){Rs.prototype.point.call(this,e,t)},zs.prototype={moveTo:function(t,e){this._context.moveTo(e,t)},closePath:function(){this._context.closePath()},lineTo:function(t,e){this._context.lineTo(e,t)},bezierCurveTo:function(t,e,r,n,i,a){this._context.bezierCurveTo(e,t,n,r,a,i)}},Ws.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,e=this._y,r=t.length;if(r)if(this._line?this._context.lineTo(t[0],e[0]):this._context.moveTo(t[0],e[0]),2===r)this._context.lineTo(t[1],e[1]);else for(var n=Hs(t),i=Hs(e),a=0,o=1;o<r;++a,++o)this._context.bezierCurveTo(n[0][a],i[0][a],n[1][a],i[1][a],t[o],e[o]);(this._line||0!==this._line&&1===r)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,e){this._x.push(+t),this._y.push(+e)}},Ys.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var r=this._x*(1-this._t)+t*this._t;this._context.lineTo(r,this._y),this._context.lineTo(r,e)}}this._x=t,this._y=e}},Xs.prototype={constructor:Xs,scale:function(t){return 1===t?this:new Xs(this.k*t,this.x,this.y)},translate:function(t,e){return 0===t&0===e?this:new Xs(this.k,this.x+this.k*t,this.y+this.k*e)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};new Xs(1,0,0);Xs.prototype},99418:(t,e,r)=>{"use strict";r.d(e,{A:()=>at});const{entries:n,setPrototypeOf:i,isFrozen:a,getPrototypeOf:o,getOwnPropertyDescriptor:s}=Object;let{freeze:l,seal:c,create:h}=Object,{apply:u,construct:d}="undefined"!=typeof Reflect&&Reflect;l||(l=function(t){return t}),c||(c=function(t){return t}),u||(u=function(t,e,r){return t.apply(e,r)}),d||(d=function(t,e){return new t(...e)});const p=A(Array.prototype.forEach),f=A(Array.prototype.pop),g=A(Array.prototype.push),m=A(String.prototype.toLowerCase),y=A(String.prototype.toString),x=A(String.prototype.match),b=A(String.prototype.replace),k=A(String.prototype.indexOf),C=A(String.prototype.trim),w=A(Object.prototype.hasOwnProperty),_=A(RegExp.prototype.test),v=(S=TypeError,function(){for(var t=arguments.length,e=new Array(t),r=0;r<t;r++)e[r]=arguments[r];return d(S,e)});var S;function A(t){return function(e){for(var r=arguments.length,n=new Array(r>1?r-1:0),i=1;i<r;i++)n[i-1]=arguments[i];return u(t,e,n)}}function T(t,e){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:m;i&&i(t,null);let n=e.length;for(;n--;){let i=e[n];if("string"==typeof i){const t=r(i);t!==i&&(a(e)||(e[n]=t),i=t)}t[i]=!0}return t}function M(t){for(let e=0;e<t.length;e++){w(t,e)||(t[e]=null)}return t}function B(t){const e=h(null);for(const[r,i]of n(t)){w(t,r)&&(Array.isArray(i)?e[r]=M(i):i&&"object"==typeof i&&i.constructor===Object?e[r]=B(i):e[r]=i)}return e}function L(t,e){for(;null!==t;){const r=s(t,e);if(r){if(r.get)return A(r.get);if("function"==typeof r.value)return A(r.value)}t=o(t)}return function(){return null}}const F=l(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),$=l(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),E=l(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),N=l(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),D=l(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),j=l(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),I=l(["#text"]),O=l(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns","slot"]),R=l(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),P=l(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),z=l(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),K=c(/\{\{[\w\W]*|[\w\W]*\}\}/gm),q=c(/<%[\w\W]*|[\w\W]*%>/gm),W=c(/\${[\w\W]*}/gm),H=c(/^data-[\-\w.\u00B7-\uFFFF]/),U=c(/^aria-[\-\w]+$/),Y=c(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),V=c(/^(?:\w+script|data):/i),G=c(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),Z=c(/^html$/i),X=c(/^[a-z][.\w]*(-[.\w]+)+$/i);var Q=Object.freeze({__proto__:null,ARIA_ATTR:U,ATTR_WHITESPACE:G,CUSTOM_ELEMENT:X,DATA_ATTR:H,DOCTYPE_NAME:Z,ERB_EXPR:q,IS_ALLOWED_URI:Y,IS_SCRIPT_OR_DATA:V,MUSTACHE_EXPR:K,TMPLIT_EXPR:W});const J=1,tt=3,et=7,rt=8,nt=9,it=function(){return"undefined"==typeof window?null:window};var at=function t(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:it();const r=e=>t(e);if(r.version="3.2.1",r.removed=[],!e||!e.document||e.document.nodeType!==nt)return r.isSupported=!1,r;let{document:i}=e;const a=i,o=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:c,Node:u,Element:d,NodeFilter:S,NamedNodeMap:A=e.NamedNodeMap||e.MozNamedAttrMap,HTMLFormElement:M,DOMParser:K,trustedTypes:q}=e,W=d.prototype,H=L(W,"cloneNode"),U=L(W,"remove"),V=L(W,"nextSibling"),G=L(W,"childNodes"),X=L(W,"parentNode");if("function"==typeof c){const t=i.createElement("template");t.content&&t.content.ownerDocument&&(i=t.content.ownerDocument)}let at,ot="";const{implementation:st,createNodeIterator:lt,createDocumentFragment:ct,getElementsByTagName:ht}=i,{importNode:ut}=a;let dt={};r.isSupported="function"==typeof n&&"function"==typeof X&&st&&void 0!==st.createHTMLDocument;const{MUSTACHE_EXPR:pt,ERB_EXPR:ft,TMPLIT_EXPR:gt,DATA_ATTR:mt,ARIA_ATTR:yt,IS_SCRIPT_OR_DATA:xt,ATTR_WHITESPACE:bt,CUSTOM_ELEMENT:kt}=Q;let{IS_ALLOWED_URI:Ct}=Q,wt=null;const _t=T({},[...F,...$,...E,...D,...I]);let vt=null;const St=T({},[...O,...R,...P,...z]);let At=Object.seal(h(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Tt=null,Mt=null,Bt=!0,Lt=!0,Ft=!1,$t=!0,Et=!1,Nt=!0,Dt=!1,jt=!1,It=!1,Ot=!1,Rt=!1,Pt=!1,zt=!0,Kt=!1,qt=!0,Wt=!1,Ht={},Ut=null;const Yt=T({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Vt=null;const Gt=T({},["audio","video","img","source","image","track"]);let Zt=null;const Xt=T({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Qt="http://www.w3.org/1998/Math/MathML",Jt="http://www.w3.org/2000/svg",te="http://www.w3.org/1999/xhtml";let ee=te,re=!1,ne=null;const ie=T({},[Qt,Jt,te],y);let ae=T({},["mi","mo","mn","ms","mtext"]),oe=T({},["annotation-xml"]);const se=T({},["title","style","font","a","script"]);let le=null;const ce=["application/xhtml+xml","text/html"];let he=null,ue=null;const de=i.createElement("form"),pe=function(t){return t instanceof RegExp||t instanceof Function},fe=function(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ue||ue!==t){if(t&&"object"==typeof t||(t={}),t=B(t),le=-1===ce.indexOf(t.PARSER_MEDIA_TYPE)?"text/html":t.PARSER_MEDIA_TYPE,he="application/xhtml+xml"===le?y:m,wt=w(t,"ALLOWED_TAGS")?T({},t.ALLOWED_TAGS,he):_t,vt=w(t,"ALLOWED_ATTR")?T({},t.ALLOWED_ATTR,he):St,ne=w(t,"ALLOWED_NAMESPACES")?T({},t.ALLOWED_NAMESPACES,y):ie,Zt=w(t,"ADD_URI_SAFE_ATTR")?T(B(Xt),t.ADD_URI_SAFE_ATTR,he):Xt,Vt=w(t,"ADD_DATA_URI_TAGS")?T(B(Gt),t.ADD_DATA_URI_TAGS,he):Gt,Ut=w(t,"FORBID_CONTENTS")?T({},t.FORBID_CONTENTS,he):Yt,Tt=w(t,"FORBID_TAGS")?T({},t.FORBID_TAGS,he):{},Mt=w(t,"FORBID_ATTR")?T({},t.FORBID_ATTR,he):{},Ht=!!w(t,"USE_PROFILES")&&t.USE_PROFILES,Bt=!1!==t.ALLOW_ARIA_ATTR,Lt=!1!==t.ALLOW_DATA_ATTR,Ft=t.ALLOW_UNKNOWN_PROTOCOLS||!1,$t=!1!==t.ALLOW_SELF_CLOSE_IN_ATTR,Et=t.SAFE_FOR_TEMPLATES||!1,Nt=!1!==t.SAFE_FOR_XML,Dt=t.WHOLE_DOCUMENT||!1,Ot=t.RETURN_DOM||!1,Rt=t.RETURN_DOM_FRAGMENT||!1,Pt=t.RETURN_TRUSTED_TYPE||!1,It=t.FORCE_BODY||!1,zt=!1!==t.SANITIZE_DOM,Kt=t.SANITIZE_NAMED_PROPS||!1,qt=!1!==t.KEEP_CONTENT,Wt=t.IN_PLACE||!1,Ct=t.ALLOWED_URI_REGEXP||Y,ee=t.NAMESPACE||te,ae=t.MATHML_TEXT_INTEGRATION_POINTS||ae,oe=t.HTML_INTEGRATION_POINTS||oe,At=t.CUSTOM_ELEMENT_HANDLING||{},t.CUSTOM_ELEMENT_HANDLING&&pe(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(At.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&pe(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(At.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(At.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Et&&(Lt=!1),Rt&&(Ot=!0),Ht&&(wt=T({},I),vt=[],!0===Ht.html&&(T(wt,F),T(vt,O)),!0===Ht.svg&&(T(wt,$),T(vt,R),T(vt,z)),!0===Ht.svgFilters&&(T(wt,E),T(vt,R),T(vt,z)),!0===Ht.mathMl&&(T(wt,D),T(vt,P),T(vt,z))),t.ADD_TAGS&&(wt===_t&&(wt=B(wt)),T(wt,t.ADD_TAGS,he)),t.ADD_ATTR&&(vt===St&&(vt=B(vt)),T(vt,t.ADD_ATTR,he)),t.ADD_URI_SAFE_ATTR&&T(Zt,t.ADD_URI_SAFE_ATTR,he),t.FORBID_CONTENTS&&(Ut===Yt&&(Ut=B(Ut)),T(Ut,t.FORBID_CONTENTS,he)),qt&&(wt["#text"]=!0),Dt&&T(wt,["html","head","body"]),wt.table&&(T(wt,["tbody"]),delete Tt.tbody),t.TRUSTED_TYPES_POLICY){if("function"!=typeof t.TRUSTED_TYPES_POLICY.createHTML)throw v('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof t.TRUSTED_TYPES_POLICY.createScriptURL)throw v('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');at=t.TRUSTED_TYPES_POLICY,ot=at.createHTML("")}else void 0===at&&(at=function(t,e){if("object"!=typeof t||"function"!=typeof t.createPolicy)return null;let r=null;const n="data-tt-policy-suffix";e&&e.hasAttribute(n)&&(r=e.getAttribute(n));const i="dompurify"+(r?"#"+r:"");try{return t.createPolicy(i,{createHTML:t=>t,createScriptURL:t=>t})}catch(a){return console.warn("TrustedTypes policy "+i+" could not be created."),null}}(q,o)),null!==at&&"string"==typeof ot&&(ot=at.createHTML(""));l&&l(t),ue=t}},ge=T({},[...$,...E,...N]),me=T({},[...D,...j]),ye=function(t){g(r.removed,{element:t});try{X(t).removeChild(t)}catch(e){U(t)}},xe=function(t,e){try{g(r.removed,{attribute:e.getAttributeNode(t),from:e})}catch(n){g(r.removed,{attribute:null,from:e})}if(e.removeAttribute(t),"is"===t&&!vt[t])if(Ot||Rt)try{ye(e)}catch(n){}else try{e.setAttribute(t,"")}catch(n){}},be=function(t){let e=null,r=null;if(It)t="<remove></remove>"+t;else{const e=x(t,/^[\r\n\t ]+/);r=e&&e[0]}"application/xhtml+xml"===le&&ee===te&&(t='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+t+"</body></html>");const n=at?at.createHTML(t):t;if(ee===te)try{e=(new K).parseFromString(n,le)}catch(o){}if(!e||!e.documentElement){e=st.createDocument(ee,"template",null);try{e.documentElement.innerHTML=re?ot:n}catch(o){}}const a=e.body||e.documentElement;return t&&r&&a.insertBefore(i.createTextNode(r),a.childNodes[0]||null),ee===te?ht.call(e,Dt?"html":"body")[0]:Dt?e.documentElement:a},ke=function(t){return lt.call(t.ownerDocument||t,t,S.SHOW_ELEMENT|S.SHOW_COMMENT|S.SHOW_TEXT|S.SHOW_PROCESSING_INSTRUCTION|S.SHOW_CDATA_SECTION,null)},Ce=function(t){return t instanceof M&&("string"!=typeof t.nodeName||"string"!=typeof t.textContent||"function"!=typeof t.removeChild||!(t.attributes instanceof A)||"function"!=typeof t.removeAttribute||"function"!=typeof t.setAttribute||"string"!=typeof t.namespaceURI||"function"!=typeof t.insertBefore||"function"!=typeof t.hasChildNodes)},we=function(t){return"function"==typeof u&&t instanceof u};function _e(t,e,n){dt[t]&&p(dt[t],(t=>{t.call(r,e,n,ue)}))}const ve=function(t){let e=null;if(_e("beforeSanitizeElements",t,null),Ce(t))return ye(t),!0;const n=he(t.nodeName);if(_e("uponSanitizeElement",t,{tagName:n,allowedTags:wt}),t.hasChildNodes()&&!we(t.firstElementChild)&&_(/<[/\w]/g,t.innerHTML)&&_(/<[/\w]/g,t.textContent))return ye(t),!0;if(t.nodeType===et)return ye(t),!0;if(Nt&&t.nodeType===rt&&_(/<[/\w]/g,t.data))return ye(t),!0;if(!wt[n]||Tt[n]){if(!Tt[n]&&Ae(n)){if(At.tagNameCheck instanceof RegExp&&_(At.tagNameCheck,n))return!1;if(At.tagNameCheck instanceof Function&&At.tagNameCheck(n))return!1}if(qt&&!Ut[n]){const e=X(t)||t.parentNode,r=G(t)||t.childNodes;if(r&&e){for(let n=r.length-1;n>=0;--n){const i=H(r[n],!0);i.__removalCount=(t.__removalCount||0)+1,e.insertBefore(i,V(t))}}}return ye(t),!0}return t instanceof d&&!function(t){let e=X(t);e&&e.tagName||(e={namespaceURI:ee,tagName:"template"});const r=m(t.tagName),n=m(e.tagName);return!!ne[t.namespaceURI]&&(t.namespaceURI===Jt?e.namespaceURI===te?"svg"===r:e.namespaceURI===Qt?"svg"===r&&("annotation-xml"===n||ae[n]):Boolean(ge[r]):t.namespaceURI===Qt?e.namespaceURI===te?"math"===r:e.namespaceURI===Jt?"math"===r&&oe[n]:Boolean(me[r]):t.namespaceURI===te?!(e.namespaceURI===Jt&&!oe[n])&&!(e.namespaceURI===Qt&&!ae[n])&&!me[r]&&(se[r]||!ge[r]):!("application/xhtml+xml"!==le||!ne[t.namespaceURI]))}(t)?(ye(t),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!_(/<\/no(script|embed|frames)/i,t.innerHTML)?(Et&&t.nodeType===tt&&(e=t.textContent,p([pt,ft,gt],(t=>{e=b(e,t," ")})),t.textContent!==e&&(g(r.removed,{element:t.cloneNode()}),t.textContent=e)),_e("afterSanitizeElements",t,null),!1):(ye(t),!0)},Se=function(t,e,r){if(zt&&("id"===e||"name"===e)&&(r in i||r in de))return!1;if(Lt&&!Mt[e]&&_(mt,e));else if(Bt&&_(yt,e));else if(!vt[e]||Mt[e]){if(!(Ae(t)&&(At.tagNameCheck instanceof RegExp&&_(At.tagNameCheck,t)||At.tagNameCheck instanceof Function&&At.tagNameCheck(t))&&(At.attributeNameCheck instanceof RegExp&&_(At.attributeNameCheck,e)||At.attributeNameCheck instanceof Function&&At.attributeNameCheck(e))||"is"===e&&At.allowCustomizedBuiltInElements&&(At.tagNameCheck instanceof RegExp&&_(At.tagNameCheck,r)||At.tagNameCheck instanceof Function&&At.tagNameCheck(r))))return!1}else if(Zt[e]);else if(_(Ct,b(r,bt,"")));else if("src"!==e&&"xlink:href"!==e&&"href"!==e||"script"===t||0!==k(r,"data:")||!Vt[t]){if(Ft&&!_(xt,b(r,bt,"")));else if(r)return!1}else;return!0},Ae=function(t){return"annotation-xml"!==t&&x(t,kt)},Te=function(t){_e("beforeSanitizeAttributes",t,null);const{attributes:e}=t;if(!e)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:vt,forceKeepAttr:void 0};let i=e.length;for(;i--;){const o=e[i],{name:s,namespaceURI:l,value:c}=o,h=he(s);let u="value"===s?c:C(c);if(n.attrName=h,n.attrValue=u,n.keepAttr=!0,n.forceKeepAttr=void 0,_e("uponSanitizeAttribute",t,n),u=n.attrValue,!Kt||"id"!==h&&"name"!==h||(xe(s,t),u="user-content-"+u),Nt&&_(/((--!?|])>)|<\/(style|title)/i,u)){xe(s,t);continue}if(n.forceKeepAttr)continue;if(xe(s,t),!n.keepAttr)continue;if(!$t&&_(/\/>/i,u)){xe(s,t);continue}Et&&p([pt,ft,gt],(t=>{u=b(u,t," ")}));const d=he(t.nodeName);if(Se(d,h,u)){if(at&&"object"==typeof q&&"function"==typeof q.getAttributeType)if(l);else switch(q.getAttributeType(d,h)){case"TrustedHTML":u=at.createHTML(u);break;case"TrustedScriptURL":u=at.createScriptURL(u)}try{l?t.setAttributeNS(l,s,u):t.setAttribute(s,u),Ce(t)?ye(t):f(r.removed)}catch(a){}}}_e("afterSanitizeAttributes",t,null)},Me=function t(e){let r=null;const n=ke(e);for(_e("beforeSanitizeShadowDOM",e,null);r=n.nextNode();)_e("uponSanitizeShadowNode",r,null),ve(r)||(r.content instanceof s&&t(r.content),Te(r));_e("afterSanitizeShadowDOM",e,null)};return r.sanitize=function(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,i=null,o=null,l=null;if(re=!t,re&&(t="\x3c!--\x3e"),"string"!=typeof t&&!we(t)){if("function"!=typeof t.toString)throw v("toString is not a function");if("string"!=typeof(t=t.toString()))throw v("dirty is not a string, aborting")}if(!r.isSupported)return t;if(jt||fe(e),r.removed=[],"string"==typeof t&&(Wt=!1),Wt){if(t.nodeName){const e=he(t.nodeName);if(!wt[e]||Tt[e])throw v("root node is forbidden and cannot be sanitized in-place")}}else if(t instanceof u)n=be("\x3c!----\x3e"),i=n.ownerDocument.importNode(t,!0),i.nodeType===J&&"BODY"===i.nodeName||"HTML"===i.nodeName?n=i:n.appendChild(i);else{if(!Ot&&!Et&&!Dt&&-1===t.indexOf("<"))return at&&Pt?at.createHTML(t):t;if(n=be(t),!n)return Ot?null:Pt?ot:""}n&&It&&ye(n.firstChild);const c=ke(Wt?t:n);for(;o=c.nextNode();)ve(o)||(o.content instanceof s&&Me(o.content),Te(o));if(Wt)return t;if(Ot){if(Rt)for(l=ct.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(vt.shadowroot||vt.shadowrootmode)&&(l=ut.call(a,l,!0)),l}let h=Dt?n.outerHTML:n.innerHTML;return Dt&&wt["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&_(Z,n.ownerDocument.doctype.name)&&(h="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+h),Et&&p([pt,ft,gt],(t=>{h=b(h,t," ")})),at&&Pt?at.createHTML(h):h},r.setConfig=function(){fe(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),jt=!0},r.clearConfig=function(){ue=null,jt=!1},r.isValidAttribute=function(t,e,r){ue||fe({});const n=he(t),i=he(e);return Se(n,i,r)},r.addHook=function(t,e){"function"==typeof e&&(dt[t]=dt[t]||[],g(dt[t],e))},r.removeHook=function(t){if(dt[t])return f(dt[t])},r.removeHooks=function(t){dt[t]&&(dt[t]=[])},r.removeAllHooks=function(){dt={}},r}()},93539:(t,e,r)=>{"use strict";r.d(e,{A:()=>o});var n=r(72453),i=r(63122);const a=class{constructor(){this.type=i.Z.ALL}get(){return this.type}set(t){if(this.type&&this.type!==t)throw new Error("Cannot change both RGB and HSL channels at the same time");this.type=t}reset(){this.type=i.Z.ALL}is(t){return this.type===t}};const o=new class{constructor(t,e){this.color=e,this.changed=!1,this.data=t,this.type=new a}set(t,e){return this.color=e,this.changed=!1,this.data=t,this.type.type=i.Z.ALL,this}_ensureHSL(){const t=this.data,{h:e,s:r,l:i}=t;void 0===e&&(t.h=n.A.channel.rgb2hsl(t,"h")),void 0===r&&(t.s=n.A.channel.rgb2hsl(t,"s")),void 0===i&&(t.l=n.A.channel.rgb2hsl(t,"l"))}_ensureRGB(){const t=this.data,{r:e,g:r,b:i}=t;void 0===e&&(t.r=n.A.channel.hsl2rgb(t,"r")),void 0===r&&(t.g=n.A.channel.hsl2rgb(t,"g")),void 0===i&&(t.b=n.A.channel.hsl2rgb(t,"b"))}get r(){const t=this.data,e=t.r;return this.type.is(i.Z.HSL)||void 0===e?(this._ensureHSL(),n.A.channel.hsl2rgb(t,"r")):e}get g(){const t=this.data,e=t.g;return this.type.is(i.Z.HSL)||void 0===e?(this._ensureHSL(),n.A.channel.hsl2rgb(t,"g")):e}get b(){const t=this.data,e=t.b;return this.type.is(i.Z.HSL)||void 0===e?(this._ensureHSL(),n.A.channel.hsl2rgb(t,"b")):e}get h(){const t=this.data,e=t.h;return this.type.is(i.Z.RGB)||void 0===e?(this._ensureRGB(),n.A.channel.rgb2hsl(t,"h")):e}get s(){const t=this.data,e=t.s;return this.type.is(i.Z.RGB)||void 0===e?(this._ensureRGB(),n.A.channel.rgb2hsl(t,"s")):e}get l(){const t=this.data,e=t.l;return this.type.is(i.Z.RGB)||void 0===e?(this._ensureRGB(),n.A.channel.rgb2hsl(t,"l")):e}get a(){return this.data.a}set r(t){this.type.set(i.Z.RGB),this.changed=!0,this.data.r=t}set g(t){this.type.set(i.Z.RGB),this.changed=!0,this.data.g=t}set b(t){this.type.set(i.Z.RGB),this.changed=!0,this.data.b=t}set h(t){this.type.set(i.Z.HSL),this.changed=!0,this.data.h=t}set s(t){this.type.set(i.Z.HSL),this.changed=!0,this.data.s=t}set l(t){this.type.set(i.Z.HSL),this.changed=!0,this.data.l=t}set a(t){this.changed=!0,this.data.a=t}}({r:0,g:0,b:0,a:0},"transparent")},74886:(t,e,r)=>{"use strict";r.d(e,{A:()=>g});var n=r(93539),i=r(63122);const a={re:/^#((?:[a-f0-9]{2}){2,4}|[a-f0-9]{3})$/i,parse:t=>{if(35!==t.charCodeAt(0))return;const e=t.match(a.re);if(!e)return;const r=e[1],i=parseInt(r,16),o=r.length,s=o%4==0,l=o>4,c=l?1:17,h=l?8:4,u=s?0:-1,d=l?255:15;return n.A.set({r:(i>>h*(u+3)&d)*c,g:(i>>h*(u+2)&d)*c,b:(i>>h*(u+1)&d)*c,a:s?(i&d)*c/255:1},t)},stringify:t=>{const{r:e,g:r,b:n,a:a}=t;return a<1?`#${i.Y[Math.round(e)]}${i.Y[Math.round(r)]}${i.Y[Math.round(n)]}${i.Y[Math.round(255*a)]}`:`#${i.Y[Math.round(e)]}${i.Y[Math.round(r)]}${i.Y[Math.round(n)]}`}},o=a;var s=r(72453);const l={re:/^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,hueRe:/^(.+?)(deg|grad|rad|turn)$/i,_hue2deg:t=>{const e=t.match(l.hueRe);if(e){const[,t,r]=e;switch(r){case"grad":return s.A.channel.clamp.h(.9*parseFloat(t));case"rad":return s.A.channel.clamp.h(180*parseFloat(t)/Math.PI);case"turn":return s.A.channel.clamp.h(360*parseFloat(t))}}return s.A.channel.clamp.h(parseFloat(t))},parse:t=>{const e=t.charCodeAt(0);if(104!==e&&72!==e)return;const r=t.match(l.re);if(!r)return;const[,i,a,o,c,h]=r;return n.A.set({h:l._hue2deg(i),s:s.A.channel.clamp.s(parseFloat(a)),l:s.A.channel.clamp.l(parseFloat(o)),a:c?s.A.channel.clamp.a(h?parseFloat(c)/100:parseFloat(c)):1},t)},stringify:t=>{const{h:e,s:r,l:n,a:i}=t;return i<1?`hsla(${s.A.lang.round(e)}, ${s.A.lang.round(r)}%, ${s.A.lang.round(n)}%, ${i})`:`hsl(${s.A.lang.round(e)}, ${s.A.lang.round(r)}%, ${s.A.lang.round(n)}%)`}},c=l,h={colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyanaqua:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",transparent:"#00000000",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},parse:t=>{t=t.toLowerCase();const e=h.colors[t];if(e)return o.parse(e)},stringify:t=>{const e=o.stringify(t);for(const r in h.colors)if(h.colors[r]===e)return r}},u=h,d={re:/^rgba?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?)))?\s*?\)$/i,parse:t=>{const e=t.charCodeAt(0);if(114!==e&&82!==e)return;const r=t.match(d.re);if(!r)return;const[,i,a,o,l,c,h,u,p]=r;return n.A.set({r:s.A.channel.clamp.r(a?2.55*parseFloat(i):parseFloat(i)),g:s.A.channel.clamp.g(l?2.55*parseFloat(o):parseFloat(o)),b:s.A.channel.clamp.b(h?2.55*parseFloat(c):parseFloat(c)),a:u?s.A.channel.clamp.a(p?parseFloat(u)/100:parseFloat(u)):1},t)},stringify:t=>{const{r:e,g:r,b:n,a:i}=t;return i<1?`rgba(${s.A.lang.round(e)}, ${s.A.lang.round(r)}, ${s.A.lang.round(n)}, ${s.A.lang.round(i)})`:`rgb(${s.A.lang.round(e)}, ${s.A.lang.round(r)}, ${s.A.lang.round(n)})`}},p=d,f={format:{keyword:h,hex:o,rgb:d,rgba:d,hsl:l,hsla:l},parse:t=>{if("string"!=typeof t)return t;const e=o.parse(t)||p.parse(t)||c.parse(t)||u.parse(t);if(e)return e;throw new Error(`Unsupported color format: "${t}"`)},stringify:t=>!t.changed&&t.color?t.color:t.type.is(i.Z.HSL)||void 0===t.data.r?c.stringify(t):t.a<1||!Number.isInteger(t.r)||!Number.isInteger(t.g)||!Number.isInteger(t.b)?p.stringify(t):o.stringify(t)},g=f},63122:(t,e,r)=>{"use strict";r.d(e,{Y:()=>i,Z:()=>a});var n=r(72453);const i={};for(let o=0;o<=255;o++)i[o]=n.A.unit.dec2hex(o);const a={ALL:0,RGB:1,HSL:2}},95635:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(72453),i=r(74886);const a=(t,e,r)=>{const a=i.A.parse(t),o=a[e],s=n.A.channel.clamp[e](o+r);return o!==s&&(a[e]=s),i.A.stringify(a)}},8232:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(72453),i=r(74886);const a=(t,e)=>{const r=i.A.parse(t);for(const i in e)r[i]=n.A.channel.clamp[i](e[i]);return i.A.stringify(r)}},75263:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=r(95635);const i=(t,e)=>(0,n.A)(t,"l",-e)},3219:(t,e,r)=>{"use strict";r.d(e,{A:()=>s});var n=r(72453),i=r(74886);const a=t=>{const{r:e,g:r,b:a}=i.A.parse(t),o=.2126*n.A.channel.toLinear(e)+.7152*n.A.channel.toLinear(r)+.0722*n.A.channel.toLinear(a);return n.A.lang.round(o)},o=t=>a(t)>=.5,s=t=>!o(t)},78041:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=r(95635);const i=(t,e)=>(0,n.A)(t,"l",e)},25582:(t,e,r)=>{"use strict";r.d(e,{A:()=>s});var n=r(72453),i=r(93539),a=r(74886),o=r(8232);const s=(t,e,r=0,s=1)=>{if("number"!=typeof t)return(0,o.A)(t,{a:e});const l=i.A.set({r:n.A.channel.clamp.r(t),g:n.A.channel.clamp.g(e),b:n.A.channel.clamp.b(r),a:n.A.channel.clamp.a(s)});return a.A.stringify(l)}},72453:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});const n={min:{r:0,g:0,b:0,s:0,l:0,a:0},max:{r:255,g:255,b:255,h:360,s:100,l:100,a:1},clamp:{r:t=>t>=255?255:t<0?0:t,g:t=>t>=255?255:t<0?0:t,b:t=>t>=255?255:t<0?0:t,h:t=>t%360,s:t=>t>=100?100:t<0?0:t,l:t=>t>=100?100:t<0?0:t,a:t=>t>=1?1:t<0?0:t},toLinear:t=>{const e=t/255;return t>.03928?Math.pow((e+.055)/1.055,2.4):e/12.92},hue2rgb:(t,e,r)=>(r<0&&(r+=1),r>1&&(r-=1),r<1/6?t+6*(e-t)*r:r<.5?e:r<2/3?t+(e-t)*(2/3-r)*6:t),hsl2rgb:({h:t,s:e,l:r},i)=>{if(!e)return 2.55*r;t/=360,e/=100;const a=(r/=100)<.5?r*(1+e):r+e-r*e,o=2*r-a;switch(i){case"r":return 255*n.hue2rgb(o,a,t+1/3);case"g":return 255*n.hue2rgb(o,a,t);case"b":return 255*n.hue2rgb(o,a,t-1/3)}},rgb2hsl:({r:t,g:e,b:r},n)=>{t/=255,e/=255,r/=255;const i=Math.max(t,e,r),a=Math.min(t,e,r),o=(i+a)/2;if("l"===n)return 100*o;if(i===a)return 0;const s=i-a;if("s"===n)return 100*(o>.5?s/(2-i-a):s/(i+a));switch(i){case t:return 60*((e-r)/s+(e<r?6:0));case e:return 60*((r-t)/s+2);case r:return 60*((t-e)/s+4);default:return-1}}},i={channel:n,lang:{clamp:(t,e,r)=>e>r?Math.min(e,Math.max(r,t)):Math.min(r,Math.max(e,t)),round:t=>Math.round(1e10*t)/1e10},unit:{dec2hex:t=>{const e=Math.round(t).toString(16);return e.length>1?e:`0${e}`}}}},80127:(t,e,r)=>{"use strict";r.d(e,{A:()=>d});const n=function(){this.__data__=[],this.size=0};var i=r(66984);const a=function(t,e){for(var r=t.length;r--;)if((0,i.A)(t[r][0],e))return r;return-1};var o=Array.prototype.splice;const s=function(t){var e=this.__data__,r=a(e,t);return!(r<0)&&(r==e.length-1?e.pop():o.call(e,r,1),--this.size,!0)};const l=function(t){var e=this.__data__,r=a(e,t);return r<0?void 0:e[r][1]};const c=function(t){return a(this.__data__,t)>-1};const h=function(t,e){var r=this.__data__,n=a(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this};function u(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}u.prototype.clear=n,u.prototype.delete=s,u.prototype.get=l,u.prototype.has=c,u.prototype.set=h;const d=u},68335:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(18744),i=r(41917);const a=(0,n.A)(i.A,"Map")},29471:(t,e,r)=>{"use strict";r.d(e,{A:()=>_});const n=(0,r(18744).A)(Object,"create");const i=function(){this.__data__=n?n(null):{},this.size=0};const a=function(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e};var o=Object.prototype.hasOwnProperty;const s=function(t){var e=this.__data__;if(n){var r=e[t];return"__lodash_hash_undefined__"===r?void 0:r}return o.call(e,t)?e[t]:void 0};var l=Object.prototype.hasOwnProperty;const c=function(t){var e=this.__data__;return n?void 0!==e[t]:l.call(e,t)};const h=function(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=n&&void 0===e?"__lodash_hash_undefined__":e,this};function u(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}u.prototype.clear=i,u.prototype.delete=a,u.prototype.get=s,u.prototype.has=c,u.prototype.set=h;const d=u;var p=r(80127),f=r(68335);const g=function(){this.size=0,this.__data__={hash:new d,map:new(f.A||p.A),string:new d}};const m=function(t){var e=typeof t;return"string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t};const y=function(t,e){var r=t.__data__;return m(e)?r["string"==typeof e?"string":"hash"]:r.map};const x=function(t){var e=y(this,t).delete(t);return this.size-=e?1:0,e};const b=function(t){return y(this,t).get(t)};const k=function(t){return y(this,t).has(t)};const C=function(t,e){var r=y(this,t),n=r.size;return r.set(t,e),this.size+=r.size==n?0:1,this};function w(t){var e=-1,r=null==t?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}w.prototype.clear=g,w.prototype.delete=x,w.prototype.get=b,w.prototype.has=k,w.prototype.set=C;const _=w},39857:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(18744),i=r(41917);const a=(0,n.A)(i.A,"Set")},11754:(t,e,r)=>{"use strict";r.d(e,{A:()=>d});var n=r(80127);const i=function(){this.__data__=new n.A,this.size=0};const a=function(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r};const o=function(t){return this.__data__.get(t)};const s=function(t){return this.__data__.has(t)};var l=r(68335),c=r(29471);const h=function(t,e){var r=this.__data__;if(r instanceof n.A){var i=r.__data__;if(!l.A||i.length<199)return i.push([t,e]),this.size=++r.size,this;r=this.__data__=new c.A(i)}return r.set(t,e),this.size=r.size,this};function u(t){var e=this.__data__=new n.A(t);this.size=e.size}u.prototype.clear=i,u.prototype.delete=a,u.prototype.get=o,u.prototype.has=s,u.prototype.set=h;const d=u},241:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=r(41917).A.Symbol},43988:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=r(41917).A.Uint8Array},83607:(t,e,r)=>{"use strict";r.d(e,{A:()=>h});const n=function(t,e){for(var r=-1,n=Array(t);++r<t;)n[r]=e(r);return n};var i=r(52274),a=r(92049),o=r(99912),s=r(25353),l=r(33858),c=Object.prototype.hasOwnProperty;const h=function(t,e){var r=(0,a.A)(t),h=!r&&(0,i.A)(t),u=!r&&!h&&(0,o.A)(t),d=!r&&!h&&!u&&(0,l.A)(t),p=r||h||u||d,f=p?n(t.length,String):[],g=f.length;for(var m in t)!e&&!c.call(t,m)||p&&("length"==m||u&&("offset"==m||"parent"==m)||d&&("buffer"==m||"byteLength"==m||"byteOffset"==m)||(0,s.A)(m,g))||f.push(m);return f}},52851:(t,e,r)=>{"use strict";r.d(e,{A:()=>o});var n=r(52528),i=r(66984),a=Object.prototype.hasOwnProperty;const o=function(t,e,r){var o=t[e];a.call(t,e)&&(0,i.A)(o,r)&&(void 0!==r||e in t)||(0,n.A)(t,e,r)}},52528:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=r(84171);const i=function(t,e,r){"__proto__"==e&&n.A?(0,n.A)(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}},4574:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){return function(e,r,n){for(var i=-1,a=Object(e),o=n(e),s=o.length;s--;){var l=o[t?s:++i];if(!1===r(a[l],l,a))break}return e}}()},88496:(t,e,r)=>{"use strict";r.d(e,{A:()=>d});var n=r(241),i=Object.prototype,a=i.hasOwnProperty,o=i.toString,s=n.A?n.A.toStringTag:void 0;const l=function(t){var e=a.call(t,s),r=t[s];try{t[s]=void 0;var n=!0}catch(l){}var i=o.call(t);return n&&(e?t[s]=r:delete t[s]),i};var c=Object.prototype.toString;const h=function(t){return c.call(t)};var u=n.A?n.A.toStringTag:void 0;const d=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":u&&u in Object(t)?l(t):h(t)}},69471:(t,e,r)=>{"use strict";r.d(e,{A:()=>o});var n=r(97271);const i=(0,r(40367).A)(Object.keys,Object);var a=Object.prototype.hasOwnProperty;const o=function(t){if(!(0,n.A)(t))return i(t);var e=[];for(var r in Object(t))a.call(t,r)&&"constructor"!=r&&e.push(r);return e}},24326:(t,e,r)=>{"use strict";r.d(e,{A:()=>o});var n=r(29008),i=r(76875),a=r(67525);const o=function(t,e){return(0,a.A)((0,i.A)(t,e,n.A),t+"")}},52789:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){return function(e){return t(e)}}},90565:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=r(43988);const i=function(t){var e=new t.constructor(t.byteLength);return new n.A(e).set(new n.A(t)),e}},80154:(t,e,r)=>{"use strict";r.d(e,{A:()=>l});var n=r(41917),i="object"==typeof exports&&exports&&!exports.nodeType&&exports,a=i&&"object"==typeof module&&module&&!module.nodeType&&module,o=a&&a.exports===i?n.A.Buffer:void 0,s=o?o.allocUnsafe:void 0;const l=function(t,e){if(e)return t.slice();var r=t.length,n=s?s(r):new t.constructor(r);return t.copy(n),n}},1801:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=r(90565);const i=function(t,e){var r=e?(0,n.A)(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}},39759:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t,e){var r=-1,n=t.length;for(e||(e=Array(n));++r<n;)e[r]=t[r];return e}},22031:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(52851),i=r(52528);const a=function(t,e,r,a){var o=!r;r||(r={});for(var s=-1,l=e.length;++s<l;){var c=e[s],h=a?a(r[c],t[c],c,r,t):void 0;void 0===h&&(h=t[c]),o?(0,i.A)(r,c,h):(0,n.A)(r,c,h)}return r}},3767:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(24326),i=r(6832);const a=function(t){return(0,n.A)((function(e,r){var n=-1,a=r.length,o=a>1?r[a-1]:void 0,s=a>2?r[2]:void 0;for(o=t.length>3&&"function"==typeof o?(a--,o):void 0,s&&(0,i.A)(r[0],r[1],s)&&(o=a<3?void 0:o,a=1),e=Object(e);++n<a;){var l=r[n];l&&t(e,l,n,o)}return e}))}},84171:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=r(18744);const i=function(){try{var t=(0,n.A)(Object,"defineProperty");return t({},"",{}),t}catch(e){}}()},72136:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n="object"==typeof global&&global&&global.Object===Object&&global},18744:(t,e,r)=>{"use strict";r.d(e,{A:()=>x});var n=r(89610);const i=r(41917).A["__core-js_shared__"];var a,o=(a=/[^.]+$/.exec(i&&i.keys&&i.keys.IE_PROTO||""))?"Symbol(src)_1."+a:"";const s=function(t){return!!o&&o in t};var l=r(23149),c=r(81121),h=/^\[object .+?Constructor\]$/,u=Function.prototype,d=Object.prototype,p=u.toString,f=d.hasOwnProperty,g=RegExp("^"+p.call(f).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");const m=function(t){return!(!(0,l.A)(t)||s(t))&&((0,n.A)(t)?g:h).test((0,c.A)(t))};const y=function(t,e){return null==t?void 0:t[e]};const x=function(t,e){var r=y(t,e);return m(r)?r:void 0}},15647:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=(0,r(40367).A)(Object.getPrototypeOf,Object)},9779:(t,e,r)=>{"use strict";r.d(e,{A:()=>_});var n=r(18744),i=r(41917);const a=(0,n.A)(i.A,"DataView");var o=r(68335);const s=(0,n.A)(i.A,"Promise");var l=r(39857);const c=(0,n.A)(i.A,"WeakMap");var h=r(88496),u=r(81121),d="[object Map]",p="[object Promise]",f="[object Set]",g="[object WeakMap]",m="[object DataView]",y=(0,u.A)(a),x=(0,u.A)(o.A),b=(0,u.A)(s),k=(0,u.A)(l.A),C=(0,u.A)(c),w=h.A;(a&&w(new a(new ArrayBuffer(1)))!=m||o.A&&w(new o.A)!=d||s&&w(s.resolve())!=p||l.A&&w(new l.A)!=f||c&&w(new c)!=g)&&(w=function(t){var e=(0,h.A)(t),r="[object Object]"==e?t.constructor:void 0,n=r?(0,u.A)(r):"";if(n)switch(n){case y:return m;case x:return d;case b:return p;case k:return f;case C:return g}return e});const _=w},18598:(t,e,r)=>{"use strict";r.d(e,{A:()=>l});var n=r(23149),i=Object.create;const a=function(){function t(){}return function(e){if(!(0,n.A)(e))return{};if(i)return i(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();var o=r(15647),s=r(97271);const l=function(t){return"function"!=typeof t.constructor||(0,s.A)(t)?{}:a((0,o.A)(t))}},25353:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=/^(?:0|[1-9]\d*)$/;const i=function(t,e){var r=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==r||"symbol"!=r&&n.test(t))&&t>-1&&t%1==0&&t<e}},6832:(t,e,r)=>{"use strict";r.d(e,{A:()=>s});var n=r(66984),i=r(38446),a=r(25353),o=r(23149);const s=function(t,e,r){if(!(0,o.A)(r))return!1;var s=typeof e;return!!("number"==s?(0,i.A)(r)&&(0,a.A)(e,r.length):"string"==s&&e in r)&&(0,n.A)(r[e],t)}},97271:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=Object.prototype;const i=function(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||n)}},64841:(t,e,r)=>{"use strict";r.d(e,{A:()=>s});var n=r(72136),i="object"==typeof exports&&exports&&!exports.nodeType&&exports,a=i&&"object"==typeof module&&module&&!module.nodeType&&module,o=a&&a.exports===i&&n.A.process;const s=function(){try{var t=a&&a.require&&a.require("util").types;return t||o&&o.binding&&o.binding("util")}catch(e){}}()},40367:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t,e){return function(r){return t(e(r))}}},76875:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});const n=function(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)};var i=Math.max;const a=function(t,e,r){return e=i(void 0===e?t.length-1:e,0),function(){for(var a=arguments,o=-1,s=i(a.length-e,0),l=Array(s);++o<s;)l[o]=a[e+o];o=-1;for(var c=Array(e+1);++o<e;)c[o]=a[o];return c[e]=r(l),n(t,this,c)}}},41917:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(72136),i="object"==typeof self&&self&&self.Object===Object&&self;const a=n.A||i||Function("return this")()},67525:(t,e,r)=>{"use strict";r.d(e,{A:()=>l});var n=r(39142),i=r(84171),a=r(29008);const o=i.A?function(t,e){return(0,i.A)(t,"toString",{configurable:!0,enumerable:!1,value:(0,n.A)(e),writable:!0})}:a.A;var s=Date.now;const l=function(t){var e=0,r=0;return function(){var n=s(),i=16-(n-r);if(r=n,i>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(o)},81121:(t,e,r)=>{"use strict";r.d(e,{A:()=>i});var n=Function.prototype.toString;const i=function(t){if(null!=t){try{return n.call(t)}catch(e){}try{return t+""}catch(e){}}return""}},39142:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){return function(){return t}}},66984:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t,e){return t===e||t!=t&&e!=e}},29008:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){return t}},52274:(t,e,r)=>{"use strict";r.d(e,{A:()=>c});var n=r(88496),i=r(53098);const a=function(t){return(0,i.A)(t)&&"[object Arguments]"==(0,n.A)(t)};var o=Object.prototype,s=o.hasOwnProperty,l=o.propertyIsEnumerable;const c=a(function(){return arguments}())?a:function(t){return(0,i.A)(t)&&s.call(t,"callee")&&!l.call(t,"callee")}},92049:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=Array.isArray},38446:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(89610),i=r(5254);const a=function(t){return null!=t&&(0,i.A)(t.length)&&!(0,n.A)(t)}},53533:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(38446),i=r(53098);const a=function(t){return(0,i.A)(t)&&(0,n.A)(t)}},99912:(t,e,r)=>{"use strict";r.d(e,{A:()=>l});var n=r(41917);const i=function(){return!1};var a="object"==typeof exports&&exports&&!exports.nodeType&&exports,o=a&&"object"==typeof module&&module&&!module.nodeType&&module,s=o&&o.exports===a?n.A.Buffer:void 0;const l=(s?s.isBuffer:void 0)||i},66401:(t,e,r)=>{"use strict";r.d(e,{A:()=>d});var n=r(69471),i=r(9779),a=r(52274),o=r(92049),s=r(38446),l=r(99912),c=r(97271),h=r(33858),u=Object.prototype.hasOwnProperty;const d=function(t){if(null==t)return!0;if((0,s.A)(t)&&((0,o.A)(t)||"string"==typeof t||"function"==typeof t.splice||(0,l.A)(t)||(0,h.A)(t)||(0,a.A)(t)))return!t.length;var e=(0,i.A)(t);if("[object Map]"==e||"[object Set]"==e)return!t.size;if((0,c.A)(t))return!(0,n.A)(t).length;for(var r in t)if(u.call(t,r))return!1;return!0}},89610:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(88496),i=r(23149);const a=function(t){if(!(0,i.A)(t))return!1;var e=(0,n.A)(t);return"[object Function]"==e||"[object GeneratorFunction]"==e||"[object AsyncFunction]"==e||"[object Proxy]"==e}},5254:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}},23149:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}},53098:(t,e,r)=>{"use strict";r.d(e,{A:()=>n});const n=function(t){return null!=t&&"object"==typeof t}},33858:(t,e,r)=>{"use strict";r.d(e,{A:()=>u});var n=r(88496),i=r(5254),a=r(53098),o={};o["[object Float32Array]"]=o["[object Float64Array]"]=o["[object Int8Array]"]=o["[object Int16Array]"]=o["[object Int32Array]"]=o["[object Uint8Array]"]=o["[object Uint8ClampedArray]"]=o["[object Uint16Array]"]=o["[object Uint32Array]"]=!0,o["[object Arguments]"]=o["[object Array]"]=o["[object ArrayBuffer]"]=o["[object Boolean]"]=o["[object DataView]"]=o["[object Date]"]=o["[object Error]"]=o["[object Function]"]=o["[object Map]"]=o["[object Number]"]=o["[object Object]"]=o["[object RegExp]"]=o["[object Set]"]=o["[object String]"]=o["[object WeakMap]"]=!1;const s=function(t){return(0,a.A)(t)&&(0,i.A)(t.length)&&!!o[(0,n.A)(t)]};var l=r(52789),c=r(64841),h=c.A&&c.A.isTypedArray;const u=h?(0,l.A)(h):s},55615:(t,e,r)=>{"use strict";r.d(e,{A:()=>h});var n=r(83607),i=r(23149),a=r(97271);const o=function(t){var e=[];if(null!=t)for(var r in Object(t))e.push(r);return e};var s=Object.prototype.hasOwnProperty;const l=function(t){if(!(0,i.A)(t))return o(t);var e=(0,a.A)(t),r=[];for(var n in t)("constructor"!=n||!e&&s.call(t,n))&&r.push(n);return r};var c=r(38446);const h=function(t){return(0,c.A)(t)?(0,n.A)(t,!0):l(t)}},46632:(t,e,r)=>{"use strict";r.d(e,{A:()=>a});var n=r(29471);function i(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new TypeError("Expected a function");var r=function(){var n=arguments,i=e?e.apply(this,n):n[0],a=r.cache;if(a.has(i))return a.get(i);var o=t.apply(this,n);return r.cache=a.set(i,o)||a,o};return r.cache=new(i.Cache||n.A),r}i.Cache=n.A;const a=i},42837:(t,e,r)=>{"use strict";r.d(e,{A:()=>N});var n=r(11754),i=r(52528),a=r(66984);const o=function(t,e,r){(void 0!==r&&!(0,a.A)(t[e],r)||void 0===r&&!(e in t))&&(0,i.A)(t,e,r)};var s=r(4574),l=r(80154),c=r(1801),h=r(39759),u=r(18598),d=r(52274),p=r(92049),f=r(53533),g=r(99912),m=r(89610),y=r(23149),x=r(88496),b=r(15647),k=r(53098),C=Function.prototype,w=Object.prototype,_=C.toString,v=w.hasOwnProperty,S=_.call(Object);const A=function(t){if(!(0,k.A)(t)||"[object Object]"!=(0,x.A)(t))return!1;var e=(0,b.A)(t);if(null===e)return!0;var r=v.call(e,"constructor")&&e.constructor;return"function"==typeof r&&r instanceof r&&_.call(r)==S};var T=r(33858);const M=function(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]};var B=r(22031),L=r(55615);const F=function(t){return(0,B.A)(t,(0,L.A)(t))};const $=function(t,e,r,n,i,a,s){var x=M(t,r),b=M(e,r),k=s.get(b);if(k)o(t,r,k);else{var C=a?a(x,b,r+"",t,e,s):void 0,w=void 0===C;if(w){var _=(0,p.A)(b),v=!_&&(0,g.A)(b),S=!_&&!v&&(0,T.A)(b);C=b,_||v||S?(0,p.A)(x)?C=x:(0,f.A)(x)?C=(0,h.A)(x):v?(w=!1,C=(0,l.A)(b,!0)):S?(w=!1,C=(0,c.A)(b,!0)):C=[]:A(b)||(0,d.A)(b)?(C=x,(0,d.A)(x)?C=F(x):(0,y.A)(x)&&!(0,m.A)(x)||(C=(0,u.A)(b))):w=!1}w&&(s.set(b,C),i(C,b,n,a,s),s.delete(b)),o(t,r,C)}};const E=function t(e,r,i,a,l){e!==r&&(0,s.A)(r,(function(s,c){if(l||(l=new n.A),(0,y.A)(s))$(e,r,c,i,t,a,l);else{var h=a?a(M(e,c),s,c+"",e,r,l):void 0;void 0===h&&(h=s),o(e,c,h)}}),L.A)};const N=(0,r(3767).A)((function(t,e,r){E(t,e,r)}))},47588:(t,e,r)=>{"use strict";r.d(e,{R:()=>s});var n=r(10009),i={aggregation:18,extension:18,composition:18,dependency:6,lollipop:13.5,arrow_point:4};function a(t,e){if(void 0===t||void 0===e)return{angle:0,deltaX:0,deltaY:0};t=o(t),e=o(e);const[r,n]=[t.x,t.y],[i,a]=[e.x,e.y],s=i-r,l=a-n;return{angle:Math.atan(l/s),deltaX:s,deltaY:l}}(0,n.K2)(a,"calculateDeltaAndAngle");var o=(0,n.K2)((t=>Array.isArray(t)?{x:t[0],y:t[1]}:t),"pointTransformer"),s=(0,n.K2)((t=>({x:(0,n.K2)((function(e,r,n){let s=0;const l=o(n[0]).x<o(n[n.length-1]).x?"left":"right";if(0===r&&Object.hasOwn(i,t.arrowTypeStart)){const{angle:e,deltaX:r}=a(n[0],n[1]);s=i[t.arrowTypeStart]*Math.cos(e)*(r>=0?1:-1)}else if(r===n.length-1&&Object.hasOwn(i,t.arrowTypeEnd)){const{angle:e,deltaX:r}=a(n[n.length-1],n[n.length-2]);s=i[t.arrowTypeEnd]*Math.cos(e)*(r>=0?1:-1)}const c=Math.abs(o(e).x-o(n[n.length-1]).x),h=Math.abs(o(e).y-o(n[n.length-1]).y),u=Math.abs(o(e).x-o(n[0]).x),d=Math.abs(o(e).y-o(n[0]).y),p=i[t.arrowTypeStart],f=i[t.arrowTypeEnd];if(c<f&&c>0&&h<f){let t=f+1-c;t*="right"===l?-1:1,s-=t}if(u<p&&u>0&&d<p){let t=p+1-u;t*="right"===l?-1:1,s+=t}return o(e).x+s}),"x"),y:(0,n.K2)((function(e,r,n){let s=0;const l=o(n[0]).y<o(n[n.length-1]).y?"down":"up";if(0===r&&Object.hasOwn(i,t.arrowTypeStart)){const{angle:e,deltaY:r}=a(n[0],n[1]);s=i[t.arrowTypeStart]*Math.abs(Math.sin(e))*(r>=0?1:-1)}else if(r===n.length-1&&Object.hasOwn(i,t.arrowTypeEnd)){const{angle:e,deltaY:r}=a(n[n.length-1],n[n.length-2]);s=i[t.arrowTypeEnd]*Math.abs(Math.sin(e))*(r>=0?1:-1)}const c=Math.abs(o(e).y-o(n[n.length-1]).y),h=Math.abs(o(e).x-o(n[n.length-1]).x),u=Math.abs(o(e).y-o(n[0]).y),d=Math.abs(o(e).x-o(n[0]).x),p=i[t.arrowTypeStart],f=i[t.arrowTypeEnd];if(c<f&&c>0&&h<f){let t=f+1-c;t*="up"===l?-1:1,s-=t}if(u<p&&u>0&&d<p){let t=p+1-u;t*="up"===l?-1:1,s+=t}return o(e).y+s}),"y")})),"getLineFunctionsWithOffset")},33115:(t,e,r)=>{"use strict";r.d(e,{O:()=>n});var n=(0,r(10009).K2)((({flowchart:t})=>{const e=t?.subGraphTitleMargin?.top??0,r=t?.subGraphTitleMargin?.bottom??0;return{subGraphTitleTopMargin:e,subGraphTitleBottomMargin:r,subGraphTitleTotalMargin:e+r}}),"getSubGraphTitleMargins")},37938:(t,e,r)=>{"use strict";r.d(e,{IU:()=>m,Jo:()=>T,T_:()=>k,g0:()=>L,jP:()=>x});var n=r(1282),i=r(47588),a=r(33115),o=r(10483),s=r(8159),l=r(10009),c=r(20007),h=r(29893),u=(0,l.K2)(((t,e,r,n,i)=>{e.arrowTypeStart&&p(t,"start",e.arrowTypeStart,r,n,i),e.arrowTypeEnd&&p(t,"end",e.arrowTypeEnd,r,n,i)}),"addEdgeMarkers"),d={arrow_cross:"cross",arrow_point:"point",arrow_barb:"barb",arrow_circle:"circle",aggregation:"aggregation",extension:"extension",composition:"composition",dependency:"dependency",lollipop:"lollipop"},p=(0,l.K2)(((t,e,r,n,i,a)=>{const o=d[r];if(!o)return void l.Rm.warn(`Unknown arrow type: ${r}`);const s="start"===e?"Start":"End";t.attr(`marker-${e}`,`url(${n}#${i}_${a}-${o}${s})`)}),"addEdgeMarker"),f=new Map,g=new Map,m=(0,l.K2)((()=>{f.clear(),g.clear()}),"clear"),y=(0,l.K2)((t=>t?t.reduce(((t,e)=>t+";"+e),""):""),"getLabelStyles"),x=(0,l.K2)((async(t,e)=>{let r=(0,l._3)((0,l.D7)().flowchart.htmlLabels);const i=await(0,o.GZ)(t,e.label,{style:y(e.labelStyle),useHtmlLabels:r,addSvgBackground:!0,isNode:!1});l.Rm.info("abc82",e,e.labelType);const a=t.insert("g").attr("class","edgeLabel"),s=a.insert("g").attr("class","label");s.node().appendChild(i);let h,u=i.getBBox();if(r){const t=i.children[0],e=(0,c.Ltv)(i);u=t.getBoundingClientRect(),e.attr("width",u.width),e.attr("height",u.height)}if(s.attr("transform","translate("+-u.width/2+", "+-u.height/2+")"),f.set(e.id,a),e.width=u.width,e.height=u.height,e.startLabelLeft){const r=await(0,n.DA)(e.startLabelLeft,y(e.labelStyle)),i=t.insert("g").attr("class","edgeTerminals"),a=i.insert("g").attr("class","inner");h=a.node().appendChild(r);const o=r.getBBox();a.attr("transform","translate("+-o.width/2+", "+-o.height/2+")"),g.get(e.id)||g.set(e.id,{}),g.get(e.id).startLeft=i,b(h,e.startLabelLeft)}if(e.startLabelRight){const r=await(0,n.DA)(e.startLabelRight,y(e.labelStyle)),i=t.insert("g").attr("class","edgeTerminals"),a=i.insert("g").attr("class","inner");h=i.node().appendChild(r),a.node().appendChild(r);const o=r.getBBox();a.attr("transform","translate("+-o.width/2+", "+-o.height/2+")"),g.get(e.id)||g.set(e.id,{}),g.get(e.id).startRight=i,b(h,e.startLabelRight)}if(e.endLabelLeft){const r=await(0,n.DA)(e.endLabelLeft,y(e.labelStyle)),i=t.insert("g").attr("class","edgeTerminals"),a=i.insert("g").attr("class","inner");h=a.node().appendChild(r);const o=r.getBBox();a.attr("transform","translate("+-o.width/2+", "+-o.height/2+")"),i.node().appendChild(r),g.get(e.id)||g.set(e.id,{}),g.get(e.id).endLeft=i,b(h,e.endLabelLeft)}if(e.endLabelRight){const r=await(0,n.DA)(e.endLabelRight,y(e.labelStyle)),i=t.insert("g").attr("class","edgeTerminals"),a=i.insert("g").attr("class","inner");h=a.node().appendChild(r);const o=r.getBBox();a.attr("transform","translate("+-o.width/2+", "+-o.height/2+")"),i.node().appendChild(r),g.get(e.id)||g.set(e.id,{}),g.get(e.id).endRight=i,b(h,e.endLabelRight)}return i}),"insertEdgeLabel");function b(t,e){(0,l.D7)().flowchart.htmlLabels&&t&&(t.style.width=9*e.length+"px",t.style.height="12px")}(0,l.K2)(b,"setTerminalWidth");var k=(0,l.K2)(((t,e)=>{l.Rm.debug("Moving label abc88 ",t.id,t.label,f.get(t.id),e);let r=e.updatedPath?e.updatedPath:e.originalPath;const n=(0,l.D7)(),{subGraphTitleTotalMargin:i}=(0,a.O)(n);if(t.label){const n=f.get(t.id);let a=t.x,o=t.y;if(r){const n=s._K.calcLabelPosition(r);l.Rm.debug("Moving label "+t.label+" from (",a,",",o,") to (",n.x,",",n.y,") abc88"),e.updatedPath&&(a=n.x,o=n.y)}n.attr("transform",`translate(${a}, ${o+i/2})`)}if(t.startLabelLeft){const e=g.get(t.id).startLeft;let n=t.x,i=t.y;if(r){const e=s._K.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_left",r);n=e.x,i=e.y}e.attr("transform",`translate(${n}, ${i})`)}if(t.startLabelRight){const e=g.get(t.id).startRight;let n=t.x,i=t.y;if(r){const e=s._K.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_right",r);n=e.x,i=e.y}e.attr("transform",`translate(${n}, ${i})`)}if(t.endLabelLeft){const e=g.get(t.id).endLeft;let n=t.x,i=t.y;if(r){const e=s._K.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_left",r);n=e.x,i=e.y}e.attr("transform",`translate(${n}, ${i})`)}if(t.endLabelRight){const e=g.get(t.id).endRight;let n=t.x,i=t.y;if(r){const e=s._K.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_right",r);n=e.x,i=e.y}e.attr("transform",`translate(${n}, ${i})`)}}),"positionEdgeLabel"),C=(0,l.K2)(((t,e)=>{const r=t.x,n=t.y,i=Math.abs(e.x-r),a=Math.abs(e.y-n),o=t.width/2,s=t.height/2;return i>=o||a>=s}),"outsideNode"),w=(0,l.K2)(((t,e,r)=>{l.Rm.debug(`intersection calc abc89:\n outsidePoint: ${JSON.stringify(e)}\n insidePoint : ${JSON.stringify(r)}\n node : x:${t.x} y:${t.y} w:${t.width} h:${t.height}`);const n=t.x,i=t.y,a=Math.abs(n-r.x),o=t.width/2;let s=r.x<e.x?o-a:o+a;const c=t.height/2,h=Math.abs(e.y-r.y),u=Math.abs(e.x-r.x);if(Math.abs(i-e.y)*o>Math.abs(n-e.x)*c){let t=r.y<e.y?e.y-c-i:i-c-e.y;s=u*t/h;const n={x:r.x<e.x?r.x+s:r.x-u+s,y:r.y<e.y?r.y+h-t:r.y-h+t};return 0===s&&(n.x=e.x,n.y=e.y),0===u&&(n.x=e.x),0===h&&(n.y=e.y),l.Rm.debug(`abc89 top/bottom calc, Q ${h}, q ${t}, R ${u}, r ${s}`,n),n}{s=r.x<e.x?e.x-o-n:n-o-e.x;let t=h*s/u,i=r.x<e.x?r.x+u-s:r.x-u+s,a=r.y<e.y?r.y+t:r.y-t;return l.Rm.debug(`sides calc abc89, Q ${h}, q ${t}, R ${u}, r ${s}`,{_x:i,_y:a}),0===s&&(i=e.x,a=e.y),0===u&&(i=e.x),0===h&&(a=e.y),{x:i,y:a}}}),"intersection"),_=(0,l.K2)(((t,e)=>{l.Rm.warn("abc88 cutPathAtIntersect",t,e);let r=[],n=t[0],i=!1;return t.forEach((t=>{if(l.Rm.info("abc88 checking point",t,e),C(e,t)||i)l.Rm.warn("abc88 outside",t,n),n=t,i||r.push(t);else{const a=w(e,n,t);l.Rm.debug("abc88 inside",t,n,a),l.Rm.debug("abc88 intersection",a,e);let o=!1;r.forEach((t=>{o=o||t.x===a.x&&t.y===a.y})),r.some((t=>t.x===a.x&&t.y===a.y))?l.Rm.warn("abc88 no intersect",a,r):r.push(a),i=!0}})),l.Rm.debug("returning points",r),r}),"cutPathAtIntersect");function v(t){const e=[],r=[];for(let n=1;n<t.length-1;n++){const i=t[n-1],a=t[n],o=t[n+1];(i.x===a.x&&a.y===o.y&&Math.abs(a.x-o.x)>5&&Math.abs(a.y-i.y)>5||i.y===a.y&&a.x===o.x&&Math.abs(a.x-i.x)>5&&Math.abs(a.y-o.y)>5)&&(e.push(a),r.push(n))}return{cornerPoints:e,cornerPointPositions:r}}(0,l.K2)(v,"extractCornerPoints");var S=(0,l.K2)((function(t,e,r){const n=e.x-t.x,i=e.y-t.y,a=r/Math.sqrt(n*n+i*i);return{x:e.x-a*n,y:e.y-a*i}}),"findAdjacentPoint"),A=(0,l.K2)((function(t){const{cornerPointPositions:e}=v(t),r=[];for(let n=0;n<t.length;n++)if(e.includes(n)){const e=t[n-1],i=t[n+1],a=t[n],o=S(e,a,5),s=S(i,a,5),c=s.x-o.x,h=s.y-o.y;r.push(o);const u=2*Math.sqrt(2);let d={x:a.x,y:a.y};if(Math.abs(i.x-e.x)>10&&Math.abs(i.y-e.y)>=10){l.Rm.debug("Corner point fixing",Math.abs(i.x-e.x),Math.abs(i.y-e.y));const t=5;d=a.x===o.x?{x:c<0?o.x-t+u:o.x+t-u,y:h<0?o.y-u:o.y+u}:{x:c<0?o.x-u:o.x+u,y:h<0?o.y-t+u:o.y+t-u}}else l.Rm.debug("Corner point skipping fixing",Math.abs(i.x-e.x),Math.abs(i.y-e.y));r.push(d,s)}else r.push(t[n]);return r}),"fixCorners"),T=(0,l.K2)((function(t,e,r,n,a,o,s){const{handDrawnSeed:d}=(0,l.D7)();let p=e.points,f=!1;const g=a;var m=o;m.intersect&&g.intersect&&(p=p.slice(1,e.points.length-1),p.unshift(g.intersect(p[0])),l.Rm.debug("Last point APA12",e.start,"--\x3e",e.end,p[p.length-1],m,m.intersect(p[p.length-1])),p.push(m.intersect(p[p.length-1]))),e.toCluster&&(l.Rm.info("to cluster abc88",r.get(e.toCluster)),p=_(e.points,r.get(e.toCluster).node),f=!0),e.fromCluster&&(l.Rm.debug("from cluster abc88",r.get(e.fromCluster),JSON.stringify(p,null,2)),p=_(p.reverse(),r.get(e.fromCluster).node).reverse(),f=!0);let y=p.filter((t=>!Number.isNaN(t.y)));y=A(y);let x=c.qrM;e.curve&&(x=e.curve);const{x:b,y:k}=(0,i.R)(e),C=(0,c.n8j)().x(b).y(k).curve(x);let w,v;switch(e.thickness){case"normal":default:w="edge-thickness-normal";break;case"thick":w="edge-thickness-thick";break;case"invisible":w="edge-thickness-invisible"}switch(e.pattern){case"solid":default:w+=" edge-pattern-solid";break;case"dotted":w+=" edge-pattern-dotted";break;case"dashed":w+=" edge-pattern-dashed"}let S=C(y);const T=Array.isArray(e.style)?e.style:[e.style];if("handDrawn"===e.look){const r=h.A.svg(t);Object.assign([],y);const n=r.path(S,{roughness:.3,seed:d});w+=" transition",v=(0,c.Ltv)(n).select("path").attr("id",e.id).attr("class"," "+w+(e.classes?" "+e.classes:"")).attr("style",T?T.reduce(((t,e)=>t+";"+e),""):"");let i=v.attr("d");v.attr("d",i),t.node().appendChild(v.node())}else v=t.append("path").attr("d",S).attr("id",e.id).attr("class"," "+w+(e.classes?" "+e.classes:"")).attr("style",T?T.reduce(((t,e)=>t+";"+e),""):"");let M="";((0,l.D7)().flowchart.arrowMarkerAbsolute||(0,l.D7)().state.arrowMarkerAbsolute)&&(M=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,M=M.replace(/\(/g,"\\(").replace(/\)/g,"\\)")),l.Rm.info("arrowTypeStart",e.arrowTypeStart),l.Rm.info("arrowTypeEnd",e.arrowTypeEnd),u(v,e,M,s,n);let B={};return f&&(B.updatedPath=p),B.originalPath=e.points,B}),"insertEdge"),M=(0,l.K2)(((t,e,r,n)=>{e.forEach((e=>{B[e](t,r,n)}))}),"insertMarkers"),B={extension:(0,l.K2)(((t,e,r)=>{l.Rm.trace("Making markers for ",r),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionStart").attr("class","marker extension "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionEnd").attr("class","marker extension "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z")}),"extension"),composition:(0,l.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionStart").attr("class","marker composition "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionEnd").attr("class","marker composition "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")}),"composition"),aggregation:(0,l.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationStart").attr("class","marker aggregation "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationEnd").attr("class","marker aggregation "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")}),"aggregation"),dependency:(0,l.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyStart").attr("class","marker dependency "+e).attr("refX",6).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyEnd").attr("class","marker dependency "+e).attr("refX",13).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")}),"dependency"),lollipop:(0,l.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopStart").attr("class","marker lollipop "+e).attr("refX",13).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6),t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopEnd").attr("class","marker lollipop "+e).attr("refX",1).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6)}),"lollipop"),point:(0,l.K2)(((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-pointEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",8).attr("markerHeight",8).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-pointStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",4.5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",8).attr("markerHeight",8).attr("orient","auto").append("path").attr("d","M 0 5 L 10 10 L 10 0 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")}),"point"),circle:(0,l.K2)(((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-circleEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",11).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-circleStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",-1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")}),"circle"),cross:(0,l.K2)(((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-crossEnd").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",12).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-crossStart").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",-1).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0")}),"cross"),barb:(0,l.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-barbEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",14).attr("markerUnits","userSpaceOnUse").attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")}),"barb")},L=M},10009:(t,e,r)=>{"use strict";r.d(e,{C0:()=>S,VA:()=>y,K2:()=>m,xA:()=>ut,hH:()=>$,Dl:()=>Pt,IU:()=>re,Wt:()=>Xt,Y2:()=>Kt,a$:()=>Ht,sb:()=>J,ME:()=>pe,UI:()=>Z,Ch:()=>T,mW:()=>A,DB:()=>_,_3:()=>Lt,EJ:()=>w,m7:()=>oe,iN:()=>ie,zj:()=>ct,D7:()=>ue,Gs:()=>be,J$:()=>L,ab:()=>le,Q2:()=>st,P$:()=>z,Wi:()=>Rt,H1:()=>yt,Rm:()=>b,QO:()=>Et,Js:()=>xe,Xd:()=>M,VJ:()=>zt,cL:()=>dt,$i:()=>X,jZ:()=>_t,oB:()=>fe,wZ:()=>at,EI:()=>ae,SV:()=>ne,Nk:()=>lt,XV:()=>de,ke:()=>se,He:()=>k,UU:()=>it,ot:()=>Ut,mj:()=>ge,tM:()=>Zt,H$:()=>H,B6:()=>ot});var n=r(74353),i=r(74886),a=r(8232);const o=(t,e)=>{const r=i.A.parse(t),n={};for(const i in e)e[i]&&(n[i]=r[i]+e[i]);return(0,a.A)(t,n)};var s=r(25582);const l=(t,e,r=50)=>{const{r:n,g:a,b:o,a:l}=i.A.parse(t),{r:c,g:h,b:u,a:d}=i.A.parse(e),p=r/100,f=2*p-1,g=l-d,m=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,y=1-m,x=n*m+c*y,b=a*m+h*y,k=o*m+u*y,C=l*p+d*(1-p);return(0,s.A)(x,b,k,C)},c=(t,e=100)=>{const r=i.A.parse(t);return r.r=255-r.r,r.g=255-r.g,r.b=255-r.b,l(r,t,e)};var h,u=r(75263),d=r(78041),p=r(3219),f=r(99418),g=Object.defineProperty,m=(t,e)=>g(t,"name",{value:e,configurable:!0}),y=(t,e)=>{for(var r in e)g(t,r,{get:e[r],enumerable:!0})},x={trace:0,debug:1,info:2,warn:3,error:4,fatal:5},b={trace:m(((...t)=>{}),"trace"),debug:m(((...t)=>{}),"debug"),info:m(((...t)=>{}),"info"),warn:m(((...t)=>{}),"warn"),error:m(((...t)=>{}),"error"),fatal:m(((...t)=>{}),"fatal")},k=m((function(t="fatal"){let e=x.fatal;"string"==typeof t?t.toLowerCase()in x&&(e=x[t]):"number"==typeof t&&(e=t),b.trace=()=>{},b.debug=()=>{},b.info=()=>{},b.warn=()=>{},b.error=()=>{},b.fatal=()=>{},e<=x.fatal&&(b.fatal=console.error?console.error.bind(console,C("FATAL"),"color: orange"):console.log.bind(console,"\x1b[35m",C("FATAL"))),e<=x.error&&(b.error=console.error?console.error.bind(console,C("ERROR"),"color: orange"):console.log.bind(console,"\x1b[31m",C("ERROR"))),e<=x.warn&&(b.warn=console.warn?console.warn.bind(console,C("WARN"),"color: orange"):console.log.bind(console,"\x1b[33m",C("WARN"))),e<=x.info&&(b.info=console.info?console.info.bind(console,C("INFO"),"color: lightblue"):console.log.bind(console,"\x1b[34m",C("INFO"))),e<=x.debug&&(b.debug=console.debug?console.debug.bind(console,C("DEBUG"),"color: lightgreen"):console.log.bind(console,"\x1b[32m",C("DEBUG"))),e<=x.trace&&(b.trace=console.debug?console.debug.bind(console,C("TRACE"),"color: lightgreen"):console.log.bind(console,"\x1b[32m",C("TRACE")))}),"setLogLevel"),C=m((t=>`%c${n().format("ss.SSS")} : ${t} : `),"format"),w=/^-{3}\s*[\n\r](.*?)[\n\r]-{3}\s*[\n\r]+/s,_=/%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi,v=/\s*%%.*\n/gm,S=class extends Error{static{m(this,"UnknownDiagramError")}constructor(t){super(t),this.name="UnknownDiagramError"}},A={},T=m((function(t,e){t=t.replace(w,"").replace(_,"").replace(v,"\n");for(const[r,{detector:n}]of Object.entries(A)){if(n(t,e))return r}throw new S(`No diagram type detected matching given configuration for text: ${t}`)}),"detectType"),M=m(((...t)=>{for(const{id:e,detector:r,loader:n}of t)B(e,r,n)}),"registerLazyLoadedDiagrams"),B=m(((t,e,r)=>{A[t]&&b.warn(`Detector with key ${t} already exists. Overwriting.`),A[t]={detector:e,loader:r},b.debug(`Detector with key ${t} added${r?" with loader":""}`)}),"addDetector"),L=m((t=>A[t].loader),"getDiagramLoader"),F=m(((t,e,{depth:r=2,clobber:n=!1}={})=>{const i={depth:r,clobber:n};return Array.isArray(e)&&!Array.isArray(t)?(e.forEach((e=>F(t,e,i))),t):Array.isArray(e)&&Array.isArray(t)?(e.forEach((e=>{t.includes(e)||t.push(e)})),t):void 0===t||r<=0?null!=t&&"object"==typeof t&&"object"==typeof e?Object.assign(t,e):e:(void 0!==e&&"object"==typeof t&&"object"==typeof e&&Object.keys(e).forEach((i=>{"object"!=typeof e[i]||void 0!==t[i]&&"object"!=typeof t[i]?(n||"object"!=typeof t[i]&&"object"!=typeof e[i])&&(t[i]=e[i]):(void 0===t[i]&&(t[i]=Array.isArray(e[i])?[]:{}),t[i]=F(t[i],e[i],{depth:r-1,clobber:n}))})),t)}),"assignWithDepth"),$=F,E="#ffffff",N="#f2f2f2",D=m(((t,e)=>o(t,e?{s:-40,l:10}:{s:-40,l:-10})),"mkBorder"),j=class{static{m(this,"Theme")}constructor(){this.background="#f4f4f4",this.primaryColor="#fff4dd",this.noteBkgColor="#fff5ad",this.noteTextColor="#333",this.THEME_COLOR_LIMIT=12,this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px"}updateColors(){if(this.primaryTextColor=this.primaryTextColor||(this.darkMode?"#eee":"#333"),this.secondaryColor=this.secondaryColor||o(this.primaryColor,{h:-120}),this.tertiaryColor=this.tertiaryColor||o(this.primaryColor,{h:180,l:5}),this.primaryBorderColor=this.primaryBorderColor||D(this.primaryColor,this.darkMode),this.secondaryBorderColor=this.secondaryBorderColor||D(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=this.tertiaryBorderColor||D(this.tertiaryColor,this.darkMode),this.noteBorderColor=this.noteBorderColor||D(this.noteBkgColor,this.darkMode),this.noteBkgColor=this.noteBkgColor||"#fff5ad",this.noteTextColor=this.noteTextColor||"#333",this.secondaryTextColor=this.secondaryTextColor||c(this.secondaryColor),this.tertiaryTextColor=this.tertiaryTextColor||c(this.tertiaryColor),this.lineColor=this.lineColor||c(this.background),this.arrowheadColor=this.arrowheadColor||c(this.background),this.textColor=this.textColor||this.primaryTextColor,this.border2=this.border2||this.tertiaryBorderColor,this.nodeBkg=this.nodeBkg||this.primaryColor,this.mainBkg=this.mainBkg||this.primaryColor,this.nodeBorder=this.nodeBorder||this.primaryBorderColor,this.clusterBkg=this.clusterBkg||this.tertiaryColor,this.clusterBorder=this.clusterBorder||this.tertiaryBorderColor,this.defaultLinkColor=this.defaultLinkColor||this.lineColor,this.titleColor=this.titleColor||this.tertiaryTextColor,this.edgeLabelBackground=this.edgeLabelBackground||(this.darkMode?(0,u.A)(this.secondaryColor,30):this.secondaryColor),this.nodeTextColor=this.nodeTextColor||this.primaryTextColor,this.actorBorder=this.actorBorder||this.primaryBorderColor,this.actorBkg=this.actorBkg||this.mainBkg,this.actorTextColor=this.actorTextColor||this.primaryTextColor,this.actorLineColor=this.actorLineColor||this.actorBorder,this.labelBoxBkgColor=this.labelBoxBkgColor||this.actorBkg,this.signalColor=this.signalColor||this.textColor,this.signalTextColor=this.signalTextColor||this.textColor,this.labelBoxBorderColor=this.labelBoxBorderColor||this.actorBorder,this.labelTextColor=this.labelTextColor||this.actorTextColor,this.loopTextColor=this.loopTextColor||this.actorTextColor,this.activationBorderColor=this.activationBorderColor||(0,u.A)(this.secondaryColor,10),this.activationBkgColor=this.activationBkgColor||this.secondaryColor,this.sequenceNumberColor=this.sequenceNumberColor||c(this.lineColor),this.sectionBkgColor=this.sectionBkgColor||this.tertiaryColor,this.altSectionBkgColor=this.altSectionBkgColor||"white",this.sectionBkgColor=this.sectionBkgColor||this.secondaryColor,this.sectionBkgColor2=this.sectionBkgColor2||this.primaryColor,this.excludeBkgColor=this.excludeBkgColor||"#eeeeee",this.taskBorderColor=this.taskBorderColor||this.primaryBorderColor,this.taskBkgColor=this.taskBkgColor||this.primaryColor,this.activeTaskBorderColor=this.activeTaskBorderColor||this.primaryColor,this.activeTaskBkgColor=this.activeTaskBkgColor||(0,d.A)(this.primaryColor,23),this.gridColor=this.gridColor||"lightgrey",this.doneTaskBkgColor=this.doneTaskBkgColor||"lightgrey",this.doneTaskBorderColor=this.doneTaskBorderColor||"grey",this.critBorderColor=this.critBorderColor||"#ff8888",this.critBkgColor=this.critBkgColor||"red",this.todayLineColor=this.todayLineColor||"red",this.taskTextColor=this.taskTextColor||this.textColor,this.taskTextOutsideColor=this.taskTextOutsideColor||this.textColor,this.taskTextLightColor=this.taskTextLightColor||this.textColor,this.taskTextColor=this.taskTextColor||this.primaryTextColor,this.taskTextDarkColor=this.taskTextDarkColor||this.textColor,this.taskTextClickableColor=this.taskTextClickableColor||"#003163",this.personBorder=this.personBorder||this.primaryBorderColor,this.personBkg=this.personBkg||this.mainBkg,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||this.tertiaryColor,this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.nodeBorder,this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.transitionColor=this.transitionColor||this.lineColor,this.specialStateColor=this.lineColor,this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||o(this.primaryColor,{h:30}),this.cScale4=this.cScale4||o(this.primaryColor,{h:60}),this.cScale5=this.cScale5||o(this.primaryColor,{h:90}),this.cScale6=this.cScale6||o(this.primaryColor,{h:120}),this.cScale7=this.cScale7||o(this.primaryColor,{h:150}),this.cScale8=this.cScale8||o(this.primaryColor,{h:210,l:150}),this.cScale9=this.cScale9||o(this.primaryColor,{h:270}),this.cScale10=this.cScale10||o(this.primaryColor,{h:300}),this.cScale11=this.cScale11||o(this.primaryColor,{h:330}),this.darkMode)for(let e=0;e<this.THEME_COLOR_LIMIT;e++)this["cScale"+e]=(0,u.A)(this["cScale"+e],75);else for(let e=0;e<this.THEME_COLOR_LIMIT;e++)this["cScale"+e]=(0,u.A)(this["cScale"+e],25);for(let e=0;e<this.THEME_COLOR_LIMIT;e++)this["cScaleInv"+e]=this["cScaleInv"+e]||c(this["cScale"+e]);for(let e=0;e<this.THEME_COLOR_LIMIT;e++)this.darkMode?this["cScalePeer"+e]=this["cScalePeer"+e]||(0,d.A)(this["cScale"+e],10):this["cScalePeer"+e]=this["cScalePeer"+e]||(0,u.A)(this["cScale"+e],10);this.scaleLabelColor=this.scaleLabelColor||this.labelTextColor;for(let e=0;e<this.THEME_COLOR_LIMIT;e++)this["cScaleLabel"+e]=this["cScaleLabel"+e]||this.scaleLabelColor;const t=this.darkMode?-4:-1;for(let e=0;e<5;e++)this["surface"+e]=this["surface"+e]||o(this.mainBkg,{h:180,s:-15,l:t*(5+3*e)}),this["surfacePeer"+e]=this["surfacePeer"+e]||o(this.mainBkg,{h:180,s:-15,l:t*(8+3*e)});this.classText=this.classText||this.textColor,this.fillType0=this.fillType0||this.primaryColor,this.fillType1=this.fillType1||this.secondaryColor,this.fillType2=this.fillType2||o(this.primaryColor,{h:64}),this.fillType3=this.fillType3||o(this.secondaryColor,{h:64}),this.fillType4=this.fillType4||o(this.primaryColor,{h:-64}),this.fillType5=this.fillType5||o(this.secondaryColor,{h:-64}),this.fillType6=this.fillType6||o(this.primaryColor,{h:128}),this.fillType7=this.fillType7||o(this.secondaryColor,{h:128}),this.pie1=this.pie1||this.primaryColor,this.pie2=this.pie2||this.secondaryColor,this.pie3=this.pie3||this.tertiaryColor,this.pie4=this.pie4||o(this.primaryColor,{l:-10}),this.pie5=this.pie5||o(this.secondaryColor,{l:-10}),this.pie6=this.pie6||o(this.tertiaryColor,{l:-10}),this.pie7=this.pie7||o(this.primaryColor,{h:60,l:-10}),this.pie8=this.pie8||o(this.primaryColor,{h:-60,l:-10}),this.pie9=this.pie9||o(this.primaryColor,{h:120,l:0}),this.pie10=this.pie10||o(this.primaryColor,{h:60,l:-20}),this.pie11=this.pie11||o(this.primaryColor,{h:-60,l:-20}),this.pie12=this.pie12||o(this.primaryColor,{h:120,l:-10}),this.pieTitleTextSize=this.pieTitleTextSize||"25px",this.pieTitleTextColor=this.pieTitleTextColor||this.taskTextDarkColor,this.pieSectionTextSize=this.pieSectionTextSize||"17px",this.pieSectionTextColor=this.pieSectionTextColor||this.textColor,this.pieLegendTextSize=this.pieLegendTextSize||"17px",this.pieLegendTextColor=this.pieLegendTextColor||this.taskTextDarkColor,this.pieStrokeColor=this.pieStrokeColor||"black",this.pieStrokeWidth=this.pieStrokeWidth||"2px",this.pieOuterStrokeWidth=this.pieOuterStrokeWidth||"2px",this.pieOuterStrokeColor=this.pieOuterStrokeColor||"black",this.pieOpacity=this.pieOpacity||"0.7",this.archEdgeColor=this.archEdgeColor||"#777",this.archEdgeArrowColor=this.archEdgeArrowColor||"#777",this.archEdgeWidth=this.archEdgeWidth||"3",this.archGroupBorderColor=this.archGroupBorderColor||"#000",this.archGroupBorderWidth=this.archGroupBorderWidth||"2px",this.quadrant1Fill=this.quadrant1Fill||this.primaryColor,this.quadrant2Fill=this.quadrant2Fill||o(this.primaryColor,{r:5,g:5,b:5}),this.quadrant3Fill=this.quadrant3Fill||o(this.primaryColor,{r:10,g:10,b:10}),this.quadrant4Fill=this.quadrant4Fill||o(this.primaryColor,{r:15,g:15,b:15}),this.quadrant1TextFill=this.quadrant1TextFill||this.primaryTextColor,this.quadrant2TextFill=this.quadrant2TextFill||o(this.primaryTextColor,{r:-5,g:-5,b:-5}),this.quadrant3TextFill=this.quadrant3TextFill||o(this.primaryTextColor,{r:-10,g:-10,b:-10}),this.quadrant4TextFill=this.quadrant4TextFill||o(this.primaryTextColor,{r:-15,g:-15,b:-15}),this.quadrantPointFill=this.quadrantPointFill||(0,p.A)(this.quadrant1Fill)?(0,d.A)(this.quadrant1Fill):(0,u.A)(this.quadrant1Fill),this.quadrantPointTextFill=this.quadrantPointTextFill||this.primaryTextColor,this.quadrantXAxisTextFill=this.quadrantXAxisTextFill||this.primaryTextColor,this.quadrantYAxisTextFill=this.quadrantYAxisTextFill||this.primaryTextColor,this.quadrantInternalBorderStrokeFill=this.quadrantInternalBorderStrokeFill||this.primaryBorderColor,this.quadrantExternalBorderStrokeFill=this.quadrantExternalBorderStrokeFill||this.primaryBorderColor,this.quadrantTitleFill=this.quadrantTitleFill||this.primaryTextColor,this.xyChart={backgroundColor:this.xyChart?.backgroundColor||this.background,titleColor:this.xyChart?.titleColor||this.primaryTextColor,xAxisTitleColor:this.xyChart?.xAxisTitleColor||this.primaryTextColor,xAxisLabelColor:this.xyChart?.xAxisLabelColor||this.primaryTextColor,xAxisTickColor:this.xyChart?.xAxisTickColor||this.primaryTextColor,xAxisLineColor:this.xyChart?.xAxisLineColor||this.primaryTextColor,yAxisTitleColor:this.xyChart?.yAxisTitleColor||this.primaryTextColor,yAxisLabelColor:this.xyChart?.yAxisLabelColor||this.primaryTextColor,yAxisTickColor:this.xyChart?.yAxisTickColor||this.primaryTextColor,yAxisLineColor:this.xyChart?.yAxisLineColor||this.primaryTextColor,plotColorPalette:this.xyChart?.plotColorPalette||"#FFF4DD,#FFD8B1,#FFA07A,#ECEFF1,#D6DBDF,#C3E0A8,#FFB6A4,#FFD74D,#738FA7,#FFFFF0"},this.requirementBackground=this.requirementBackground||this.primaryColor,this.requirementBorderColor=this.requirementBorderColor||this.primaryBorderColor,this.requirementBorderSize=this.requirementBorderSize||"1",this.requirementTextColor=this.requirementTextColor||this.primaryTextColor,this.relationColor=this.relationColor||this.lineColor,this.relationLabelBackground=this.relationLabelBackground||(this.darkMode?(0,u.A)(this.secondaryColor,30):this.secondaryColor),this.relationLabelColor=this.relationLabelColor||this.actorTextColor,this.git0=this.git0||this.primaryColor,this.git1=this.git1||this.secondaryColor,this.git2=this.git2||this.tertiaryColor,this.git3=this.git3||o(this.primaryColor,{h:-30}),this.git4=this.git4||o(this.primaryColor,{h:-60}),this.git5=this.git5||o(this.primaryColor,{h:-90}),this.git6=this.git6||o(this.primaryColor,{h:60}),this.git7=this.git7||o(this.primaryColor,{h:120}),this.darkMode?(this.git0=(0,d.A)(this.git0,25),this.git1=(0,d.A)(this.git1,25),this.git2=(0,d.A)(this.git2,25),this.git3=(0,d.A)(this.git3,25),this.git4=(0,d.A)(this.git4,25),this.git5=(0,d.A)(this.git5,25),this.git6=(0,d.A)(this.git6,25),this.git7=(0,d.A)(this.git7,25)):(this.git0=(0,u.A)(this.git0,25),this.git1=(0,u.A)(this.git1,25),this.git2=(0,u.A)(this.git2,25),this.git3=(0,u.A)(this.git3,25),this.git4=(0,u.A)(this.git4,25),this.git5=(0,u.A)(this.git5,25),this.git6=(0,u.A)(this.git6,25),this.git7=(0,u.A)(this.git7,25)),this.gitInv0=this.gitInv0||c(this.git0),this.gitInv1=this.gitInv1||c(this.git1),this.gitInv2=this.gitInv2||c(this.git2),this.gitInv3=this.gitInv3||c(this.git3),this.gitInv4=this.gitInv4||c(this.git4),this.gitInv5=this.gitInv5||c(this.git5),this.gitInv6=this.gitInv6||c(this.git6),this.gitInv7=this.gitInv7||c(this.git7),this.branchLabelColor=this.branchLabelColor||(this.darkMode?"black":this.labelTextColor),this.gitBranchLabel0=this.gitBranchLabel0||this.branchLabelColor,this.gitBranchLabel1=this.gitBranchLabel1||this.branchLabelColor,this.gitBranchLabel2=this.gitBranchLabel2||this.branchLabelColor,this.gitBranchLabel3=this.gitBranchLabel3||this.branchLabelColor,this.gitBranchLabel4=this.gitBranchLabel4||this.branchLabelColor,this.gitBranchLabel5=this.gitBranchLabel5||this.branchLabelColor,this.gitBranchLabel6=this.gitBranchLabel6||this.branchLabelColor,this.gitBranchLabel7=this.gitBranchLabel7||this.branchLabelColor,this.tagLabelColor=this.tagLabelColor||this.primaryTextColor,this.tagLabelBackground=this.tagLabelBackground||this.primaryColor,this.tagLabelBorder=this.tagBorder||this.primaryBorderColor,this.tagLabelFontSize=this.tagLabelFontSize||"10px",this.commitLabelColor=this.commitLabelColor||this.secondaryTextColor,this.commitLabelBackground=this.commitLabelBackground||this.secondaryColor,this.commitLabelFontSize=this.commitLabelFontSize||"10px",this.attributeBackgroundColorOdd=this.attributeBackgroundColorOdd||E,this.attributeBackgroundColorEven=this.attributeBackgroundColorEven||N}calculate(t){if("object"!=typeof t)return void this.updateColors();const e=Object.keys(t);e.forEach((e=>{this[e]=t[e]})),this.updateColors(),e.forEach((e=>{this[e]=t[e]}))}},I=m((t=>{const e=new j;return e.calculate(t),e}),"getThemeVariables"),O=class{static{m(this,"Theme")}constructor(){this.background="#333",this.primaryColor="#1f2020",this.secondaryColor=(0,d.A)(this.primaryColor,16),this.tertiaryColor=o(this.primaryColor,{h:-160}),this.primaryBorderColor=c(this.background),this.secondaryBorderColor=D(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=D(this.tertiaryColor,this.darkMode),this.primaryTextColor=c(this.primaryColor),this.secondaryTextColor=c(this.secondaryColor),this.tertiaryTextColor=c(this.tertiaryColor),this.lineColor=c(this.background),this.textColor=c(this.background),this.mainBkg="#1f2020",this.secondBkg="calculated",this.mainContrastColor="lightgrey",this.darkTextColor=(0,d.A)(c("#323D47"),10),this.lineColor="calculated",this.border1="#ccc",this.border2=(0,s.A)(255,255,255,.25),this.arrowheadColor="calculated",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.labelBackground="#181818",this.textColor="#ccc",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="#F9FFFE",this.edgeLabelBackground="calculated",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="calculated",this.actorLineColor="calculated",this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="calculated",this.activationBkgColor="calculated",this.sequenceNumberColor="black",this.sectionBkgColor=(0,u.A)("#EAE8D9",30),this.altSectionBkgColor="calculated",this.sectionBkgColor2="#EAE8D9",this.excludeBkgColor=(0,u.A)(this.sectionBkgColor,10),this.taskBorderColor=(0,s.A)(255,255,255,70),this.taskBkgColor="calculated",this.taskTextColor="calculated",this.taskTextLightColor="calculated",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor=(0,s.A)(255,255,255,50),this.activeTaskBkgColor="#81B1DB",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="grey",this.critBorderColor="#E83737",this.critBkgColor="#E83737",this.taskTextDarkColor="calculated",this.todayLineColor="#DB5757",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="calculated",this.errorBkgColor="#a44141",this.errorTextColor="#ddd"}updateColors(){this.secondBkg=(0,d.A)(this.mainBkg,16),this.lineColor=this.mainContrastColor,this.arrowheadColor=this.mainContrastColor,this.nodeBkg=this.mainBkg,this.nodeBorder=this.border1,this.clusterBkg=this.secondBkg,this.clusterBorder=this.border2,this.defaultLinkColor=this.lineColor,this.edgeLabelBackground=(0,d.A)(this.labelBackground,25),this.actorBorder=this.border1,this.actorBkg=this.mainBkg,this.actorTextColor=this.mainContrastColor,this.actorLineColor=this.actorBorder,this.signalColor=this.mainContrastColor,this.signalTextColor=this.mainContrastColor,this.labelBoxBkgColor=this.actorBkg,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.mainContrastColor,this.loopTextColor=this.mainContrastColor,this.noteBorderColor=this.secondaryBorderColor,this.noteBkgColor=this.secondBkg,this.noteTextColor=this.secondaryTextColor,this.activationBorderColor=this.border1,this.activationBkgColor=this.secondBkg,this.altSectionBkgColor=this.background,this.taskBkgColor=(0,d.A)(this.mainBkg,23),this.taskTextColor=this.darkTextColor,this.taskTextLightColor=this.mainContrastColor,this.taskTextOutsideColor=this.taskTextLightColor,this.gridColor=this.mainContrastColor,this.doneTaskBkgColor=this.mainContrastColor,this.taskTextDarkColor=this.darkTextColor,this.archEdgeColor=this.lineColor,this.archEdgeArrowColor=this.lineColor,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||"#555",this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.primaryBorderColor,this.specialStateColor="#f4f4f4",this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.fillType0=this.primaryColor,this.fillType1=this.secondaryColor,this.fillType2=o(this.primaryColor,{h:64}),this.fillType3=o(this.secondaryColor,{h:64}),this.fillType4=o(this.primaryColor,{h:-64}),this.fillType5=o(this.secondaryColor,{h:-64}),this.fillType6=o(this.primaryColor,{h:128}),this.fillType7=o(this.secondaryColor,{h:128}),this.cScale1=this.cScale1||"#0b0000",this.cScale2=this.cScale2||"#4d1037",this.cScale3=this.cScale3||"#3f5258",this.cScale4=this.cScale4||"#4f2f1b",this.cScale5=this.cScale5||"#6e0a0a",this.cScale6=this.cScale6||"#3b0048",this.cScale7=this.cScale7||"#995a01",this.cScale8=this.cScale8||"#154706",this.cScale9=this.cScale9||"#161722",this.cScale10=this.cScale10||"#00296f",this.cScale11=this.cScale11||"#01629c",this.cScale12=this.cScale12||"#010029",this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||o(this.primaryColor,{h:30}),this.cScale4=this.cScale4||o(this.primaryColor,{h:60}),this.cScale5=this.cScale5||o(this.primaryColor,{h:90}),this.cScale6=this.cScale6||o(this.primaryColor,{h:120}),this.cScale7=this.cScale7||o(this.primaryColor,{h:150}),this.cScale8=this.cScale8||o(this.primaryColor,{h:210}),this.cScale9=this.cScale9||o(this.primaryColor,{h:270}),this.cScale10=this.cScale10||o(this.primaryColor,{h:300}),this.cScale11=this.cScale11||o(this.primaryColor,{h:330});for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleInv"+t]=this["cScaleInv"+t]||c(this["cScale"+t]);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScalePeer"+t]=this["cScalePeer"+t]||(0,d.A)(this["cScale"+t],10);for(let t=0;t<5;t++)this["surface"+t]=this["surface"+t]||o(this.mainBkg,{h:30,s:-30,l:-(4*t-10)}),this["surfacePeer"+t]=this["surfacePeer"+t]||o(this.mainBkg,{h:30,s:-30,l:-(4*t-7)});this.scaleLabelColor=this.scaleLabelColor||(this.darkMode?"black":this.labelTextColor);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleLabel"+t]=this["cScaleLabel"+t]||this.scaleLabelColor;for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["pie"+t]=this["cScale"+t];this.pieTitleTextSize=this.pieTitleTextSize||"25px",this.pieTitleTextColor=this.pieTitleTextColor||this.taskTextDarkColor,this.pieSectionTextSize=this.pieSectionTextSize||"17px",this.pieSectionTextColor=this.pieSectionTextColor||this.textColor,this.pieLegendTextSize=this.pieLegendTextSize||"17px",this.pieLegendTextColor=this.pieLegendTextColor||this.taskTextDarkColor,this.pieStrokeColor=this.pieStrokeColor||"black",this.pieStrokeWidth=this.pieStrokeWidth||"2px",this.pieOuterStrokeWidth=this.pieOuterStrokeWidth||"2px",this.pieOuterStrokeColor=this.pieOuterStrokeColor||"black",this.pieOpacity=this.pieOpacity||"0.7",this.quadrant1Fill=this.quadrant1Fill||this.primaryColor,this.quadrant2Fill=this.quadrant2Fill||o(this.primaryColor,{r:5,g:5,b:5}),this.quadrant3Fill=this.quadrant3Fill||o(this.primaryColor,{r:10,g:10,b:10}),this.quadrant4Fill=this.quadrant4Fill||o(this.primaryColor,{r:15,g:15,b:15}),this.quadrant1TextFill=this.quadrant1TextFill||this.primaryTextColor,this.quadrant2TextFill=this.quadrant2TextFill||o(this.primaryTextColor,{r:-5,g:-5,b:-5}),this.quadrant3TextFill=this.quadrant3TextFill||o(this.primaryTextColor,{r:-10,g:-10,b:-10}),this.quadrant4TextFill=this.quadrant4TextFill||o(this.primaryTextColor,{r:-15,g:-15,b:-15}),this.quadrantPointFill=this.quadrantPointFill||(0,p.A)(this.quadrant1Fill)?(0,d.A)(this.quadrant1Fill):(0,u.A)(this.quadrant1Fill),this.quadrantPointTextFill=this.quadrantPointTextFill||this.primaryTextColor,this.quadrantXAxisTextFill=this.quadrantXAxisTextFill||this.primaryTextColor,this.quadrantYAxisTextFill=this.quadrantYAxisTextFill||this.primaryTextColor,this.quadrantInternalBorderStrokeFill=this.quadrantInternalBorderStrokeFill||this.primaryBorderColor,this.quadrantExternalBorderStrokeFill=this.quadrantExternalBorderStrokeFill||this.primaryBorderColor,this.quadrantTitleFill=this.quadrantTitleFill||this.primaryTextColor,this.xyChart={backgroundColor:this.xyChart?.backgroundColor||this.background,titleColor:this.xyChart?.titleColor||this.primaryTextColor,xAxisTitleColor:this.xyChart?.xAxisTitleColor||this.primaryTextColor,xAxisLabelColor:this.xyChart?.xAxisLabelColor||this.primaryTextColor,xAxisTickColor:this.xyChart?.xAxisTickColor||this.primaryTextColor,xAxisLineColor:this.xyChart?.xAxisLineColor||this.primaryTextColor,yAxisTitleColor:this.xyChart?.yAxisTitleColor||this.primaryTextColor,yAxisLabelColor:this.xyChart?.yAxisLabelColor||this.primaryTextColor,yAxisTickColor:this.xyChart?.yAxisTickColor||this.primaryTextColor,yAxisLineColor:this.xyChart?.yAxisLineColor||this.primaryTextColor,plotColorPalette:this.xyChart?.plotColorPalette||"#3498db,#2ecc71,#e74c3c,#f1c40f,#bdc3c7,#ffffff,#34495e,#9b59b6,#1abc9c,#e67e22"},this.packet={startByteColor:this.primaryTextColor,endByteColor:this.primaryTextColor,labelColor:this.primaryTextColor,titleColor:this.primaryTextColor,blockStrokeColor:this.primaryTextColor,blockFillColor:this.background},this.classText=this.primaryTextColor,this.requirementBackground=this.requirementBackground||this.primaryColor,this.requirementBorderColor=this.requirementBorderColor||this.primaryBorderColor,this.requirementBorderSize=this.requirementBorderSize||"1",this.requirementTextColor=this.requirementTextColor||this.primaryTextColor,this.relationColor=this.relationColor||this.lineColor,this.relationLabelBackground=this.relationLabelBackground||(this.darkMode?(0,u.A)(this.secondaryColor,30):this.secondaryColor),this.relationLabelColor=this.relationLabelColor||this.actorTextColor,this.git0=(0,d.A)(this.secondaryColor,20),this.git1=(0,d.A)(this.pie2||this.secondaryColor,20),this.git2=(0,d.A)(this.pie3||this.tertiaryColor,20),this.git3=(0,d.A)(this.pie4||o(this.primaryColor,{h:-30}),20),this.git4=(0,d.A)(this.pie5||o(this.primaryColor,{h:-60}),20),this.git5=(0,d.A)(this.pie6||o(this.primaryColor,{h:-90}),10),this.git6=(0,d.A)(this.pie7||o(this.primaryColor,{h:60}),10),this.git7=(0,d.A)(this.pie8||o(this.primaryColor,{h:120}),20),this.gitInv0=this.gitInv0||c(this.git0),this.gitInv1=this.gitInv1||c(this.git1),this.gitInv2=this.gitInv2||c(this.git2),this.gitInv3=this.gitInv3||c(this.git3),this.gitInv4=this.gitInv4||c(this.git4),this.gitInv5=this.gitInv5||c(this.git5),this.gitInv6=this.gitInv6||c(this.git6),this.gitInv7=this.gitInv7||c(this.git7),this.gitBranchLabel0=this.gitBranchLabel0||c(this.labelTextColor),this.gitBranchLabel1=this.gitBranchLabel1||this.labelTextColor,this.gitBranchLabel2=this.gitBranchLabel2||this.labelTextColor,this.gitBranchLabel3=this.gitBranchLabel3||c(this.labelTextColor),this.gitBranchLabel4=this.gitBranchLabel4||this.labelTextColor,this.gitBranchLabel5=this.gitBranchLabel5||this.labelTextColor,this.gitBranchLabel6=this.gitBranchLabel6||this.labelTextColor,this.gitBranchLabel7=this.gitBranchLabel7||this.labelTextColor,this.tagLabelColor=this.tagLabelColor||this.primaryTextColor,this.tagLabelBackground=this.tagLabelBackground||this.primaryColor,this.tagLabelBorder=this.tagBorder||this.primaryBorderColor,this.tagLabelFontSize=this.tagLabelFontSize||"10px",this.commitLabelColor=this.commitLabelColor||this.secondaryTextColor,this.commitLabelBackground=this.commitLabelBackground||this.secondaryColor,this.commitLabelFontSize=this.commitLabelFontSize||"10px",this.attributeBackgroundColorOdd=this.attributeBackgroundColorOdd||(0,d.A)(this.background,12),this.attributeBackgroundColorEven=this.attributeBackgroundColorEven||(0,d.A)(this.background,2),this.nodeBorder=this.nodeBorder||"#999"}calculate(t){if("object"!=typeof t)return void this.updateColors();const e=Object.keys(t);e.forEach((e=>{this[e]=t[e]})),this.updateColors(),e.forEach((e=>{this[e]=t[e]}))}},R=m((t=>{const e=new O;return e.calculate(t),e}),"getThemeVariables"),P=class{static{m(this,"Theme")}constructor(){this.background="#f4f4f4",this.primaryColor="#ECECFF",this.secondaryColor=o(this.primaryColor,{h:120}),this.secondaryColor="#ffffde",this.tertiaryColor=o(this.primaryColor,{h:-160}),this.primaryBorderColor=D(this.primaryColor,this.darkMode),this.secondaryBorderColor=D(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=D(this.tertiaryColor,this.darkMode),this.primaryTextColor=c(this.primaryColor),this.secondaryTextColor=c(this.secondaryColor),this.tertiaryTextColor=c(this.tertiaryColor),this.lineColor=c(this.background),this.textColor=c(this.background),this.background="white",this.mainBkg="#ECECFF",this.secondBkg="#ffffde",this.lineColor="#333333",this.border1="#9370DB",this.border2="#aaaa33",this.arrowheadColor="#333333",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.labelBackground="rgba(232,232,232, 0.8)",this.textColor="#333",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="calculated",this.edgeLabelBackground="calculated",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="black",this.actorLineColor="calculated",this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="calculated",this.altSectionBkgColor="calculated",this.sectionBkgColor2="calculated",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="calculated",this.taskTextLightColor="calculated",this.taskTextColor=this.taskTextLightColor,this.taskTextDarkColor="calculated",this.taskTextOutsideColor=this.taskTextDarkColor,this.taskTextClickableColor="calculated",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="calculated",this.critBorderColor="calculated",this.critBkgColor="calculated",this.todayLineColor="calculated",this.sectionBkgColor=(0,s.A)(102,102,255,.49),this.altSectionBkgColor="white",this.sectionBkgColor2="#fff400",this.taskBorderColor="#534fbc",this.taskBkgColor="#8a90dd",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="black",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="#534fbc",this.activeTaskBkgColor="#bfc7ff",this.gridColor="lightgrey",this.doneTaskBkgColor="lightgrey",this.doneTaskBorderColor="grey",this.critBorderColor="#ff8888",this.critBkgColor="red",this.todayLineColor="red",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222",this.updateColors()}updateColors(){this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||o(this.primaryColor,{h:30}),this.cScale4=this.cScale4||o(this.primaryColor,{h:60}),this.cScale5=this.cScale5||o(this.primaryColor,{h:90}),this.cScale6=this.cScale6||o(this.primaryColor,{h:120}),this.cScale7=this.cScale7||o(this.primaryColor,{h:150}),this.cScale8=this.cScale8||o(this.primaryColor,{h:210}),this.cScale9=this.cScale9||o(this.primaryColor,{h:270}),this.cScale10=this.cScale10||o(this.primaryColor,{h:300}),this.cScale11=this.cScale11||o(this.primaryColor,{h:330}),this.cScalePeer1=this.cScalePeer1||(0,u.A)(this.secondaryColor,45),this.cScalePeer2=this.cScalePeer2||(0,u.A)(this.tertiaryColor,40);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScale"+t]=(0,u.A)(this["cScale"+t],10),this["cScalePeer"+t]=this["cScalePeer"+t]||(0,u.A)(this["cScale"+t],25);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleInv"+t]=this["cScaleInv"+t]||o(this["cScale"+t],{h:180});for(let t=0;t<5;t++)this["surface"+t]=this["surface"+t]||o(this.mainBkg,{h:30,l:-(5+5*t)}),this["surfacePeer"+t]=this["surfacePeer"+t]||o(this.mainBkg,{h:30,l:-(7+5*t)});if(this.scaleLabelColor="calculated"!==this.scaleLabelColor&&this.scaleLabelColor?this.scaleLabelColor:this.labelTextColor,"calculated"!==this.labelTextColor){this.cScaleLabel0=this.cScaleLabel0||c(this.labelTextColor),this.cScaleLabel3=this.cScaleLabel3||c(this.labelTextColor);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleLabel"+t]=this["cScaleLabel"+t]||this.labelTextColor}this.nodeBkg=this.mainBkg,this.nodeBorder=this.border1,this.clusterBkg=this.secondBkg,this.clusterBorder=this.border2,this.defaultLinkColor=this.lineColor,this.titleColor=this.textColor,this.edgeLabelBackground=this.labelBackground,this.actorBorder=(0,d.A)(this.border1,23),this.actorBkg=this.mainBkg,this.labelBoxBkgColor=this.actorBkg,this.signalColor=this.textColor,this.signalTextColor=this.textColor,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.actorTextColor,this.loopTextColor=this.actorTextColor,this.noteBorderColor=this.border2,this.noteTextColor=this.actorTextColor,this.actorLineColor=this.actorBorder,this.taskTextColor=this.taskTextLightColor,this.taskTextOutsideColor=this.taskTextDarkColor,this.archEdgeColor=this.lineColor,this.archEdgeArrowColor=this.lineColor,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||"#f0f0f0",this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.nodeBorder,this.specialStateColor=this.lineColor,this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.transitionColor=this.transitionColor||this.lineColor,this.classText=this.primaryTextColor,this.fillType0=this.primaryColor,this.fillType1=this.secondaryColor,this.fillType2=o(this.primaryColor,{h:64}),this.fillType3=o(this.secondaryColor,{h:64}),this.fillType4=o(this.primaryColor,{h:-64}),this.fillType5=o(this.secondaryColor,{h:-64}),this.fillType6=o(this.primaryColor,{h:128}),this.fillType7=o(this.secondaryColor,{h:128}),this.pie1=this.pie1||this.primaryColor,this.pie2=this.pie2||this.secondaryColor,this.pie3=this.pie3||o(this.tertiaryColor,{l:-40}),this.pie4=this.pie4||o(this.primaryColor,{l:-10}),this.pie5=this.pie5||o(this.secondaryColor,{l:-30}),this.pie6=this.pie6||o(this.tertiaryColor,{l:-20}),this.pie7=this.pie7||o(this.primaryColor,{h:60,l:-20}),this.pie8=this.pie8||o(this.primaryColor,{h:-60,l:-40}),this.pie9=this.pie9||o(this.primaryColor,{h:120,l:-40}),this.pie10=this.pie10||o(this.primaryColor,{h:60,l:-40}),this.pie11=this.pie11||o(this.primaryColor,{h:-90,l:-40}),this.pie12=this.pie12||o(this.primaryColor,{h:120,l:-30}),this.pieTitleTextSize=this.pieTitleTextSize||"25px",this.pieTitleTextColor=this.pieTitleTextColor||this.taskTextDarkColor,this.pieSectionTextSize=this.pieSectionTextSize||"17px",this.pieSectionTextColor=this.pieSectionTextColor||this.textColor,this.pieLegendTextSize=this.pieLegendTextSize||"17px",this.pieLegendTextColor=this.pieLegendTextColor||this.taskTextDarkColor,this.pieStrokeColor=this.pieStrokeColor||"black",this.pieStrokeWidth=this.pieStrokeWidth||"2px",this.pieOuterStrokeWidth=this.pieOuterStrokeWidth||"2px",this.pieOuterStrokeColor=this.pieOuterStrokeColor||"black",this.pieOpacity=this.pieOpacity||"0.7",this.quadrant1Fill=this.quadrant1Fill||this.primaryColor,this.quadrant2Fill=this.quadrant2Fill||o(this.primaryColor,{r:5,g:5,b:5}),this.quadrant3Fill=this.quadrant3Fill||o(this.primaryColor,{r:10,g:10,b:10}),this.quadrant4Fill=this.quadrant4Fill||o(this.primaryColor,{r:15,g:15,b:15}),this.quadrant1TextFill=this.quadrant1TextFill||this.primaryTextColor,this.quadrant2TextFill=this.quadrant2TextFill||o(this.primaryTextColor,{r:-5,g:-5,b:-5}),this.quadrant3TextFill=this.quadrant3TextFill||o(this.primaryTextColor,{r:-10,g:-10,b:-10}),this.quadrant4TextFill=this.quadrant4TextFill||o(this.primaryTextColor,{r:-15,g:-15,b:-15}),this.quadrantPointFill=this.quadrantPointFill||(0,p.A)(this.quadrant1Fill)?(0,d.A)(this.quadrant1Fill):(0,u.A)(this.quadrant1Fill),this.quadrantPointTextFill=this.quadrantPointTextFill||this.primaryTextColor,this.quadrantXAxisTextFill=this.quadrantXAxisTextFill||this.primaryTextColor,this.quadrantYAxisTextFill=this.quadrantYAxisTextFill||this.primaryTextColor,this.quadrantInternalBorderStrokeFill=this.quadrantInternalBorderStrokeFill||this.primaryBorderColor,this.quadrantExternalBorderStrokeFill=this.quadrantExternalBorderStrokeFill||this.primaryBorderColor,this.quadrantTitleFill=this.quadrantTitleFill||this.primaryTextColor,this.xyChart={backgroundColor:this.xyChart?.backgroundColor||this.background,titleColor:this.xyChart?.titleColor||this.primaryTextColor,xAxisTitleColor:this.xyChart?.xAxisTitleColor||this.primaryTextColor,xAxisLabelColor:this.xyChart?.xAxisLabelColor||this.primaryTextColor,xAxisTickColor:this.xyChart?.xAxisTickColor||this.primaryTextColor,xAxisLineColor:this.xyChart?.xAxisLineColor||this.primaryTextColor,yAxisTitleColor:this.xyChart?.yAxisTitleColor||this.primaryTextColor,yAxisLabelColor:this.xyChart?.yAxisLabelColor||this.primaryTextColor,yAxisTickColor:this.xyChart?.yAxisTickColor||this.primaryTextColor,yAxisLineColor:this.xyChart?.yAxisLineColor||this.primaryTextColor,plotColorPalette:this.xyChart?.plotColorPalette||"#ECECFF,#8493A6,#FFC3A0,#DCDDE1,#B8E994,#D1A36F,#C3CDE6,#FFB6C1,#496078,#F8F3E3"},this.requirementBackground=this.requirementBackground||this.primaryColor,this.requirementBorderColor=this.requirementBorderColor||this.primaryBorderColor,this.requirementBorderSize=this.requirementBorderSize||"1",this.requirementTextColor=this.requirementTextColor||this.primaryTextColor,this.relationColor=this.relationColor||this.lineColor,this.relationLabelBackground=this.relationLabelBackground||this.labelBackground,this.relationLabelColor=this.relationLabelColor||this.actorTextColor,this.git0=this.git0||this.primaryColor,this.git1=this.git1||this.secondaryColor,this.git2=this.git2||this.tertiaryColor,this.git3=this.git3||o(this.primaryColor,{h:-30}),this.git4=this.git4||o(this.primaryColor,{h:-60}),this.git5=this.git5||o(this.primaryColor,{h:-90}),this.git6=this.git6||o(this.primaryColor,{h:60}),this.git7=this.git7||o(this.primaryColor,{h:120}),this.darkMode?(this.git0=(0,d.A)(this.git0,25),this.git1=(0,d.A)(this.git1,25),this.git2=(0,d.A)(this.git2,25),this.git3=(0,d.A)(this.git3,25),this.git4=(0,d.A)(this.git4,25),this.git5=(0,d.A)(this.git5,25),this.git6=(0,d.A)(this.git6,25),this.git7=(0,d.A)(this.git7,25)):(this.git0=(0,u.A)(this.git0,25),this.git1=(0,u.A)(this.git1,25),this.git2=(0,u.A)(this.git2,25),this.git3=(0,u.A)(this.git3,25),this.git4=(0,u.A)(this.git4,25),this.git5=(0,u.A)(this.git5,25),this.git6=(0,u.A)(this.git6,25),this.git7=(0,u.A)(this.git7,25)),this.gitInv0=this.gitInv0||(0,u.A)(c(this.git0),25),this.gitInv1=this.gitInv1||c(this.git1),this.gitInv2=this.gitInv2||c(this.git2),this.gitInv3=this.gitInv3||c(this.git3),this.gitInv4=this.gitInv4||c(this.git4),this.gitInv5=this.gitInv5||c(this.git5),this.gitInv6=this.gitInv6||c(this.git6),this.gitInv7=this.gitInv7||c(this.git7),this.gitBranchLabel0=this.gitBranchLabel0||c(this.labelTextColor),this.gitBranchLabel1=this.gitBranchLabel1||this.labelTextColor,this.gitBranchLabel2=this.gitBranchLabel2||this.labelTextColor,this.gitBranchLabel3=this.gitBranchLabel3||c(this.labelTextColor),this.gitBranchLabel4=this.gitBranchLabel4||this.labelTextColor,this.gitBranchLabel5=this.gitBranchLabel5||this.labelTextColor,this.gitBranchLabel6=this.gitBranchLabel6||this.labelTextColor,this.gitBranchLabel7=this.gitBranchLabel7||this.labelTextColor,this.tagLabelColor=this.tagLabelColor||this.primaryTextColor,this.tagLabelBackground=this.tagLabelBackground||this.primaryColor,this.tagLabelBorder=this.tagBorder||this.primaryBorderColor,this.tagLabelFontSize=this.tagLabelFontSize||"10px",this.commitLabelColor=this.commitLabelColor||this.secondaryTextColor,this.commitLabelBackground=this.commitLabelBackground||this.secondaryColor,this.commitLabelFontSize=this.commitLabelFontSize||"10px",this.attributeBackgroundColorOdd=this.attributeBackgroundColorOdd||E,this.attributeBackgroundColorEven=this.attributeBackgroundColorEven||N}calculate(t){if("object"!=typeof t)return void this.updateColors();const e=Object.keys(t);e.forEach((e=>{this[e]=t[e]})),this.updateColors(),e.forEach((e=>{this[e]=t[e]}))}},z=m((t=>{const e=new P;return e.calculate(t),e}),"getThemeVariables"),K=class{static{m(this,"Theme")}constructor(){this.background="#f4f4f4",this.primaryColor="#cde498",this.secondaryColor="#cdffb2",this.background="white",this.mainBkg="#cde498",this.secondBkg="#cdffb2",this.lineColor="green",this.border1="#13540c",this.border2="#6eaa49",this.arrowheadColor="green",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.tertiaryColor=(0,d.A)("#cde498",10),this.primaryBorderColor=D(this.primaryColor,this.darkMode),this.secondaryBorderColor=D(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=D(this.tertiaryColor,this.darkMode),this.primaryTextColor=c(this.primaryColor),this.secondaryTextColor=c(this.secondaryColor),this.tertiaryTextColor=c(this.primaryColor),this.lineColor=c(this.background),this.textColor=c(this.background),this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="#333",this.edgeLabelBackground="#e8e8e8",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="black",this.actorLineColor="calculated",this.signalColor="#333",this.signalTextColor="#333",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="#326932",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="#fff5ad",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="#6eaa49",this.altSectionBkgColor="white",this.sectionBkgColor2="#6eaa49",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="#487e3a",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="black",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="lightgrey",this.doneTaskBkgColor="lightgrey",this.doneTaskBorderColor="grey",this.critBorderColor="#ff8888",this.critBkgColor="red",this.todayLineColor="red",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222"}updateColors(){this.actorBorder=(0,u.A)(this.mainBkg,20),this.actorBkg=this.mainBkg,this.labelBoxBkgColor=this.actorBkg,this.labelTextColor=this.actorTextColor,this.loopTextColor=this.actorTextColor,this.noteBorderColor=this.border2,this.noteTextColor=this.actorTextColor,this.actorLineColor=this.actorBorder,this.cScale0=this.cScale0||this.primaryColor,this.cScale1=this.cScale1||this.secondaryColor,this.cScale2=this.cScale2||this.tertiaryColor,this.cScale3=this.cScale3||o(this.primaryColor,{h:30}),this.cScale4=this.cScale4||o(this.primaryColor,{h:60}),this.cScale5=this.cScale5||o(this.primaryColor,{h:90}),this.cScale6=this.cScale6||o(this.primaryColor,{h:120}),this.cScale7=this.cScale7||o(this.primaryColor,{h:150}),this.cScale8=this.cScale8||o(this.primaryColor,{h:210}),this.cScale9=this.cScale9||o(this.primaryColor,{h:270}),this.cScale10=this.cScale10||o(this.primaryColor,{h:300}),this.cScale11=this.cScale11||o(this.primaryColor,{h:330}),this.cScalePeer1=this.cScalePeer1||(0,u.A)(this.secondaryColor,45),this.cScalePeer2=this.cScalePeer2||(0,u.A)(this.tertiaryColor,40);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScale"+t]=(0,u.A)(this["cScale"+t],10),this["cScalePeer"+t]=this["cScalePeer"+t]||(0,u.A)(this["cScale"+t],25);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleInv"+t]=this["cScaleInv"+t]||o(this["cScale"+t],{h:180});this.scaleLabelColor="calculated"!==this.scaleLabelColor&&this.scaleLabelColor?this.scaleLabelColor:this.labelTextColor;for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleLabel"+t]=this["cScaleLabel"+t]||this.scaleLabelColor;for(let t=0;t<5;t++)this["surface"+t]=this["surface"+t]||o(this.mainBkg,{h:30,s:-30,l:-(5+5*t)}),this["surfacePeer"+t]=this["surfacePeer"+t]||o(this.mainBkg,{h:30,s:-30,l:-(8+5*t)});this.nodeBkg=this.mainBkg,this.nodeBorder=this.border1,this.clusterBkg=this.secondBkg,this.clusterBorder=this.border2,this.defaultLinkColor=this.lineColor,this.taskBorderColor=this.border1,this.taskTextColor=this.taskTextLightColor,this.taskTextOutsideColor=this.taskTextDarkColor,this.activeTaskBorderColor=this.taskBorderColor,this.activeTaskBkgColor=this.mainBkg,this.archEdgeColor=this.lineColor,this.archEdgeArrowColor=this.lineColor,this.transitionColor=this.transitionColor||this.lineColor,this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||"#f0f0f0",this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.compositeBorder=this.compositeBorder||this.nodeBorder,this.innerEndBackground=this.primaryBorderColor,this.specialStateColor=this.lineColor,this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.transitionColor=this.transitionColor||this.lineColor,this.classText=this.primaryTextColor,this.fillType0=this.primaryColor,this.fillType1=this.secondaryColor,this.fillType2=o(this.primaryColor,{h:64}),this.fillType3=o(this.secondaryColor,{h:64}),this.fillType4=o(this.primaryColor,{h:-64}),this.fillType5=o(this.secondaryColor,{h:-64}),this.fillType6=o(this.primaryColor,{h:128}),this.fillType7=o(this.secondaryColor,{h:128}),this.pie1=this.pie1||this.primaryColor,this.pie2=this.pie2||this.secondaryColor,this.pie3=this.pie3||this.tertiaryColor,this.pie4=this.pie4||o(this.primaryColor,{l:-30}),this.pie5=this.pie5||o(this.secondaryColor,{l:-30}),this.pie6=this.pie6||o(this.tertiaryColor,{h:40,l:-40}),this.pie7=this.pie7||o(this.primaryColor,{h:60,l:-10}),this.pie8=this.pie8||o(this.primaryColor,{h:-60,l:-10}),this.pie9=this.pie9||o(this.primaryColor,{h:120,l:0}),this.pie10=this.pie10||o(this.primaryColor,{h:60,l:-50}),this.pie11=this.pie11||o(this.primaryColor,{h:-60,l:-50}),this.pie12=this.pie12||o(this.primaryColor,{h:120,l:-50}),this.pieTitleTextSize=this.pieTitleTextSize||"25px",this.pieTitleTextColor=this.pieTitleTextColor||this.taskTextDarkColor,this.pieSectionTextSize=this.pieSectionTextSize||"17px",this.pieSectionTextColor=this.pieSectionTextColor||this.textColor,this.pieLegendTextSize=this.pieLegendTextSize||"17px",this.pieLegendTextColor=this.pieLegendTextColor||this.taskTextDarkColor,this.pieStrokeColor=this.pieStrokeColor||"black",this.pieStrokeWidth=this.pieStrokeWidth||"2px",this.pieOuterStrokeWidth=this.pieOuterStrokeWidth||"2px",this.pieOuterStrokeColor=this.pieOuterStrokeColor||"black",this.pieOpacity=this.pieOpacity||"0.7",this.quadrant1Fill=this.quadrant1Fill||this.primaryColor,this.quadrant2Fill=this.quadrant2Fill||o(this.primaryColor,{r:5,g:5,b:5}),this.quadrant3Fill=this.quadrant3Fill||o(this.primaryColor,{r:10,g:10,b:10}),this.quadrant4Fill=this.quadrant4Fill||o(this.primaryColor,{r:15,g:15,b:15}),this.quadrant1TextFill=this.quadrant1TextFill||this.primaryTextColor,this.quadrant2TextFill=this.quadrant2TextFill||o(this.primaryTextColor,{r:-5,g:-5,b:-5}),this.quadrant3TextFill=this.quadrant3TextFill||o(this.primaryTextColor,{r:-10,g:-10,b:-10}),this.quadrant4TextFill=this.quadrant4TextFill||o(this.primaryTextColor,{r:-15,g:-15,b:-15}),this.quadrantPointFill=this.quadrantPointFill||(0,p.A)(this.quadrant1Fill)?(0,d.A)(this.quadrant1Fill):(0,u.A)(this.quadrant1Fill),this.quadrantPointTextFill=this.quadrantPointTextFill||this.primaryTextColor,this.quadrantXAxisTextFill=this.quadrantXAxisTextFill||this.primaryTextColor,this.quadrantYAxisTextFill=this.quadrantYAxisTextFill||this.primaryTextColor,this.quadrantInternalBorderStrokeFill=this.quadrantInternalBorderStrokeFill||this.primaryBorderColor,this.quadrantExternalBorderStrokeFill=this.quadrantExternalBorderStrokeFill||this.primaryBorderColor,this.quadrantTitleFill=this.quadrantTitleFill||this.primaryTextColor,this.packet={startByteColor:this.primaryTextColor,endByteColor:this.primaryTextColor,labelColor:this.primaryTextColor,titleColor:this.primaryTextColor,blockStrokeColor:this.primaryTextColor,blockFillColor:this.mainBkg},this.xyChart={backgroundColor:this.xyChart?.backgroundColor||this.background,titleColor:this.xyChart?.titleColor||this.primaryTextColor,xAxisTitleColor:this.xyChart?.xAxisTitleColor||this.primaryTextColor,xAxisLabelColor:this.xyChart?.xAxisLabelColor||this.primaryTextColor,xAxisTickColor:this.xyChart?.xAxisTickColor||this.primaryTextColor,xAxisLineColor:this.xyChart?.xAxisLineColor||this.primaryTextColor,yAxisTitleColor:this.xyChart?.yAxisTitleColor||this.primaryTextColor,yAxisLabelColor:this.xyChart?.yAxisLabelColor||this.primaryTextColor,yAxisTickColor:this.xyChart?.yAxisTickColor||this.primaryTextColor,yAxisLineColor:this.xyChart?.yAxisLineColor||this.primaryTextColor,plotColorPalette:this.xyChart?.plotColorPalette||"#CDE498,#FF6B6B,#A0D2DB,#D7BDE2,#F0F0F0,#FFC3A0,#7FD8BE,#FF9A8B,#FAF3E0,#FFF176"},this.requirementBackground=this.requirementBackground||this.primaryColor,this.requirementBorderColor=this.requirementBorderColor||this.primaryBorderColor,this.requirementBorderSize=this.requirementBorderSize||"1",this.requirementTextColor=this.requirementTextColor||this.primaryTextColor,this.relationColor=this.relationColor||this.lineColor,this.relationLabelBackground=this.relationLabelBackground||this.edgeLabelBackground,this.relationLabelColor=this.relationLabelColor||this.actorTextColor,this.git0=this.git0||this.primaryColor,this.git1=this.git1||this.secondaryColor,this.git2=this.git2||this.tertiaryColor,this.git3=this.git3||o(this.primaryColor,{h:-30}),this.git4=this.git4||o(this.primaryColor,{h:-60}),this.git5=this.git5||o(this.primaryColor,{h:-90}),this.git6=this.git6||o(this.primaryColor,{h:60}),this.git7=this.git7||o(this.primaryColor,{h:120}),this.darkMode?(this.git0=(0,d.A)(this.git0,25),this.git1=(0,d.A)(this.git1,25),this.git2=(0,d.A)(this.git2,25),this.git3=(0,d.A)(this.git3,25),this.git4=(0,d.A)(this.git4,25),this.git5=(0,d.A)(this.git5,25),this.git6=(0,d.A)(this.git6,25),this.git7=(0,d.A)(this.git7,25)):(this.git0=(0,u.A)(this.git0,25),this.git1=(0,u.A)(this.git1,25),this.git2=(0,u.A)(this.git2,25),this.git3=(0,u.A)(this.git3,25),this.git4=(0,u.A)(this.git4,25),this.git5=(0,u.A)(this.git5,25),this.git6=(0,u.A)(this.git6,25),this.git7=(0,u.A)(this.git7,25)),this.gitInv0=this.gitInv0||c(this.git0),this.gitInv1=this.gitInv1||c(this.git1),this.gitInv2=this.gitInv2||c(this.git2),this.gitInv3=this.gitInv3||c(this.git3),this.gitInv4=this.gitInv4||c(this.git4),this.gitInv5=this.gitInv5||c(this.git5),this.gitInv6=this.gitInv6||c(this.git6),this.gitInv7=this.gitInv7||c(this.git7),this.gitBranchLabel0=this.gitBranchLabel0||c(this.labelTextColor),this.gitBranchLabel1=this.gitBranchLabel1||this.labelTextColor,this.gitBranchLabel2=this.gitBranchLabel2||this.labelTextColor,this.gitBranchLabel3=this.gitBranchLabel3||c(this.labelTextColor),this.gitBranchLabel4=this.gitBranchLabel4||this.labelTextColor,this.gitBranchLabel5=this.gitBranchLabel5||this.labelTextColor,this.gitBranchLabel6=this.gitBranchLabel6||this.labelTextColor,this.gitBranchLabel7=this.gitBranchLabel7||this.labelTextColor,this.tagLabelColor=this.tagLabelColor||this.primaryTextColor,this.tagLabelBackground=this.tagLabelBackground||this.primaryColor,this.tagLabelBorder=this.tagBorder||this.primaryBorderColor,this.tagLabelFontSize=this.tagLabelFontSize||"10px",this.commitLabelColor=this.commitLabelColor||this.secondaryTextColor,this.commitLabelBackground=this.commitLabelBackground||this.secondaryColor,this.commitLabelFontSize=this.commitLabelFontSize||"10px",this.attributeBackgroundColorOdd=this.attributeBackgroundColorOdd||E,this.attributeBackgroundColorEven=this.attributeBackgroundColorEven||N}calculate(t){if("object"!=typeof t)return void this.updateColors();const e=Object.keys(t);e.forEach((e=>{this[e]=t[e]})),this.updateColors(),e.forEach((e=>{this[e]=t[e]}))}},q=m((t=>{const e=new K;return e.calculate(t),e}),"getThemeVariables"),W=class{static{m(this,"Theme")}constructor(){this.primaryColor="#eee",this.contrast="#707070",this.secondaryColor=(0,d.A)(this.contrast,55),this.background="#ffffff",this.tertiaryColor=o(this.primaryColor,{h:-160}),this.primaryBorderColor=D(this.primaryColor,this.darkMode),this.secondaryBorderColor=D(this.secondaryColor,this.darkMode),this.tertiaryBorderColor=D(this.tertiaryColor,this.darkMode),this.primaryTextColor=c(this.primaryColor),this.secondaryTextColor=c(this.secondaryColor),this.tertiaryTextColor=c(this.tertiaryColor),this.lineColor=c(this.background),this.textColor=c(this.background),this.mainBkg="#eee",this.secondBkg="calculated",this.lineColor="#666",this.border1="#999",this.border2="calculated",this.note="#ffa",this.text="#333",this.critical="#d42",this.done="#bbb",this.arrowheadColor="#333333",this.fontFamily='"trebuchet ms", verdana, arial, sans-serif',this.fontSize="16px",this.THEME_COLOR_LIMIT=12,this.nodeBkg="calculated",this.nodeBorder="calculated",this.clusterBkg="calculated",this.clusterBorder="calculated",this.defaultLinkColor="calculated",this.titleColor="calculated",this.edgeLabelBackground="white",this.actorBorder="calculated",this.actorBkg="calculated",this.actorTextColor="calculated",this.actorLineColor=this.actorBorder,this.signalColor="calculated",this.signalTextColor="calculated",this.labelBoxBkgColor="calculated",this.labelBoxBorderColor="calculated",this.labelTextColor="calculated",this.loopTextColor="calculated",this.noteBorderColor="calculated",this.noteBkgColor="calculated",this.noteTextColor="calculated",this.activationBorderColor="#666",this.activationBkgColor="#f4f4f4",this.sequenceNumberColor="white",this.sectionBkgColor="calculated",this.altSectionBkgColor="white",this.sectionBkgColor2="calculated",this.excludeBkgColor="#eeeeee",this.taskBorderColor="calculated",this.taskBkgColor="calculated",this.taskTextLightColor="white",this.taskTextColor="calculated",this.taskTextDarkColor="calculated",this.taskTextOutsideColor="calculated",this.taskTextClickableColor="#003163",this.activeTaskBorderColor="calculated",this.activeTaskBkgColor="calculated",this.gridColor="calculated",this.doneTaskBkgColor="calculated",this.doneTaskBorderColor="calculated",this.critBkgColor="calculated",this.critBorderColor="calculated",this.todayLineColor="calculated",this.personBorder=this.primaryBorderColor,this.personBkg=this.mainBkg,this.archEdgeColor="calculated",this.archEdgeArrowColor="calculated",this.archEdgeWidth="3",this.archGroupBorderColor=this.primaryBorderColor,this.archGroupBorderWidth="2px",this.labelColor="black",this.errorBkgColor="#552222",this.errorTextColor="#552222"}updateColors(){this.secondBkg=(0,d.A)(this.contrast,55),this.border2=this.contrast,this.actorBorder=(0,d.A)(this.border1,23),this.actorBkg=this.mainBkg,this.actorTextColor=this.text,this.actorLineColor=this.actorBorder,this.signalColor=this.text,this.signalTextColor=this.text,this.labelBoxBkgColor=this.actorBkg,this.labelBoxBorderColor=this.actorBorder,this.labelTextColor=this.text,this.loopTextColor=this.text,this.noteBorderColor="#999",this.noteBkgColor="#666",this.noteTextColor="#fff",this.cScale0=this.cScale0||"#555",this.cScale1=this.cScale1||"#F4F4F4",this.cScale2=this.cScale2||"#555",this.cScale3=this.cScale3||"#BBB",this.cScale4=this.cScale4||"#777",this.cScale5=this.cScale5||"#999",this.cScale6=this.cScale6||"#DDD",this.cScale7=this.cScale7||"#FFF",this.cScale8=this.cScale8||"#DDD",this.cScale9=this.cScale9||"#BBB",this.cScale10=this.cScale10||"#999",this.cScale11=this.cScale11||"#777";for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleInv"+t]=this["cScaleInv"+t]||c(this["cScale"+t]);for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this.darkMode?this["cScalePeer"+t]=this["cScalePeer"+t]||(0,d.A)(this["cScale"+t],10):this["cScalePeer"+t]=this["cScalePeer"+t]||(0,u.A)(this["cScale"+t],10);this.scaleLabelColor=this.scaleLabelColor||(this.darkMode?"black":this.labelTextColor),this.cScaleLabel0=this.cScaleLabel0||this.cScale1,this.cScaleLabel2=this.cScaleLabel2||this.cScale1;for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["cScaleLabel"+t]=this["cScaleLabel"+t]||this.scaleLabelColor;for(let t=0;t<5;t++)this["surface"+t]=this["surface"+t]||o(this.mainBkg,{l:-(5+5*t)}),this["surfacePeer"+t]=this["surfacePeer"+t]||o(this.mainBkg,{l:-(8+5*t)});this.nodeBkg=this.mainBkg,this.nodeBorder=this.border1,this.clusterBkg=this.secondBkg,this.clusterBorder=this.border2,this.defaultLinkColor=this.lineColor,this.titleColor=this.text,this.sectionBkgColor=(0,d.A)(this.contrast,30),this.sectionBkgColor2=(0,d.A)(this.contrast,30),this.taskBorderColor=(0,u.A)(this.contrast,10),this.taskBkgColor=this.contrast,this.taskTextColor=this.taskTextLightColor,this.taskTextDarkColor=this.text,this.taskTextOutsideColor=this.taskTextDarkColor,this.activeTaskBorderColor=this.taskBorderColor,this.activeTaskBkgColor=this.mainBkg,this.gridColor=(0,d.A)(this.border1,30),this.doneTaskBkgColor=this.done,this.doneTaskBorderColor=this.lineColor,this.critBkgColor=this.critical,this.critBorderColor=(0,u.A)(this.critBkgColor,10),this.todayLineColor=this.critBkgColor,this.archEdgeColor=this.lineColor,this.archEdgeArrowColor=this.lineColor,this.transitionColor=this.transitionColor||"#000",this.transitionLabelColor=this.transitionLabelColor||this.textColor,this.stateLabelColor=this.stateLabelColor||this.stateBkg||this.primaryTextColor,this.stateBkg=this.stateBkg||this.mainBkg,this.labelBackgroundColor=this.labelBackgroundColor||this.stateBkg,this.compositeBackground=this.compositeBackground||this.background||this.tertiaryColor,this.altBackground=this.altBackground||"#f4f4f4",this.compositeTitleBackground=this.compositeTitleBackground||this.mainBkg,this.stateBorder=this.stateBorder||"#000",this.innerEndBackground=this.primaryBorderColor,this.specialStateColor="#222",this.errorBkgColor=this.errorBkgColor||this.tertiaryColor,this.errorTextColor=this.errorTextColor||this.tertiaryTextColor,this.classText=this.primaryTextColor,this.fillType0=this.primaryColor,this.fillType1=this.secondaryColor,this.fillType2=o(this.primaryColor,{h:64}),this.fillType3=o(this.secondaryColor,{h:64}),this.fillType4=o(this.primaryColor,{h:-64}),this.fillType5=o(this.secondaryColor,{h:-64}),this.fillType6=o(this.primaryColor,{h:128}),this.fillType7=o(this.secondaryColor,{h:128});for(let t=0;t<this.THEME_COLOR_LIMIT;t++)this["pie"+t]=this["cScale"+t];this.pie12=this.pie0,this.pieTitleTextSize=this.pieTitleTextSize||"25px",this.pieTitleTextColor=this.pieTitleTextColor||this.taskTextDarkColor,this.pieSectionTextSize=this.pieSectionTextSize||"17px",this.pieSectionTextColor=this.pieSectionTextColor||this.textColor,this.pieLegendTextSize=this.pieLegendTextSize||"17px",this.pieLegendTextColor=this.pieLegendTextColor||this.taskTextDarkColor,this.pieStrokeColor=this.pieStrokeColor||"black",this.pieStrokeWidth=this.pieStrokeWidth||"2px",this.pieOuterStrokeWidth=this.pieOuterStrokeWidth||"2px",this.pieOuterStrokeColor=this.pieOuterStrokeColor||"black",this.pieOpacity=this.pieOpacity||"0.7",this.quadrant1Fill=this.quadrant1Fill||this.primaryColor,this.quadrant2Fill=this.quadrant2Fill||o(this.primaryColor,{r:5,g:5,b:5}),this.quadrant3Fill=this.quadrant3Fill||o(this.primaryColor,{r:10,g:10,b:10}),this.quadrant4Fill=this.quadrant4Fill||o(this.primaryColor,{r:15,g:15,b:15}),this.quadrant1TextFill=this.quadrant1TextFill||this.primaryTextColor,this.quadrant2TextFill=this.quadrant2TextFill||o(this.primaryTextColor,{r:-5,g:-5,b:-5}),this.quadrant3TextFill=this.quadrant3TextFill||o(this.primaryTextColor,{r:-10,g:-10,b:-10}),this.quadrant4TextFill=this.quadrant4TextFill||o(this.primaryTextColor,{r:-15,g:-15,b:-15}),this.quadrantPointFill=this.quadrantPointFill||(0,p.A)(this.quadrant1Fill)?(0,d.A)(this.quadrant1Fill):(0,u.A)(this.quadrant1Fill),this.quadrantPointTextFill=this.quadrantPointTextFill||this.primaryTextColor,this.quadrantXAxisTextFill=this.quadrantXAxisTextFill||this.primaryTextColor,this.quadrantYAxisTextFill=this.quadrantYAxisTextFill||this.primaryTextColor,this.quadrantInternalBorderStrokeFill=this.quadrantInternalBorderStrokeFill||this.primaryBorderColor,this.quadrantExternalBorderStrokeFill=this.quadrantExternalBorderStrokeFill||this.primaryBorderColor,this.quadrantTitleFill=this.quadrantTitleFill||this.primaryTextColor,this.xyChart={backgroundColor:this.xyChart?.backgroundColor||this.background,titleColor:this.xyChart?.titleColor||this.primaryTextColor,xAxisTitleColor:this.xyChart?.xAxisTitleColor||this.primaryTextColor,xAxisLabelColor:this.xyChart?.xAxisLabelColor||this.primaryTextColor,xAxisTickColor:this.xyChart?.xAxisTickColor||this.primaryTextColor,xAxisLineColor:this.xyChart?.xAxisLineColor||this.primaryTextColor,yAxisTitleColor:this.xyChart?.yAxisTitleColor||this.primaryTextColor,yAxisLabelColor:this.xyChart?.yAxisLabelColor||this.primaryTextColor,yAxisTickColor:this.xyChart?.yAxisTickColor||this.primaryTextColor,yAxisLineColor:this.xyChart?.yAxisLineColor||this.primaryTextColor,plotColorPalette:this.xyChart?.plotColorPalette||"#EEE,#6BB8E4,#8ACB88,#C7ACD6,#E8DCC2,#FFB2A8,#FFF380,#7E8D91,#FFD8B1,#FAF3E0"},this.requirementBackground=this.requirementBackground||this.primaryColor,this.requirementBorderColor=this.requirementBorderColor||this.primaryBorderColor,this.requirementBorderSize=this.requirementBorderSize||"1",this.requirementTextColor=this.requirementTextColor||this.primaryTextColor,this.relationColor=this.relationColor||this.lineColor,this.relationLabelBackground=this.relationLabelBackground||this.edgeLabelBackground,this.relationLabelColor=this.relationLabelColor||this.actorTextColor,this.git0=(0,u.A)(this.pie1,25)||this.primaryColor,this.git1=this.pie2||this.secondaryColor,this.git2=this.pie3||this.tertiaryColor,this.git3=this.pie4||o(this.primaryColor,{h:-30}),this.git4=this.pie5||o(this.primaryColor,{h:-60}),this.git5=this.pie6||o(this.primaryColor,{h:-90}),this.git6=this.pie7||o(this.primaryColor,{h:60}),this.git7=this.pie8||o(this.primaryColor,{h:120}),this.gitInv0=this.gitInv0||c(this.git0),this.gitInv1=this.gitInv1||c(this.git1),this.gitInv2=this.gitInv2||c(this.git2),this.gitInv3=this.gitInv3||c(this.git3),this.gitInv4=this.gitInv4||c(this.git4),this.gitInv5=this.gitInv5||c(this.git5),this.gitInv6=this.gitInv6||c(this.git6),this.gitInv7=this.gitInv7||c(this.git7),this.branchLabelColor=this.branchLabelColor||this.labelTextColor,this.gitBranchLabel0=this.branchLabelColor,this.gitBranchLabel1="white",this.gitBranchLabel2=this.branchLabelColor,this.gitBranchLabel3="white",this.gitBranchLabel4=this.branchLabelColor,this.gitBranchLabel5=this.branchLabelColor,this.gitBranchLabel6=this.branchLabelColor,this.gitBranchLabel7=this.branchLabelColor,this.tagLabelColor=this.tagLabelColor||this.primaryTextColor,this.tagLabelBackground=this.tagLabelBackground||this.primaryColor,this.tagLabelBorder=this.tagBorder||this.primaryBorderColor,this.tagLabelFontSize=this.tagLabelFontSize||"10px",this.commitLabelColor=this.commitLabelColor||this.secondaryTextColor,this.commitLabelBackground=this.commitLabelBackground||this.secondaryColor,this.commitLabelFontSize=this.commitLabelFontSize||"10px",this.attributeBackgroundColorOdd=this.attributeBackgroundColorOdd||E,this.attributeBackgroundColorEven=this.attributeBackgroundColorEven||N}calculate(t){if("object"!=typeof t)return void this.updateColors();const e=Object.keys(t);e.forEach((e=>{this[e]=t[e]})),this.updateColors(),e.forEach((e=>{this[e]=t[e]}))}},H={base:{getThemeVariables:I},dark:{getThemeVariables:R},default:{getThemeVariables:z},forest:{getThemeVariables:q},neutral:{getThemeVariables:m((t=>{const e=new W;return e.calculate(t),e}),"getThemeVariables")}},U={flowchart:{useMaxWidth:!0,titleTopMargin:25,subGraphTitleMargin:{top:0,bottom:0},diagramPadding:8,htmlLabels:!0,nodeSpacing:50,rankSpacing:50,curve:"basis",padding:15,defaultRenderer:"dagre-wrapper",wrappingWidth:200},sequence:{useMaxWidth:!0,hideUnusedParticipants:!1,activationWidth:10,diagramMarginX:50,diagramMarginY:10,actorMargin:50,width:150,height:65,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",mirrorActors:!0,forceMenus:!1,bottomMarginAdj:1,rightAngles:!1,showSequenceNumbers:!1,actorFontSize:14,actorFontFamily:'"Open Sans", sans-serif',actorFontWeight:400,noteFontSize:14,noteFontFamily:'"trebuchet ms", verdana, arial, sans-serif',noteFontWeight:400,noteAlign:"center",messageFontSize:16,messageFontFamily:'"trebuchet ms", verdana, arial, sans-serif',messageFontWeight:400,wrap:!1,wrapPadding:10,labelBoxWidth:50,labelBoxHeight:20},gantt:{useMaxWidth:!0,titleTopMargin:25,barHeight:20,barGap:4,topPadding:50,rightPadding:75,leftPadding:75,gridLineStartPadding:35,fontSize:11,sectionFontSize:11,numberSectionStyles:4,axisFormat:"%Y-%m-%d",topAxis:!1,displayMode:"",weekday:"sunday"},journey:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,leftMargin:150,width:150,height:50,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,rightAngles:!1,taskFontSize:14,taskFontFamily:'"Open Sans", sans-serif',taskMargin:50,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"]},class:{useMaxWidth:!0,titleTopMargin:25,arrowMarkerAbsolute:!1,dividerMargin:10,padding:5,textHeight:10,defaultRenderer:"dagre-wrapper",htmlLabels:!1,hideEmptyMembersBox:!1},state:{useMaxWidth:!0,titleTopMargin:25,dividerMargin:10,sizeUnit:5,padding:8,textHeight:10,titleShift:-15,noteMargin:10,forkWidth:70,forkHeight:7,miniPadding:2,fontSizeFactor:5.02,fontSize:24,labelHeight:16,edgeLengthFactor:"20",compositTitleSize:35,radius:5,defaultRenderer:"dagre-wrapper"},er:{useMaxWidth:!0,titleTopMargin:25,diagramPadding:20,layoutDirection:"TB",minEntityWidth:100,minEntityHeight:75,entityPadding:15,stroke:"gray",fill:"honeydew",fontSize:12},pie:{useMaxWidth:!0,textPosition:.75},quadrantChart:{useMaxWidth:!0,chartWidth:500,chartHeight:500,titleFontSize:20,titlePadding:10,quadrantPadding:5,xAxisLabelPadding:5,yAxisLabelPadding:5,xAxisLabelFontSize:16,yAxisLabelFontSize:16,quadrantLabelFontSize:16,quadrantTextTopPadding:5,pointTextPadding:5,pointLabelFontSize:12,pointRadius:5,xAxisPosition:"top",yAxisPosition:"left",quadrantInternalBorderStrokeWidth:1,quadrantExternalBorderStrokeWidth:2},xyChart:{useMaxWidth:!0,width:700,height:500,titleFontSize:20,titlePadding:10,showTitle:!0,xAxis:{$ref:"#/$defs/XYChartAxisConfig",showLabel:!0,labelFontSize:14,labelPadding:5,showTitle:!0,titleFontSize:16,titlePadding:5,showTick:!0,tickLength:5,tickWidth:2,showAxisLine:!0,axisLineWidth:2},yAxis:{$ref:"#/$defs/XYChartAxisConfig",showLabel:!0,labelFontSize:14,labelPadding:5,showTitle:!0,titleFontSize:16,titlePadding:5,showTick:!0,tickLength:5,tickWidth:2,showAxisLine:!0,axisLineWidth:2},chartOrientation:"vertical",plotReservedSpacePercent:50},requirement:{useMaxWidth:!0,rect_fill:"#f9f9f9",text_color:"#333",rect_border_size:"0.5px",rect_border_color:"#bbb",rect_min_width:200,rect_min_height:200,fontSize:14,rect_padding:10,line_height:20},mindmap:{useMaxWidth:!0,padding:10,maxNodeWidth:200},kanban:{useMaxWidth:!0,padding:8,sectionWidth:200,ticketBaseUrl:""},timeline:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,leftMargin:150,width:150,height:50,boxMargin:10,boxTextMargin:5,noteMargin:10,messageMargin:35,messageAlign:"center",bottomMarginAdj:1,rightAngles:!1,taskFontSize:14,taskFontFamily:'"Open Sans", sans-serif',taskMargin:50,activationWidth:10,textPlacement:"fo",actorColours:["#8FBC8F","#7CFC00","#00FFFF","#20B2AA","#B0E0E6","#FFFFE0"],sectionFills:["#191970","#8B008B","#4B0082","#2F4F4F","#800000","#8B4513","#00008B"],sectionColours:["#fff"],disableMulticolor:!1},gitGraph:{useMaxWidth:!0,titleTopMargin:25,diagramPadding:8,nodeLabel:{width:75,height:100,x:-25,y:0},mainBranchName:"main",mainBranchOrder:0,showCommitLabel:!0,showBranches:!0,rotateCommitLabel:!0,parallelCommits:!1,arrowMarkerAbsolute:!1},c4:{useMaxWidth:!0,diagramMarginX:50,diagramMarginY:10,c4ShapeMargin:50,c4ShapePadding:20,width:216,height:60,boxMargin:10,c4ShapeInRow:4,nextLinePaddingX:0,c4BoundaryInRow:2,personFontSize:14,personFontFamily:'"Open Sans", sans-serif',personFontWeight:"normal",external_personFontSize:14,external_personFontFamily:'"Open Sans", sans-serif',external_personFontWeight:"normal",systemFontSize:14,systemFontFamily:'"Open Sans", sans-serif',systemFontWeight:"normal",external_systemFontSize:14,external_systemFontFamily:'"Open Sans", sans-serif',external_systemFontWeight:"normal",system_dbFontSize:14,system_dbFontFamily:'"Open Sans", sans-serif',system_dbFontWeight:"normal",external_system_dbFontSize:14,external_system_dbFontFamily:'"Open Sans", sans-serif',external_system_dbFontWeight:"normal",system_queueFontSize:14,system_queueFontFamily:'"Open Sans", sans-serif',system_queueFontWeight:"normal",external_system_queueFontSize:14,external_system_queueFontFamily:'"Open Sans", sans-serif',external_system_queueFontWeight:"normal",boundaryFontSize:14,boundaryFontFamily:'"Open Sans", sans-serif',boundaryFontWeight:"normal",messageFontSize:12,messageFontFamily:'"Open Sans", sans-serif',messageFontWeight:"normal",containerFontSize:14,containerFontFamily:'"Open Sans", sans-serif',containerFontWeight:"normal",external_containerFontSize:14,external_containerFontFamily:'"Open Sans", sans-serif',external_containerFontWeight:"normal",container_dbFontSize:14,container_dbFontFamily:'"Open Sans", sans-serif',container_dbFontWeight:"normal",external_container_dbFontSize:14,external_container_dbFontFamily:'"Open Sans", sans-serif',external_container_dbFontWeight:"normal",container_queueFontSize:14,container_queueFontFamily:'"Open Sans", sans-serif',container_queueFontWeight:"normal",external_container_queueFontSize:14,external_container_queueFontFamily:'"Open Sans", sans-serif',external_container_queueFontWeight:"normal",componentFontSize:14,componentFontFamily:'"Open Sans", sans-serif',componentFontWeight:"normal",external_componentFontSize:14,external_componentFontFamily:'"Open Sans", sans-serif',external_componentFontWeight:"normal",component_dbFontSize:14,component_dbFontFamily:'"Open Sans", sans-serif',component_dbFontWeight:"normal",external_component_dbFontSize:14,external_component_dbFontFamily:'"Open Sans", sans-serif',external_component_dbFontWeight:"normal",component_queueFontSize:14,component_queueFontFamily:'"Open Sans", sans-serif',component_queueFontWeight:"normal",external_component_queueFontSize:14,external_component_queueFontFamily:'"Open Sans", sans-serif',external_component_queueFontWeight:"normal",wrap:!0,wrapPadding:10,person_bg_color:"#08427B",person_border_color:"#073B6F",external_person_bg_color:"#686868",external_person_border_color:"#8A8A8A",system_bg_color:"#1168BD",system_border_color:"#3C7FC0",system_db_bg_color:"#1168BD",system_db_border_color:"#3C7FC0",system_queue_bg_color:"#1168BD",system_queue_border_color:"#3C7FC0",external_system_bg_color:"#999999",external_system_border_color:"#8A8A8A",external_system_db_bg_color:"#999999",external_system_db_border_color:"#8A8A8A",external_system_queue_bg_color:"#999999",external_system_queue_border_color:"#8A8A8A",container_bg_color:"#438DD5",container_border_color:"#3C7FC0",container_db_bg_color:"#438DD5",container_db_border_color:"#3C7FC0",container_queue_bg_color:"#438DD5",container_queue_border_color:"#3C7FC0",external_container_bg_color:"#B3B3B3",external_container_border_color:"#A6A6A6",external_container_db_bg_color:"#B3B3B3",external_container_db_border_color:"#A6A6A6",external_container_queue_bg_color:"#B3B3B3",external_container_queue_border_color:"#A6A6A6",component_bg_color:"#85BBF0",component_border_color:"#78A8D8",component_db_bg_color:"#85BBF0",component_db_border_color:"#78A8D8",component_queue_bg_color:"#85BBF0",component_queue_border_color:"#78A8D8",external_component_bg_color:"#CCCCCC",external_component_border_color:"#BFBFBF",external_component_db_bg_color:"#CCCCCC",external_component_db_border_color:"#BFBFBF",external_component_queue_bg_color:"#CCCCCC",external_component_queue_border_color:"#BFBFBF"},sankey:{useMaxWidth:!0,width:600,height:400,linkColor:"gradient",nodeAlignment:"justify",showValues:!0,prefix:"",suffix:""},block:{useMaxWidth:!0,padding:8},packet:{useMaxWidth:!0,rowHeight:32,bitWidth:32,bitsPerRow:32,showBits:!0,paddingX:5,paddingY:5},architecture:{useMaxWidth:!0,padding:40,iconSize:80,fontSize:16},theme:"default",look:"classic",handDrawnSeed:0,layout:"dagre",maxTextSize:5e4,maxEdges:500,darkMode:!1,fontFamily:'"trebuchet ms", verdana, arial, sans-serif;',logLevel:5,securityLevel:"strict",startOnLoad:!0,arrowMarkerAbsolute:!1,secure:["secure","securityLevel","startOnLoad","maxTextSize","suppressErrorRendering","maxEdges"],legacyMathML:!1,forceLegacyMathML:!1,deterministicIds:!1,fontSize:16,markdownAutoWrap:!0,suppressErrorRendering:!1},Y={...U,deterministicIDSeed:void 0,elk:{mergeEdges:!1,nodePlacementStrategy:"BRANDES_KOEPF"},themeCSS:void 0,themeVariables:H.default.getThemeVariables(),sequence:{...U.sequence,messageFont:m((function(){return{fontFamily:this.messageFontFamily,fontSize:this.messageFontSize,fontWeight:this.messageFontWeight}}),"messageFont"),noteFont:m((function(){return{fontFamily:this.noteFontFamily,fontSize:this.noteFontSize,fontWeight:this.noteFontWeight}}),"noteFont"),actorFont:m((function(){return{fontFamily:this.actorFontFamily,fontSize:this.actorFontSize,fontWeight:this.actorFontWeight}}),"actorFont")},class:{hideEmptyMembersBox:!1},gantt:{...U.gantt,tickInterval:void 0,useWidth:void 0},c4:{...U.c4,useWidth:void 0,personFont:m((function(){return{fontFamily:this.personFontFamily,fontSize:this.personFontSize,fontWeight:this.personFontWeight}}),"personFont"),external_personFont:m((function(){return{fontFamily:this.external_personFontFamily,fontSize:this.external_personFontSize,fontWeight:this.external_personFontWeight}}),"external_personFont"),systemFont:m((function(){return{fontFamily:this.systemFontFamily,fontSize:this.systemFontSize,fontWeight:this.systemFontWeight}}),"systemFont"),external_systemFont:m((function(){return{fontFamily:this.external_systemFontFamily,fontSize:this.external_systemFontSize,fontWeight:this.external_systemFontWeight}}),"external_systemFont"),system_dbFont:m((function(){return{fontFamily:this.system_dbFontFamily,fontSize:this.system_dbFontSize,fontWeight:this.system_dbFontWeight}}),"system_dbFont"),external_system_dbFont:m((function(){return{fontFamily:this.external_system_dbFontFamily,fontSize:this.external_system_dbFontSize,fontWeight:this.external_system_dbFontWeight}}),"external_system_dbFont"),system_queueFont:m((function(){return{fontFamily:this.system_queueFontFamily,fontSize:this.system_queueFontSize,fontWeight:this.system_queueFontWeight}}),"system_queueFont"),external_system_queueFont:m((function(){return{fontFamily:this.external_system_queueFontFamily,fontSize:this.external_system_queueFontSize,fontWeight:this.external_system_queueFontWeight}}),"external_system_queueFont"),containerFont:m((function(){return{fontFamily:this.containerFontFamily,fontSize:this.containerFontSize,fontWeight:this.containerFontWeight}}),"containerFont"),external_containerFont:m((function(){return{fontFamily:this.external_containerFontFamily,fontSize:this.external_containerFontSize,fontWeight:this.external_containerFontWeight}}),"external_containerFont"),container_dbFont:m((function(){return{fontFamily:this.container_dbFontFamily,fontSize:this.container_dbFontSize,fontWeight:this.container_dbFontWeight}}),"container_dbFont"),external_container_dbFont:m((function(){return{fontFamily:this.external_container_dbFontFamily,fontSize:this.external_container_dbFontSize,fontWeight:this.external_container_dbFontWeight}}),"external_container_dbFont"),container_queueFont:m((function(){return{fontFamily:this.container_queueFontFamily,fontSize:this.container_queueFontSize,fontWeight:this.container_queueFontWeight}}),"container_queueFont"),external_container_queueFont:m((function(){return{fontFamily:this.external_container_queueFontFamily,fontSize:this.external_container_queueFontSize,fontWeight:this.external_container_queueFontWeight}}),"external_container_queueFont"),componentFont:m((function(){return{fontFamily:this.componentFontFamily,fontSize:this.componentFontSize,fontWeight:this.componentFontWeight}}),"componentFont"),external_componentFont:m((function(){return{fontFamily:this.external_componentFontFamily,fontSize:this.external_componentFontSize,fontWeight:this.external_componentFontWeight}}),"external_componentFont"),component_dbFont:m((function(){return{fontFamily:this.component_dbFontFamily,fontSize:this.component_dbFontSize,fontWeight:this.component_dbFontWeight}}),"component_dbFont"),external_component_dbFont:m((function(){return{fontFamily:this.external_component_dbFontFamily,fontSize:this.external_component_dbFontSize,fontWeight:this.external_component_dbFontWeight}}),"external_component_dbFont"),component_queueFont:m((function(){return{fontFamily:this.component_queueFontFamily,fontSize:this.component_queueFontSize,fontWeight:this.component_queueFontWeight}}),"component_queueFont"),external_component_queueFont:m((function(){return{fontFamily:this.external_component_queueFontFamily,fontSize:this.external_component_queueFontSize,fontWeight:this.external_component_queueFontWeight}}),"external_component_queueFont"),boundaryFont:m((function(){return{fontFamily:this.boundaryFontFamily,fontSize:this.boundaryFontSize,fontWeight:this.boundaryFontWeight}}),"boundaryFont"),messageFont:m((function(){return{fontFamily:this.messageFontFamily,fontSize:this.messageFontSize,fontWeight:this.messageFontWeight}}),"messageFont")},pie:{...U.pie,useWidth:984},xyChart:{...U.xyChart,useWidth:void 0},requirement:{...U.requirement,useWidth:void 0},packet:{...U.packet}},V=m(((t,e="")=>Object.keys(t).reduce(((r,n)=>Array.isArray(t[n])?r:"object"==typeof t[n]&&null!==t[n]?[...r,e+n,...V(t[n],"")]:[...r,e+n]),[])),"keyify"),G=new Set(V(Y,"")),Z=Y,X=m((t=>{if(b.debug("sanitizeDirective called with",t),"object"==typeof t&&null!=t)if(Array.isArray(t))t.forEach((t=>X(t)));else{for(const e of Object.keys(t)){if(b.debug("Checking key",e),e.startsWith("__")||e.includes("proto")||e.includes("constr")||!G.has(e)||null==t[e]){b.debug("sanitize deleting key: ",e),delete t[e];continue}if("object"==typeof t[e]){b.debug("sanitizing object",e),X(t[e]);continue}const r=["themeCSS","fontFamily","altFontFamily"];for(const n of r)e.includes(n)&&(b.debug("sanitizing css option",e),t[e]=Q(t[e]))}if(t.themeVariables)for(const e of Object.keys(t.themeVariables)){const r=t.themeVariables[e];r?.match&&!r.match(/^[\d "#%(),.;A-Za-z]+$/)&&(t.themeVariables[e]="")}b.debug("After sanitization",t)}}),"sanitizeDirective"),Q=m((t=>{let e=0,r=0;for(const n of t){if(e<r)return"{ /* ERROR: Unbalanced CSS */ }";"{"===n?e++:"}"===n&&r++}return e!==r?"{ /* ERROR: Unbalanced CSS */ }":t}),"sanitizeCss"),J=Object.freeze(Z),tt=$({},J),et=[],rt=$({},J),nt=m(((t,e)=>{let r=$({},t),n={};for(const i of e)ht(i),n=$(n,i);if(r=$(r,n),n.theme&&n.theme in H){const t=$({},h),e=$(t.themeVariables||{},n.themeVariables);r.theme&&r.theme in H&&(r.themeVariables=H[r.theme].getThemeVariables(e))}return mt(rt=r),rt}),"updateCurrentConfig"),it=m((t=>(tt=$({},J),tt=$(tt,t),t.theme&&H[t.theme]&&(tt.themeVariables=H[t.theme].getThemeVariables(t.themeVariables)),nt(tt,et),tt)),"setSiteConfig"),at=m((t=>{h=$({},t)}),"saveConfigFromInitialize"),ot=m((t=>(tt=$(tt,t),nt(tt,et),tt)),"updateSiteConfig"),st=m((()=>$({},tt)),"getSiteConfig"),lt=m((t=>(mt(t),$(rt,t),ct())),"setConfig"),ct=m((()=>$({},rt)),"getConfig"),ht=m((t=>{t&&(["secure",...tt.secure??[]].forEach((e=>{Object.hasOwn(t,e)&&(b.debug(`Denied attempt to modify a secure key ${e}`,t[e]),delete t[e])})),Object.keys(t).forEach((e=>{e.startsWith("__")&&delete t[e]})),Object.keys(t).forEach((e=>{"string"==typeof t[e]&&(t[e].includes("<")||t[e].includes(">")||t[e].includes("url(data:"))&&delete t[e],"object"==typeof t[e]&&ht(t[e])})))}),"sanitize"),ut=m((t=>{X(t),t.fontFamily&&!t.themeVariables?.fontFamily&&(t.themeVariables={...t.themeVariables,fontFamily:t.fontFamily}),et.push(t),nt(tt,et)}),"addDirective"),dt=m(((t=tt)=>{nt(t,et=[])}),"reset"),pt={LAZY_LOAD_DEPRECATED:"The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead."},ft={},gt=m((t=>{ft[t]||(b.warn(pt[t]),ft[t]=!0)}),"issueWarning"),mt=m((t=>{t&&(t.lazyLoadedDiagrams||t.loadExternalDiagramsAtStartup)&>("LAZY_LOAD_DEPRECATED")}),"checkConfig"),yt=/<br\s*\/?>/gi,xt=m((t=>{if(!t)return[""];return Mt(t).replace(/\\n/g,"#br#").split("#br#")}),"getRows"),bt=(()=>{let t=!1;return()=>{t||(kt(),t=!0)}})();function kt(){const t="data-temp-href-target";f.A.addHook("beforeSanitizeAttributes",(e=>{e instanceof Element&&"A"===e.tagName&&e.hasAttribute("target")&&e.setAttribute(t,e.getAttribute("target")??"")})),f.A.addHook("afterSanitizeAttributes",(e=>{e instanceof Element&&"A"===e.tagName&&e.hasAttribute(t)&&(e.setAttribute("target",e.getAttribute(t)??""),e.removeAttribute(t),"_blank"===e.getAttribute("target")&&e.setAttribute("rel","noopener"))}))}m(kt,"setupDompurifyHooks");var Ct=m((t=>{bt();return f.A.sanitize(t)}),"removeScript"),wt=m(((t,e)=>{if(!1!==e.flowchart?.htmlLabels){const r=e.securityLevel;"antiscript"===r||"strict"===r?t=Ct(t):"loose"!==r&&(t=(t=(t=Mt(t)).replace(/</g,"<").replace(/>/g,">")).replace(/=/g,"="),t=Tt(t))}return t}),"sanitizeMore"),_t=m(((t,e)=>t?t=e.dompurifyConfig?f.A.sanitize(wt(t,e),e.dompurifyConfig).toString():f.A.sanitize(wt(t,e),{FORBID_TAGS:["style"]}).toString():t),"sanitizeText"),vt=m(((t,e)=>"string"==typeof t?_t(t,e):t.flat().map((t=>_t(t,e)))),"sanitizeTextOrArray"),St=m((t=>yt.test(t)),"hasBreaks"),At=m((t=>t.split(yt)),"splitBreaks"),Tt=m((t=>t.replace(/#br#/g,"<br/>")),"placeholderToBreak"),Mt=m((t=>t.replace(yt,"#br#")),"breakToPlaceholder"),Bt=m((t=>{let e="";return t&&(e=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,e=e.replaceAll(/\(/g,"\\("),e=e.replaceAll(/\)/g,"\\)")),e}),"getUrl"),Lt=m((t=>!1!==t&&!["false","null","0"].includes(String(t).trim().toLowerCase())),"evaluate"),Ft=m((function(...t){const e=t.filter((t=>!isNaN(t)));return Math.max(...e)}),"getMax"),$t=m((function(...t){const e=t.filter((t=>!isNaN(t)));return Math.min(...e)}),"getMin"),Et=m((function(t){const e=t.split(/(,)/),r=[];for(let n=0;n<e.length;n++){let t=e[n];if(","===t&&n>0&&n+1<e.length){const i=e[n-1],a=e[n+1];Dt(i,a)&&(t=i+","+a,n++,r.pop())}r.push(jt(t))}return r.join("")}),"parseGenericTypes"),Nt=m(((t,e)=>Math.max(0,t.split(e).length-1)),"countOccurrence"),Dt=m(((t,e)=>{const r=Nt(t,"~"),n=Nt(e,"~");return 1===r&&1===n}),"shouldCombineSets"),jt=m((t=>{const e=Nt(t,"~");let r=!1;if(e<=1)return t;e%2!=0&&t.startsWith("~")&&(t=t.substring(1),r=!0);const n=[...t];let i=n.indexOf("~"),a=n.lastIndexOf("~");for(;-1!==i&&-1!==a&&i!==a;)n[i]="<",n[a]=">",i=n.indexOf("~"),a=n.lastIndexOf("~");return r&&n.unshift("~"),n.join("")}),"processSet"),It=m((()=>void 0!==window.MathMLElement),"isMathMLSupported"),Ot=/\$\$(.*)\$\$/g,Rt=m((t=>(t.match(Ot)?.length??0)>0),"hasKatex"),Pt=m((async(t,e)=>{t=await zt(t,e);const r=document.createElement("div");r.innerHTML=t,r.id="katex-temp",r.style.visibility="hidden",r.style.position="absolute",r.style.top="0";const n=document.querySelector("body");n?.insertAdjacentElement("beforeend",r);const i={width:r.clientWidth,height:r.clientHeight};return r.remove(),i}),"calculateMathMLDimensions"),zt=m((async(t,e)=>{if(!Rt(t))return t;if(!(It()||e.legacyMathML||e.forceLegacyMathML))return t.replace(Ot,"MathML is unsupported in this environment.");const{default:n}=await r.e(2130).then(r.bind(r,22130)),i=e.forceLegacyMathML||!It()&&e.legacyMathML?"htmlAndMathml":"mathml";return t.split(yt).map((t=>Rt(t)?`<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">${t}</div>`:`<div>${t}</div>`)).join("").replace(Ot,((t,e)=>n.renderToString(e,{throwOnError:!0,displayMode:!0,output:i}).replace(/\n/g," ").replace(/<annotation.*<\/annotation>/g,"")))}),"renderKatex"),Kt={getRows:xt,sanitizeText:_t,sanitizeTextOrArray:vt,hasBreaks:St,splitBreaks:At,lineBreakRegex:yt,removeScript:Ct,getUrl:Bt,evaluate:Lt,getMax:Ft,getMin:$t},qt=m((function(t,e){for(let r of e)t.attr(r[0],r[1])}),"d3Attrs"),Wt=m((function(t,e,r){let n=new Map;return r?(n.set("width","100%"),n.set("style",`max-width: ${e}px;`)):(n.set("height",t),n.set("width",e)),n}),"calculateSvgSizeAttrs"),Ht=m((function(t,e,r,n){const i=Wt(e,r,n);qt(t,i)}),"configureSvgSize"),Ut=m((function(t,e,r,n){const i=e.node().getBBox(),a=i.width,o=i.height;b.info(`SVG bounds: ${a}x${o}`,i);let s=0,l=0;b.info(`Graph bounds: ${s}x${l}`,t),s=a+2*r,l=o+2*r,b.info(`Calculated bounds: ${s}x${l}`),Ht(e,l,s,n);const c=`${i.x-r} ${i.y-r} ${i.width+2*r} ${i.height+2*r}`;e.attr("viewBox",c)}),"setupGraphViewbox"),Yt={},Vt=m(((t,e,r)=>{let n="";return t in Yt&&Yt[t]?n=Yt[t](r):b.warn(`No theme found for ${t}`),` & {\n font-family: ${r.fontFamily};\n font-size: ${r.fontSize};\n fill: ${r.textColor}\n }\n\n /* Classes common for multiple diagrams */\n\n & .error-icon {\n fill: ${r.errorBkgColor};\n }\n & .error-text {\n fill: ${r.errorTextColor};\n stroke: ${r.errorTextColor};\n }\n\n & .edge-thickness-normal {\n stroke-width: 1px;\n }\n & .edge-thickness-thick {\n stroke-width: 3.5px\n }\n & .edge-pattern-solid {\n stroke-dasharray: 0;\n }\n & .edge-thickness-invisible {\n stroke-width: 0;\n fill: none;\n }\n & .edge-pattern-dashed{\n stroke-dasharray: 3;\n }\n .edge-pattern-dotted {\n stroke-dasharray: 2;\n }\n\n & .marker {\n fill: ${r.lineColor};\n stroke: ${r.lineColor};\n }\n & .marker.cross {\n stroke: ${r.lineColor};\n }\n\n & svg {\n font-family: ${r.fontFamily};\n font-size: ${r.fontSize};\n }\n & p {\n margin: 0\n }\n\n ${n}\n\n ${e}\n`}),"getStyles"),Gt=m(((t,e)=>{void 0!==e&&(Yt[t]=e)}),"addStylesForDiagram"),Zt=Vt,Xt={};y(Xt,{clear:()=>re,getAccDescription:()=>oe,getAccTitle:()=>ie,getDiagramTitle:()=>le,setAccDescription:()=>ae,setAccTitle:()=>ne,setDiagramTitle:()=>se});var Qt="",Jt="",te="",ee=m((t=>_t(t,ct())),"sanitizeText"),re=m((()=>{Qt="",te="",Jt=""}),"clear"),ne=m((t=>{Qt=ee(t).replace(/^\s+/g,"")}),"setAccTitle"),ie=m((()=>Qt),"getAccTitle"),ae=m((t=>{te=ee(t).replace(/\n\s+/g,"\n")}),"setAccDescription"),oe=m((()=>te),"getAccDescription"),se=m((t=>{Jt=ee(t)}),"setDiagramTitle"),le=m((()=>Jt),"getDiagramTitle"),ce=b,he=k,ue=ct,de=lt,pe=J,fe=m((t=>_t(t,ue())),"sanitizeText"),ge=Ut,me=m((()=>Xt),"getCommonDb"),ye={},xe=m(((t,e,r)=>{ye[t]&&ce.warn(`Diagram with id ${t} already registered. Overwriting.`),ye[t]=e,r&&B(t,r),Gt(t,e.styles),e.injectUtils?.(ce,he,ue,fe,ge,me(),(()=>{}))}),"registerDiagram"),be=m((t=>{if(t in ye)return ye[t];throw new ke(t)}),"getDiagram"),ke=class extends Error{static{m(this,"DiagramNotFoundError")}constructor(t){super(`Diagram ${t} not found.`)}}},10483:(t,e,r)=>{"use strict";r.d(e,{W6:()=>Tt,GZ:()=>Ft,hE:()=>Lt});var n=r(8159),i=r(10009),a=r(20007);function o(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}let s={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};function l(t){s=t}const c=/[&<>"']/,h=new RegExp(c.source,"g"),u=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,d=new RegExp(u.source,"g"),p={"&":"&","<":"<",">":">",'"':""","'":"'"},f=t=>p[t];function g(t,e){if(e){if(c.test(t))return t.replace(h,f)}else if(u.test(t))return t.replace(d,f);return t}const m=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;const y=/(^|[^\[])\^/g;function x(t,e){let r="string"==typeof t?t:t.source;e=e||"";const n={replace:(t,e)=>{let i="string"==typeof e?e:e.source;return i=i.replace(y,"$1"),r=r.replace(t,i),n},getRegex:()=>new RegExp(r,e)};return n}function b(t){try{t=encodeURI(t).replace(/%25/g,"%")}catch{return null}return t}const k={exec:()=>null};function C(t,e){const r=t.replace(/\|/g,((t,e,r)=>{let n=!1,i=e;for(;--i>=0&&"\\"===r[i];)n=!n;return n?"|":" |"})).split(/ \|/);let n=0;if(r[0].trim()||r.shift(),r.length>0&&!r[r.length-1].trim()&&r.pop(),e)if(r.length>e)r.splice(e);else for(;r.length<e;)r.push("");for(;n<r.length;n++)r[n]=r[n].trim().replace(/\\\|/g,"|");return r}function w(t,e,r){const n=t.length;if(0===n)return"";let i=0;for(;i<n;){const a=t.charAt(n-i-1);if(a!==e||r){if(a===e||!r)break;i++}else i++}return t.slice(0,n-i)}function _(t,e,r,n){const i=e.href,a=e.title?g(e.title):null,o=t[1].replace(/\\([\[\]])/g,"$1");if("!"!==t[0].charAt(0)){n.state.inLink=!0;const t={type:"link",raw:r,href:i,title:a,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,t}return{type:"image",raw:r,href:i,title:a,text:g(o)}}class v{options;rules;lexer;constructor(t){this.options=t||s}space(t){const e=this.rules.block.newline.exec(t);if(e&&e[0].length>0)return{type:"space",raw:e[0]}}code(t){const e=this.rules.block.code.exec(t);if(e){const t=e[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:e[0],codeBlockStyle:"indented",text:this.options.pedantic?t:w(t,"\n")}}}fences(t){const e=this.rules.block.fences.exec(t);if(e){const t=e[0],r=function(t,e){const r=t.match(/^(\s+)(?:```)/);if(null===r)return e;const n=r[1];return e.split("\n").map((t=>{const e=t.match(/^\s+/);if(null===e)return t;const[r]=e;return r.length>=n.length?t.slice(n.length):t})).join("\n")}(t,e[3]||"");return{type:"code",raw:t,lang:e[2]?e[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):e[2],text:r}}}heading(t){const e=this.rules.block.heading.exec(t);if(e){let t=e[2].trim();if(/#$/.test(t)){const e=w(t,"#");this.options.pedantic?t=e.trim():e&&!/ $/.test(e)||(t=e.trim())}return{type:"heading",raw:e[0],depth:e[1].length,text:t,tokens:this.lexer.inline(t)}}}hr(t){const e=this.rules.block.hr.exec(t);if(e)return{type:"hr",raw:w(e[0],"\n")}}blockquote(t){const e=this.rules.block.blockquote.exec(t);if(e){let t=w(e[0],"\n").split("\n"),r="",n="";const i=[];for(;t.length>0;){let e=!1;const a=[];let o;for(o=0;o<t.length;o++)if(/^ {0,3}>/.test(t[o]))a.push(t[o]),e=!0;else{if(e)break;a.push(t[o])}t=t.slice(o);const s=a.join("\n"),l=s.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1").replace(/^ {0,3}>[ \t]?/gm,"");r=r?`${r}\n${s}`:s,n=n?`${n}\n${l}`:l;const c=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(l,i,!0),this.lexer.state.top=c,0===t.length)break;const h=i[i.length-1];if("code"===h?.type)break;if("blockquote"===h?.type){const e=h,a=e.raw+"\n"+t.join("\n"),o=this.blockquote(a);i[i.length-1]=o,r=r.substring(0,r.length-e.raw.length)+o.raw,n=n.substring(0,n.length-e.text.length)+o.text;break}if("list"!==h?.type);else{const e=h,a=e.raw+"\n"+t.join("\n"),o=this.list(a);i[i.length-1]=o,r=r.substring(0,r.length-h.raw.length)+o.raw,n=n.substring(0,n.length-e.raw.length)+o.raw,t=a.substring(i[i.length-1].raw.length).split("\n")}}return{type:"blockquote",raw:r,tokens:i,text:n}}}list(t){let e=this.rules.block.list.exec(t);if(e){let r=e[1].trim();const n=r.length>1,i={type:"list",raw:"",ordered:n,start:n?+r.slice(0,-1):"",loose:!1,items:[]};r=n?`\\d{1,9}\\${r.slice(-1)}`:`\\${r}`,this.options.pedantic&&(r=n?r:"[*+-]");const a=new RegExp(`^( {0,3}${r})((?:[\t ][^\\n]*)?(?:\\n|$))`);let o=!1;for(;t;){let r=!1,n="",s="";if(!(e=a.exec(t)))break;if(this.rules.block.hr.test(t))break;n=e[0],t=t.substring(n.length);let l=e[2].split("\n",1)[0].replace(/^\t+/,(t=>" ".repeat(3*t.length))),c=t.split("\n",1)[0],h=!l.trim(),u=0;if(this.options.pedantic?(u=2,s=l.trimStart()):h?u=e[1].length+1:(u=e[2].search(/[^ ]/),u=u>4?1:u,s=l.slice(u),u+=e[1].length),h&&/^ *$/.test(c)&&(n+=c+"\n",t=t.substring(c.length+1),r=!0),!r){const e=new RegExp(`^ {0,${Math.min(3,u-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),r=new RegExp(`^ {0,${Math.min(3,u-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),i=new RegExp(`^ {0,${Math.min(3,u-1)}}(?:\`\`\`|~~~)`),a=new RegExp(`^ {0,${Math.min(3,u-1)}}#`);for(;t;){const o=t.split("\n",1)[0];if(c=o,this.options.pedantic&&(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),i.test(c))break;if(a.test(c))break;if(e.test(c))break;if(r.test(t))break;if(c.search(/[^ ]/)>=u||!c.trim())s+="\n"+c.slice(u);else{if(h)break;if(l.search(/[^ ]/)>=4)break;if(i.test(l))break;if(a.test(l))break;if(r.test(l))break;s+="\n"+c}h||c.trim()||(h=!0),n+=o+"\n",t=t.substring(o.length+1),l=c.slice(u)}}i.loose||(o?i.loose=!0:/\n *\n *$/.test(n)&&(o=!0));let d,p=null;this.options.gfm&&(p=/^\[[ xX]\] /.exec(s),p&&(d="[ ] "!==p[0],s=s.replace(/^\[[ xX]\] +/,""))),i.items.push({type:"list_item",raw:n,task:!!p,checked:d,loose:!1,text:s,tokens:[]}),i.raw+=n}i.items[i.items.length-1].raw=i.items[i.items.length-1].raw.trimEnd(),i.items[i.items.length-1].text=i.items[i.items.length-1].text.trimEnd(),i.raw=i.raw.trimEnd();for(let t=0;t<i.items.length;t++)if(this.lexer.state.top=!1,i.items[t].tokens=this.lexer.blockTokens(i.items[t].text,[]),!i.loose){const e=i.items[t].tokens.filter((t=>"space"===t.type)),r=e.length>0&&e.some((t=>/\n.*\n/.test(t.raw)));i.loose=r}if(i.loose)for(let t=0;t<i.items.length;t++)i.items[t].loose=!0;return i}}html(t){const e=this.rules.block.html.exec(t);if(e){return{type:"html",block:!0,raw:e[0],pre:"pre"===e[1]||"script"===e[1]||"style"===e[1],text:e[0]}}}def(t){const e=this.rules.block.def.exec(t);if(e){const t=e[1].toLowerCase().replace(/\s+/g," "),r=e[2]?e[2].replace(/^<(.*)>$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",n=e[3]?e[3].substring(1,e[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):e[3];return{type:"def",tag:t,raw:e[0],href:r,title:n}}}table(t){const e=this.rules.block.table.exec(t);if(!e)return;if(!/[:|]/.test(e[2]))return;const r=C(e[1]),n=e[2].replace(/^\||\| *$/g,"").split("|"),i=e[3]&&e[3].trim()?e[3].replace(/\n[ \t]*$/,"").split("\n"):[],a={type:"table",raw:e[0],header:[],align:[],rows:[]};if(r.length===n.length){for(const t of n)/^ *-+: *$/.test(t)?a.align.push("right"):/^ *:-+: *$/.test(t)?a.align.push("center"):/^ *:-+ *$/.test(t)?a.align.push("left"):a.align.push(null);for(let t=0;t<r.length;t++)a.header.push({text:r[t],tokens:this.lexer.inline(r[t]),header:!0,align:a.align[t]});for(const t of i)a.rows.push(C(t,a.header.length).map(((t,e)=>({text:t,tokens:this.lexer.inline(t),header:!1,align:a.align[e]}))));return a}}lheading(t){const e=this.rules.block.lheading.exec(t);if(e)return{type:"heading",raw:e[0],depth:"="===e[2].charAt(0)?1:2,text:e[1],tokens:this.lexer.inline(e[1])}}paragraph(t){const e=this.rules.block.paragraph.exec(t);if(e){const t="\n"===e[1].charAt(e[1].length-1)?e[1].slice(0,-1):e[1];return{type:"paragraph",raw:e[0],text:t,tokens:this.lexer.inline(t)}}}text(t){const e=this.rules.block.text.exec(t);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(t){const e=this.rules.inline.escape.exec(t);if(e)return{type:"escape",raw:e[0],text:g(e[1])}}tag(t){const e=this.rules.inline.tag.exec(t);if(e)return!this.lexer.state.inLink&&/^<a /i.test(e[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&/^<\/a>/i.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(t){const e=this.rules.inline.link.exec(t);if(e){const t=e[2].trim();if(!this.options.pedantic&&/^</.test(t)){if(!/>$/.test(t))return;const e=w(t.slice(0,-1),"\\");if((t.length-e.length)%2==0)return}else{const t=function(t,e){if(-1===t.indexOf(e[1]))return-1;let r=0;for(let n=0;n<t.length;n++)if("\\"===t[n])n++;else if(t[n]===e[0])r++;else if(t[n]===e[1]&&(r--,r<0))return n;return-1}(e[2],"()");if(t>-1){const r=(0===e[0].indexOf("!")?5:4)+e[1].length+t;e[2]=e[2].substring(0,t),e[0]=e[0].substring(0,r).trim(),e[3]=""}}let r=e[2],n="";if(this.options.pedantic){const t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r);t&&(r=t[1],n=t[3])}else n=e[3]?e[3].slice(1,-1):"";return r=r.trim(),/^</.test(r)&&(r=this.options.pedantic&&!/>$/.test(t)?r.slice(1):r.slice(1,-1)),_(e,{href:r?r.replace(this.rules.inline.anyPunctuation,"$1"):r,title:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n},e[0],this.lexer)}}reflink(t,e){let r;if((r=this.rules.inline.reflink.exec(t))||(r=this.rules.inline.nolink.exec(t))){const t=e[(r[2]||r[1]).replace(/\s+/g," ").toLowerCase()];if(!t){const t=r[0].charAt(0);return{type:"text",raw:t,text:t}}return _(r,t,r[0],this.lexer)}}emStrong(t,e,r=""){let n=this.rules.inline.emStrongLDelim.exec(t);if(!n)return;if(n[3]&&r.match(/[\p{L}\p{N}]/u))return;if(!(n[1]||n[2]||"")||!r||this.rules.inline.punctuation.exec(r)){const r=[...n[0]].length-1;let i,a,o=r,s=0;const l="*"===n[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(l.lastIndex=0,e=e.slice(-1*t.length+r);null!=(n=l.exec(e));){if(i=n[1]||n[2]||n[3]||n[4]||n[5]||n[6],!i)continue;if(a=[...i].length,n[3]||n[4]){o+=a;continue}if((n[5]||n[6])&&r%3&&!((r+a)%3)){s+=a;continue}if(o-=a,o>0)continue;a=Math.min(a,a+o+s);const e=[...n[0]][0].length,l=t.slice(0,r+n.index+e+a);if(Math.min(r,a)%2){const t=l.slice(1,-1);return{type:"em",raw:l,text:t,tokens:this.lexer.inlineTokens(t)}}const c=l.slice(2,-2);return{type:"strong",raw:l,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(t){const e=this.rules.inline.code.exec(t);if(e){let t=e[2].replace(/\n/g," ");const r=/[^ ]/.test(t),n=/^ /.test(t)&&/ $/.test(t);return r&&n&&(t=t.substring(1,t.length-1)),t=g(t,!0),{type:"codespan",raw:e[0],text:t}}}br(t){const e=this.rules.inline.br.exec(t);if(e)return{type:"br",raw:e[0]}}del(t){const e=this.rules.inline.del.exec(t);if(e)return{type:"del",raw:e[0],text:e[2],tokens:this.lexer.inlineTokens(e[2])}}autolink(t){const e=this.rules.inline.autolink.exec(t);if(e){let t,r;return"@"===e[2]?(t=g(e[1]),r="mailto:"+t):(t=g(e[1]),r=t),{type:"link",raw:e[0],text:t,href:r,tokens:[{type:"text",raw:t,text:t}]}}}url(t){let e;if(e=this.rules.inline.url.exec(t)){let t,r;if("@"===e[2])t=g(e[0]),r="mailto:"+t;else{let n;do{n=e[0],e[0]=this.rules.inline._backpedal.exec(e[0])?.[0]??""}while(n!==e[0]);t=g(e[0]),r="www."===e[1]?"http://"+e[0]:e[0]}return{type:"link",raw:e[0],text:t,href:r,tokens:[{type:"text",raw:t,text:t}]}}}inlineText(t){const e=this.rules.inline.text.exec(t);if(e){let t;return t=this.lexer.state.inRawBlock?e[0]:g(e[0]),{type:"text",raw:e[0],text:t}}}}const S=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,A=/(?:[*+-]|\d{1,9}[.)])/,T=x(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,A).replace(/blockCode/g,/ {4}/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),M=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,B=/(?!\s*\])(?:\\.|[^\[\]\\])+/,L=x(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",B).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),F=x(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,A).getRegex(),$="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",E=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,N=x("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",E).replace("tag",$).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),D=x(M).replace("hr",S).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",$).getRegex(),j={blockquote:x(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",D).getRegex(),code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,def:L,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:S,html:N,lheading:T,list:F,newline:/^(?: *(?:\n|$))+/,paragraph:D,table:k,text:/^[^\n]+/},I=x("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",S).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",$).getRegex(),O={...j,table:I,paragraph:x(M).replace("hr",S).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",I).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",$).getRegex()},R={...j,html:x("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",E).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:k,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:x(M).replace("hr",S).replace("heading"," *#{1,6} *[^\n]").replace("lheading",T).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},P=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,z=/^( {2,}|\\)\n(?!\s*$)/,K="\\p{P}\\p{S}",q=x(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,K).getRegex(),W=x(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,K).getRegex(),H=x("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,K).getRegex(),U=x("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,K).getRegex(),Y=x(/\\([punct])/,"gu").replace(/punct/g,K).getRegex(),V=x(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),G=x(E).replace("(?:--\x3e|$)","--\x3e").getRegex(),Z=x("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",G).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),X=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Q=x(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",X).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),J=x(/^!?\[(label)\]\[(ref)\]/).replace("label",X).replace("ref",B).getRegex(),tt=x(/^!?\[(ref)\](?:\[\])?/).replace("ref",B).getRegex(),et={_backpedal:k,anyPunctuation:Y,autolink:V,blockSkip:/\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g,br:z,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:k,emStrongLDelim:W,emStrongRDelimAst:H,emStrongRDelimUnd:U,escape:P,link:Q,nolink:tt,punctuation:q,reflink:J,reflinkSearch:x("reflink|nolink(?!\\()","g").replace("reflink",J).replace("nolink",tt).getRegex(),tag:Z,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,url:k},rt={...et,link:x(/^!?\[(label)\]\((.*?)\)/).replace("label",X).getRegex(),reflink:x(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",X).getRegex()},nt={...et,escape:x(P).replace("])","~|])").getRegex(),url:x(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/},it={...nt,br:x(z).replace("{2,}","*").getRegex(),text:x(nt.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},at={normal:j,gfm:O,pedantic:R},ot={normal:et,gfm:nt,breaks:it,pedantic:rt};class st{tokens;options;state;tokenizer;inlineQueue;constructor(t){this.tokens=[],this.tokens.links=Object.create(null),this.options=t||s,this.options.tokenizer=this.options.tokenizer||new v,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};const e={block:at.normal,inline:ot.normal};this.options.pedantic?(e.block=at.pedantic,e.inline=ot.pedantic):this.options.gfm&&(e.block=at.gfm,this.options.breaks?e.inline=ot.breaks:e.inline=ot.gfm),this.tokenizer.rules=e}static get rules(){return{block:at,inline:ot}}static lex(t,e){return new st(e).lex(t)}static lexInline(t,e){return new st(e).inlineTokens(t)}lex(t){t=t.replace(/\r\n|\r/g,"\n"),this.blockTokens(t,this.tokens);for(let e=0;e<this.inlineQueue.length;e++){const t=this.inlineQueue[e];this.inlineTokens(t.src,t.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(t,e=[],r=!1){let n,i,a;for(t=this.options.pedantic?t.replace(/\t/g," ").replace(/^ +$/gm,""):t.replace(/^( *)(\t+)/gm,((t,e,r)=>e+" ".repeat(r.length)));t;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((r=>!!(n=r.call({lexer:this},t,e))&&(t=t.substring(n.raw.length),e.push(n),!0)))))if(n=this.tokenizer.space(t))t=t.substring(n.raw.length),1===n.raw.length&&e.length>0?e[e.length-1].raw+="\n":e.push(n);else if(n=this.tokenizer.code(t))t=t.substring(n.raw.length),i=e[e.length-1],!i||"paragraph"!==i.type&&"text"!==i.type?e.push(n):(i.raw+="\n"+n.raw,i.text+="\n"+n.text,this.inlineQueue[this.inlineQueue.length-1].src=i.text);else if(n=this.tokenizer.fences(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.heading(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.hr(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.blockquote(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.list(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.html(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.def(t))t=t.substring(n.raw.length),i=e[e.length-1],!i||"paragraph"!==i.type&&"text"!==i.type?this.tokens.links[n.tag]||(this.tokens.links[n.tag]={href:n.href,title:n.title}):(i.raw+="\n"+n.raw,i.text+="\n"+n.raw,this.inlineQueue[this.inlineQueue.length-1].src=i.text);else if(n=this.tokenizer.table(t))t=t.substring(n.raw.length),e.push(n);else if(n=this.tokenizer.lheading(t))t=t.substring(n.raw.length),e.push(n);else{if(a=t,this.options.extensions&&this.options.extensions.startBlock){let e=1/0;const r=t.slice(1);let n;this.options.extensions.startBlock.forEach((t=>{n=t.call({lexer:this},r),"number"==typeof n&&n>=0&&(e=Math.min(e,n))})),e<1/0&&e>=0&&(a=t.substring(0,e+1))}if(this.state.top&&(n=this.tokenizer.paragraph(a)))i=e[e.length-1],r&&"paragraph"===i?.type?(i.raw+="\n"+n.raw,i.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=i.text):e.push(n),r=a.length!==t.length,t=t.substring(n.raw.length);else if(n=this.tokenizer.text(t))t=t.substring(n.raw.length),i=e[e.length-1],i&&"text"===i.type?(i.raw+="\n"+n.raw,i.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=i.text):e.push(n);else if(t){const e="Infinite loop on byte: "+t.charCodeAt(0);if(this.options.silent){console.error(e);break}throw new Error(e)}}return this.state.top=!0,e}inline(t,e=[]){return this.inlineQueue.push({src:t,tokens:e}),e}inlineTokens(t,e=[]){let r,n,i,a,o,s,l=t;if(this.tokens.links){const t=Object.keys(this.tokens.links);if(t.length>0)for(;null!=(a=this.tokenizer.rules.inline.reflinkSearch.exec(l));)t.includes(a[0].slice(a[0].lastIndexOf("[")+1,-1))&&(l=l.slice(0,a.index)+"["+"a".repeat(a[0].length-2)+"]"+l.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(a=this.tokenizer.rules.inline.blockSkip.exec(l));)l=l.slice(0,a.index)+"["+"a".repeat(a[0].length-2)+"]"+l.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(a=this.tokenizer.rules.inline.anyPunctuation.exec(l));)l=l.slice(0,a.index)+"++"+l.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;t;)if(o||(s=""),o=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((n=>!!(r=n.call({lexer:this},t,e))&&(t=t.substring(r.raw.length),e.push(r),!0)))))if(r=this.tokenizer.escape(t))t=t.substring(r.raw.length),e.push(r);else if(r=this.tokenizer.tag(t))t=t.substring(r.raw.length),n=e[e.length-1],n&&"text"===r.type&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):e.push(r);else if(r=this.tokenizer.link(t))t=t.substring(r.raw.length),e.push(r);else if(r=this.tokenizer.reflink(t,this.tokens.links))t=t.substring(r.raw.length),n=e[e.length-1],n&&"text"===r.type&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):e.push(r);else if(r=this.tokenizer.emStrong(t,l,s))t=t.substring(r.raw.length),e.push(r);else if(r=this.tokenizer.codespan(t))t=t.substring(r.raw.length),e.push(r);else if(r=this.tokenizer.br(t))t=t.substring(r.raw.length),e.push(r);else if(r=this.tokenizer.del(t))t=t.substring(r.raw.length),e.push(r);else if(r=this.tokenizer.autolink(t))t=t.substring(r.raw.length),e.push(r);else if(this.state.inLink||!(r=this.tokenizer.url(t))){if(i=t,this.options.extensions&&this.options.extensions.startInline){let e=1/0;const r=t.slice(1);let n;this.options.extensions.startInline.forEach((t=>{n=t.call({lexer:this},r),"number"==typeof n&&n>=0&&(e=Math.min(e,n))})),e<1/0&&e>=0&&(i=t.substring(0,e+1))}if(r=this.tokenizer.inlineText(i))t=t.substring(r.raw.length),"_"!==r.raw.slice(-1)&&(s=r.raw.slice(-1)),o=!0,n=e[e.length-1],n&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):e.push(r);else if(t){const e="Infinite loop on byte: "+t.charCodeAt(0);if(this.options.silent){console.error(e);break}throw new Error(e)}}else t=t.substring(r.raw.length),e.push(r);return e}}class lt{options;parser;constructor(t){this.options=t||s}space(t){return""}code({text:t,lang:e,escaped:r}){const n=(e||"").match(/^\S*/)?.[0],i=t.replace(/\n$/,"")+"\n";return n?'<pre><code class="language-'+g(n)+'">'+(r?i:g(i,!0))+"</code></pre>\n":"<pre><code>"+(r?i:g(i,!0))+"</code></pre>\n"}blockquote({tokens:t}){return`<blockquote>\n${this.parser.parse(t)}</blockquote>\n`}html({text:t}){return t}heading({tokens:t,depth:e}){return`<h${e}>${this.parser.parseInline(t)}</h${e}>\n`}hr(t){return"<hr>\n"}list(t){const e=t.ordered,r=t.start;let n="";for(let a=0;a<t.items.length;a++){const e=t.items[a];n+=this.listitem(e)}const i=e?"ol":"ul";return"<"+i+(e&&1!==r?' start="'+r+'"':"")+">\n"+n+"</"+i+">\n"}listitem(t){let e="";if(t.task){const r=this.checkbox({checked:!!t.checked});t.loose?t.tokens.length>0&&"paragraph"===t.tokens[0].type?(t.tokens[0].text=r+" "+t.tokens[0].text,t.tokens[0].tokens&&t.tokens[0].tokens.length>0&&"text"===t.tokens[0].tokens[0].type&&(t.tokens[0].tokens[0].text=r+" "+t.tokens[0].tokens[0].text)):t.tokens.unshift({type:"text",raw:r+" ",text:r+" "}):e+=r+" "}return e+=this.parser.parse(t.tokens,!!t.loose),`<li>${e}</li>\n`}checkbox({checked:t}){return"<input "+(t?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph({tokens:t}){return`<p>${this.parser.parseInline(t)}</p>\n`}table(t){let e="",r="";for(let i=0;i<t.header.length;i++)r+=this.tablecell(t.header[i]);e+=this.tablerow({text:r});let n="";for(let i=0;i<t.rows.length;i++){const e=t.rows[i];r="";for(let t=0;t<e.length;t++)r+=this.tablecell(e[t]);n+=this.tablerow({text:r})}return n&&(n=`<tbody>${n}</tbody>`),"<table>\n<thead>\n"+e+"</thead>\n"+n+"</table>\n"}tablerow({text:t}){return`<tr>\n${t}</tr>\n`}tablecell(t){const e=this.parser.parseInline(t.tokens),r=t.header?"th":"td";return(t.align?`<${r} align="${t.align}">`:`<${r}>`)+e+`</${r}>\n`}strong({tokens:t}){return`<strong>${this.parser.parseInline(t)}</strong>`}em({tokens:t}){return`<em>${this.parser.parseInline(t)}</em>`}codespan({text:t}){return`<code>${t}</code>`}br(t){return"<br>"}del({tokens:t}){return`<del>${this.parser.parseInline(t)}</del>`}link({href:t,title:e,tokens:r}){const n=this.parser.parseInline(r),i=b(t);if(null===i)return n;let a='<a href="'+(t=i)+'"';return e&&(a+=' title="'+e+'"'),a+=">"+n+"</a>",a}image({href:t,title:e,text:r}){const n=b(t);if(null===n)return r;let i=`<img src="${t=n}" alt="${r}"`;return e&&(i+=` title="${e}"`),i+=">",i}text(t){return"tokens"in t&&t.tokens?this.parser.parseInline(t.tokens):t.text}}class ct{strong({text:t}){return t}em({text:t}){return t}codespan({text:t}){return t}del({text:t}){return t}html({text:t}){return t}text({text:t}){return t}link({text:t}){return""+t}image({text:t}){return""+t}br(){return""}}class ht{options;renderer;textRenderer;constructor(t){this.options=t||s,this.options.renderer=this.options.renderer||new lt,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new ct}static parse(t,e){return new ht(e).parse(t)}static parseInline(t,e){return new ht(e).parseInline(t)}parse(t,e=!0){let r="";for(let n=0;n<t.length;n++){const i=t[n];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[i.type]){const t=i,e=this.options.extensions.renderers[t.type].call({parser:this},t);if(!1!==e||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(t.type)){r+=e||"";continue}}const a=i;switch(a.type){case"space":r+=this.renderer.space(a);continue;case"hr":r+=this.renderer.hr(a);continue;case"heading":r+=this.renderer.heading(a);continue;case"code":r+=this.renderer.code(a);continue;case"table":r+=this.renderer.table(a);continue;case"blockquote":r+=this.renderer.blockquote(a);continue;case"list":r+=this.renderer.list(a);continue;case"html":r+=this.renderer.html(a);continue;case"paragraph":r+=this.renderer.paragraph(a);continue;case"text":{let i=a,o=this.renderer.text(i);for(;n+1<t.length&&"text"===t[n+1].type;)i=t[++n],o+="\n"+this.renderer.text(i);r+=e?this.renderer.paragraph({type:"paragraph",raw:o,text:o,tokens:[{type:"text",raw:o,text:o}]}):o;continue}default:{const t='Token with "'+a.type+'" type was not found.';if(this.options.silent)return console.error(t),"";throw new Error(t)}}}return r}parseInline(t,e){e=e||this.renderer;let r="";for(let n=0;n<t.length;n++){const i=t[n];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[i.type]){const t=this.options.extensions.renderers[i.type].call({parser:this},i);if(!1!==t||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(i.type)){r+=t||"";continue}}const a=i;switch(a.type){case"escape":case"text":r+=e.text(a);break;case"html":r+=e.html(a);break;case"link":r+=e.link(a);break;case"image":r+=e.image(a);break;case"strong":r+=e.strong(a);break;case"em":r+=e.em(a);break;case"codespan":r+=e.codespan(a);break;case"br":r+=e.br(a);break;case"del":r+=e.del(a);break;default:{const t='Token with "'+a.type+'" type was not found.';if(this.options.silent)return console.error(t),"";throw new Error(t)}}}return r}}class ut{options;constructor(t){this.options=t||s}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(t){return t}postprocess(t){return t}processAllTokens(t){return t}}const dt=new class{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.#t(st.lex,ht.parse);parseInline=this.#t(st.lexInline,ht.parseInline);Parser=ht;Renderer=lt;TextRenderer=ct;Lexer=st;Tokenizer=v;Hooks=ut;constructor(...t){this.use(...t)}walkTokens(t,e){let r=[];for(const n of t)switch(r=r.concat(e.call(this,n)),n.type){case"table":{const t=n;for(const n of t.header)r=r.concat(this.walkTokens(n.tokens,e));for(const n of t.rows)for(const t of n)r=r.concat(this.walkTokens(t.tokens,e));break}case"list":{const t=n;r=r.concat(this.walkTokens(t.items,e));break}default:{const t=n;this.defaults.extensions?.childTokens?.[t.type]?this.defaults.extensions.childTokens[t.type].forEach((n=>{const i=t[n].flat(1/0);r=r.concat(this.walkTokens(i,e))})):t.tokens&&(r=r.concat(this.walkTokens(t.tokens,e)))}}return r}use(...t){const e=this.defaults.extensions||{renderers:{},childTokens:{}};return t.forEach((t=>{const r={...t};if(r.async=this.defaults.async||r.async||!1,t.extensions&&(t.extensions.forEach((t=>{if(!t.name)throw new Error("extension name required");if("renderer"in t){const r=e.renderers[t.name];e.renderers[t.name]=r?function(...e){let n=t.renderer.apply(this,e);return!1===n&&(n=r.apply(this,e)),n}:t.renderer}if("tokenizer"in t){if(!t.level||"block"!==t.level&&"inline"!==t.level)throw new Error("extension level must be 'block' or 'inline'");const r=e[t.level];r?r.unshift(t.tokenizer):e[t.level]=[t.tokenizer],t.start&&("block"===t.level?e.startBlock?e.startBlock.push(t.start):e.startBlock=[t.start]:"inline"===t.level&&(e.startInline?e.startInline.push(t.start):e.startInline=[t.start]))}"childTokens"in t&&t.childTokens&&(e.childTokens[t.name]=t.childTokens)})),r.extensions=e),t.renderer){const e=this.defaults.renderer||new lt(this.defaults);for(const r in t.renderer){if(!(r in e))throw new Error(`renderer '${r}' does not exist`);if(["options","parser"].includes(r))continue;const n=r;let i=t.renderer[n];t.useNewRenderer||(i=this.#e(i,n,e));const a=e[n];e[n]=(...t)=>{let r=i.apply(e,t);return!1===r&&(r=a.apply(e,t)),r||""}}r.renderer=e}if(t.tokenizer){const e=this.defaults.tokenizer||new v(this.defaults);for(const r in t.tokenizer){if(!(r in e))throw new Error(`tokenizer '${r}' does not exist`);if(["options","rules","lexer"].includes(r))continue;const n=r,i=t.tokenizer[n],a=e[n];e[n]=(...t)=>{let r=i.apply(e,t);return!1===r&&(r=a.apply(e,t)),r}}r.tokenizer=e}if(t.hooks){const e=this.defaults.hooks||new ut;for(const r in t.hooks){if(!(r in e))throw new Error(`hook '${r}' does not exist`);if("options"===r)continue;const n=r,i=t.hooks[n],a=e[n];ut.passThroughHooks.has(r)?e[n]=t=>{if(this.defaults.async)return Promise.resolve(i.call(e,t)).then((t=>a.call(e,t)));const r=i.call(e,t);return a.call(e,r)}:e[n]=(...t)=>{let r=i.apply(e,t);return!1===r&&(r=a.apply(e,t)),r}}r.hooks=e}if(t.walkTokens){const e=this.defaults.walkTokens,n=t.walkTokens;r.walkTokens=function(t){let r=[];return r.push(n.call(this,t)),e&&(r=r.concat(e.call(this,t))),r}}this.defaults={...this.defaults,...r}})),this}#e(t,e,r){switch(e){case"heading":return function(n){return n.type&&n.type===e?t.call(this,r.parser.parseInline(n.tokens),n.depth,function(t){return t.replace(m,((t,e)=>"colon"===(e=e.toLowerCase())?":":"#"===e.charAt(0)?"x"===e.charAt(1)?String.fromCharCode(parseInt(e.substring(2),16)):String.fromCharCode(+e.substring(1)):""))}(r.parser.parseInline(n.tokens,r.parser.textRenderer))):t.apply(this,arguments)};case"code":return function(r){return r.type&&r.type===e?t.call(this,r.text,r.lang,!!r.escaped):t.apply(this,arguments)};case"table":return function(r){if(!r.type||r.type!==e)return t.apply(this,arguments);let n="",i="";for(let t=0;t<r.header.length;t++)i+=this.tablecell({text:r.header[t].text,tokens:r.header[t].tokens,header:!0,align:r.align[t]});n+=this.tablerow({text:i});let a="";for(let t=0;t<r.rows.length;t++){const e=r.rows[t];i="";for(let t=0;t<e.length;t++)i+=this.tablecell({text:e[t].text,tokens:e[t].tokens,header:!1,align:r.align[t]});a+=this.tablerow({text:i})}return t.call(this,n,a)};case"blockquote":return function(r){if(!r.type||r.type!==e)return t.apply(this,arguments);const n=this.parser.parse(r.tokens);return t.call(this,n)};case"list":return function(r){if(!r.type||r.type!==e)return t.apply(this,arguments);const n=r.ordered,i=r.start,a=r.loose;let o="";for(let t=0;t<r.items.length;t++){const e=r.items[t],n=e.checked,i=e.task;let s="";if(e.task){const t=this.checkbox({checked:!!n});a?e.tokens.length>0&&"paragraph"===e.tokens[0].type?(e.tokens[0].text=t+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&"text"===e.tokens[0].tokens[0].type&&(e.tokens[0].tokens[0].text=t+" "+e.tokens[0].tokens[0].text)):e.tokens.unshift({type:"text",text:t+" "}):s+=t+" "}s+=this.parser.parse(e.tokens,a),o+=this.listitem({type:"list_item",raw:s,text:s,task:i,checked:!!n,loose:a,tokens:e.tokens})}return t.call(this,o,n,i)};case"html":return function(r){return r.type&&r.type===e?t.call(this,r.text,r.block):t.apply(this,arguments)};case"paragraph":case"strong":case"em":case"del":return function(r){return r.type&&r.type===e?t.call(this,this.parser.parseInline(r.tokens)):t.apply(this,arguments)};case"escape":case"codespan":case"text":return function(r){return r.type&&r.type===e?t.call(this,r.text):t.apply(this,arguments)};case"link":return function(r){return r.type&&r.type===e?t.call(this,r.href,r.title,this.parser.parseInline(r.tokens)):t.apply(this,arguments)};case"image":return function(r){return r.type&&r.type===e?t.call(this,r.href,r.title,r.text):t.apply(this,arguments)}}return t}setOptions(t){return this.defaults={...this.defaults,...t},this}lexer(t,e){return st.lex(t,e??this.defaults)}parser(t,e){return ht.parse(t,e??this.defaults)}#t(t,e){return(r,n)=>{const i={...n},a={...this.defaults,...i};!0===this.defaults.async&&!1===i.async&&(a.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),a.async=!0);const o=this.#r(!!a.silent,!!a.async);if(null==r)return o(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof r)return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(r)+", string expected"));if(a.hooks&&(a.hooks.options=a),a.async)return Promise.resolve(a.hooks?a.hooks.preprocess(r):r).then((e=>t(e,a))).then((t=>a.hooks?a.hooks.processAllTokens(t):t)).then((t=>a.walkTokens?Promise.all(this.walkTokens(t,a.walkTokens)).then((()=>t)):t)).then((t=>e(t,a))).then((t=>a.hooks?a.hooks.postprocess(t):t)).catch(o);try{a.hooks&&(r=a.hooks.preprocess(r));let n=t(r,a);a.hooks&&(n=a.hooks.processAllTokens(n)),a.walkTokens&&this.walkTokens(n,a.walkTokens);let i=e(n,a);return a.hooks&&(i=a.hooks.postprocess(i)),i}catch(s){return o(s)}}}#r(t,e){return r=>{if(r.message+="\nPlease report this to https://github.com/markedjs/marked.",t){const t="<p>An error occurred:</p><pre>"+g(r.message+"",!0)+"</pre>";return e?Promise.resolve(t):t}if(e)return Promise.reject(r);throw r}}};function pt(t,e){return dt.parse(t,e)}pt.options=pt.setOptions=function(t){return dt.setOptions(t),pt.defaults=dt.defaults,l(pt.defaults),pt},pt.getDefaults=o,pt.defaults=s,pt.use=function(...t){return dt.use(...t),pt.defaults=dt.defaults,l(pt.defaults),pt},pt.walkTokens=function(t,e){return dt.walkTokens(t,e)},pt.parseInline=dt.parseInline,pt.Parser=ht,pt.parser=ht.parse,pt.Renderer=lt,pt.TextRenderer=ct,pt.Lexer=st,pt.lexer=st.lex,pt.Tokenizer=v,pt.Hooks=ut,pt.parse=pt;pt.options,pt.setOptions,pt.use,pt.walkTokens,pt.parseInline,ht.parse,st.lex;var ft=r(60513);function gt(t,{markdownAutoWrap:e}){const r=t.replace(/<br\/>/g,"\n").replace(/\n{2,}/g,"\n"),n=(0,ft.T)(r);return!1===e?n.replace(/ /g," "):n}function mt(t,e={}){const r=gt(t,e),n=pt.lexer(r),a=[[]];let o=0;function s(t,e="normal"){if("text"===t.type){t.text.split("\n").forEach(((t,r)=>{0!==r&&(o++,a.push([])),t.split(" ").forEach((t=>{(t=t.replace(/'/g,"'"))&&a[o].push({content:t,type:e})}))}))}else"strong"===t.type||"em"===t.type?t.tokens.forEach((e=>{s(e,t.type)})):"html"===t.type&&a[o].push({content:t.text,type:"normal"})}return(0,i.K2)(s,"processNode"),n.forEach((t=>{"paragraph"===t.type?t.tokens?.forEach((t=>{s(t)})):"html"===t.type&&a[o].push({content:t.text,type:"normal"})})),a}function yt(t,{markdownAutoWrap:e}={}){const r=pt.lexer(t);function n(t){return"text"===t.type?!1===e?t.text.replace(/\n */g,"<br/>").replace(/ /g," "):t.text.replace(/\n */g,"<br/>"):"strong"===t.type?`<strong>${t.tokens?.map(n).join("")}</strong>`:"em"===t.type?`<em>${t.tokens?.map(n).join("")}</em>`:"paragraph"===t.type?`<p>${t.tokens?.map(n).join("")}</p>`:"space"===t.type?"":"html"===t.type?`${t.text}`:"escape"===t.type?t.text:`Unsupported markdown: ${t.type}`}return(0,i.K2)(n,"output"),r.map(n).join("")}function xt(t){return Intl.Segmenter?[...(new Intl.Segmenter).segment(t)].map((t=>t.segment)):[...t]}function bt(t,e){return kt(t,[],xt(e.content),e.type)}function kt(t,e,r,n){if(0===r.length)return[{content:e.join(""),type:n},{content:"",type:n}];const[i,...a]=r,o=[...e,i];return t([{content:o.join(""),type:n}])?kt(t,o,a,n):(0===e.length&&i&&(e.push(i),r.shift()),[{content:e.join(""),type:n},{content:r.join(""),type:n}])}function Ct(t,e){if(t.some((({content:t})=>t.includes("\n"))))throw new Error("splitLineToFitWidth does not support newlines in the line");return wt(t,e)}function wt(t,e,r=[],n=[]){if(0===t.length)return n.length>0&&r.push(n),r.length>0?r:[];let i="";" "===t[0].content&&(i=" ",t.shift());const a=t.shift()??{content:" ",type:"normal"},o=[...n];if(""!==i&&o.push({content:i,type:"normal"}),o.push(a),e(o))return wt(t,e,r,o);if(n.length>0)r.push(n),t.unshift(a);else if(a.content){const[n,i]=bt(e,a);r.push([n]),i.content&&t.unshift(i)}return wt(t,e,r)}function _t(t,e){e&&t.attr("style",e)}async function vt(t,e,r,n,a=!1){const o=t.append("foreignObject");o.attr("width",10*r+"px"),o.attr("height",10*r+"px");const s=o.append("xhtml:div");let l=e.label;e.label&&(0,i.Wi)(e.label)&&(l=await(0,i.VJ)(e.label.replace(i.Y2.lineBreakRegex,"\n"),(0,i.D7)()));const c=e.isNode?"nodeLabel":"edgeLabel",h=s.append("span");h.html(l),_t(h,e.labelStyle),h.attr("class",`${c} ${n}`),_t(s,e.labelStyle),s.style("display","table-cell"),s.style("white-space","nowrap"),s.style("line-height","1.5"),s.style("max-width",r+"px"),s.style("text-align","center"),s.attr("xmlns","http://www.w3.org/1999/xhtml"),a&&s.attr("class","labelBkg");let u=s.node().getBoundingClientRect();return u.width===r&&(s.style("display","table"),s.style("white-space","break-spaces"),s.style("width",r+"px"),u=s.node().getBoundingClientRect()),o.node()}function St(t,e,r){return t.append("tspan").attr("class","text-outer-tspan").attr("x",0).attr("y",e*r-.1+"em").attr("dy",r+"em")}function At(t,e,r){const n=t.append("text"),i=St(n,1,e);Bt(i,r);const a=i.node().getComputedTextLength();return n.remove(),a}function Tt(t,e,r){const n=t.append("text"),i=St(n,1,e);Bt(i,[{content:r,type:"normal"}]);const a=i.node()?.getBoundingClientRect();return a&&n.remove(),a}function Mt(t,e,r,n=!1){const a=e.append("g"),o=a.insert("rect").attr("class","background").attr("style","stroke: none"),s=a.append("text").attr("y","-10.1");let l=0;for(const c of r){const e=(0,i.K2)((e=>At(a,1.1,e)<=t),"checkWidth"),r=e(c)?[c]:Ct(c,e);for(const t of r){Bt(St(s,l,1.1),t),l++}}if(n){const t=s.node().getBBox(),e=2;return o.attr("x",t.x-e).attr("y",t.y-e).attr("width",t.width+2*e).attr("height",t.height+2*e),a.node()}return s.node()}function Bt(t,e){t.text(""),e.forEach(((e,r)=>{const n=t.append("tspan").attr("font-style","em"===e.type?"italic":"normal").attr("class","text-inner-tspan").attr("font-weight","strong"===e.type?"bold":"normal");0===r?n.text(e.content):n.text(" "+e.content)}))}function Lt(t){return t.replace(/fa[bklrs]?:fa-[\w-]+/g,(t=>`<i class='${t.replace(":"," ")}'></i>`))}(0,i.K2)(gt,"preprocessMarkdown"),(0,i.K2)(mt,"markdownToLines"),(0,i.K2)(yt,"markdownToHTML"),(0,i.K2)(xt,"splitTextToChars"),(0,i.K2)(bt,"splitWordToFitWidth"),(0,i.K2)(kt,"splitWordToFitWidthRecursion"),(0,i.K2)(Ct,"splitLineToFitWidth"),(0,i.K2)(wt,"splitLineToFitWidthRecursion"),(0,i.K2)(_t,"applyStyle"),(0,i.K2)(vt,"addHtmlSpan"),(0,i.K2)(St,"createTspan"),(0,i.K2)(At,"computeWidthOfText"),(0,i.K2)(Tt,"computeDimensionOfText"),(0,i.K2)(Mt,"createFormattedText"),(0,i.K2)(Bt,"updateTextContentAndStyles"),(0,i.K2)(Lt,"replaceIconSubstring");var Ft=(0,i.K2)((async(t,e="",{style:r="",isTitle:o=!1,classes:s="",useHtmlLabels:l=!0,isNode:c=!0,width:h=200,addSvgBackground:u=!1}={},d)=>{if(i.Rm.debug("XYZ createText",e,r,o,s,l,c,"addSvgBackground: ",u),l){const a=yt(e,d),o=Lt((0,n.Sm)(a)),l=e.replace(/\\\\/g,"\\"),p={isNode:c,label:(0,i.Wi)(e)?l:o,labelStyle:r.replace("fill:","color:")};return await vt(t,p,h,s,u)}{const n=Mt(h,t,mt(e.replace(/<br\s*\/?>/g,"<br/>").replace("<br>","<br/>"),d),!!e&&u);if(c){/stroke:/.exec(r)&&(r=r.replace("stroke:","lineColor:"));const t=r.replace(/stroke:[^;]+;?/g,"").replace(/stroke-width:[^;]+;?/g,"").replace(/fill:[^;]+;?/g,"").replace(/color:/g,"fill:");(0,a.Ltv)(n).attr("style",t)}else{const t=r.replace(/stroke:[^;]+;?/g,"").replace(/stroke-width:[^;]+;?/g,"").replace(/fill:[^;]+;?/g,"").replace(/background:/g,"fill:");(0,a.Ltv)(n).select("rect").attr("style",t.replace(/background:/g,"fill:"));const e=r.replace(/stroke:[^;]+;?/g,"").replace(/stroke-width:[^;]+;?/g,"").replace(/fill:[^;]+;?/g,"").replace(/color:/g,"fill:");(0,a.Ltv)(n).select("text").attr("style",e)}return n}}),"createText")},8159:(t,e,r)=>{"use strict";r.d(e,{$C:()=>T,$t:()=>q,C4:()=>H,I5:()=>K,Ib:()=>g,KL:()=>V,Sm:()=>U,Un:()=>D,_K:()=>W,bH:()=>$,dq:()=>P,pe:()=>l,rY:()=>Y,ru:()=>N,sM:()=>S,vU:()=>p,yT:()=>B});var n=r(10009),i=r(16750),a=r(20007),o=r(46632),s=r(42837),l="\u200b",c={curveBasis:a.qrM,curveBasisClosed:a.Yu4,curveBasisOpen:a.IA3,curveBumpX:a.Wi0,curveBumpY:a.PGM,curveBundle:a.OEq,curveCardinalClosed:a.olC,curveCardinalOpen:a.IrU,curveCardinal:a.y8u,curveCatmullRomClosed:a.Q7f,curveCatmullRomOpen:a.cVp,curveCatmullRom:a.oDi,curveLinear:a.lUB,curveLinearClosed:a.Lx9,curveMonotoneX:a.nVG,curveMonotoneY:a.uxU,curveNatural:a.Xf2,curveStep:a.GZz,curveStepAfter:a.UPb,curveStepBefore:a.dyv},h=/\s*(?:(\w+)(?=:):|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi,u=(0,n.K2)((function(t,e){const r=d(t,/(?:init\b)|(?:initialize\b)/);let i={};if(Array.isArray(r)){const t=r.map((t=>t.args));(0,n.$i)(t),i=(0,n.hH)(i,[...t])}else i=r.args;if(!i)return;let a=(0,n.Ch)(t,e);const o="config";return void 0!==i[o]&&("flowchart-v2"===a&&(a="flowchart"),i[a]=i[o],delete i[o]),i}),"detectInit"),d=(0,n.K2)((function(t,e=null){try{const r=new RegExp(`[%]{2}(?![{]${h.source})(?=[}][%]{2}).*\n`,"ig");let i;t=t.trim().replace(r,"").replace(/'/gm,'"'),n.Rm.debug(`Detecting diagram directive${null!==e?" type:"+e:""} based on the text:${t}`);const a=[];for(;null!==(i=n.DB.exec(t));)if(i.index===n.DB.lastIndex&&n.DB.lastIndex++,i&&!e||e&&i[1]?.match(e)||e&&i[2]?.match(e)){const t=i[1]?i[1]:i[2],e=i[3]?i[3].trim():i[4]?JSON.parse(i[4].trim()):null;a.push({type:t,args:e})}return 0===a.length?{type:t,args:null}:1===a.length?a[0]:a}catch(r){return n.Rm.error(`ERROR: ${r.message} - Unable to parse directive type: '${e}' based on the text: '${t}'`),{type:void 0,args:null}}}),"detectDirective"),p=(0,n.K2)((function(t){return t.replace(n.DB,"")}),"removeDirectives"),f=(0,n.K2)((function(t,e){for(const[r,n]of e.entries())if(n.match(t))return r;return-1}),"isSubstringInArray");function g(t,e){if(!t)return e;const r=`curve${t.charAt(0).toUpperCase()+t.slice(1)}`;return c[r]??e}function m(t,e){const r=t.trim();if(r)return"loose"!==e.securityLevel?(0,i.J)(r):r}(0,n.K2)(g,"interpolateToCurve"),(0,n.K2)(m,"formatUrl");var y=(0,n.K2)(((t,...e)=>{const r=t.split("."),i=r.length-1,a=r[i];let o=window;for(let s=0;s<i;s++)if(o=o[r[s]],!o)return void n.Rm.error(`Function name: ${t} not found in window`);o[a](...e)}),"runFunc");function x(t,e){return t&&e?Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2)):0}function b(t){let e,r=0;t.forEach((t=>{r+=x(t,e),e=t}));return w(t,r/2)}function k(t){return 1===t.length?t[0]:b(t)}(0,n.K2)(x,"distance"),(0,n.K2)(b,"traverseEdge"),(0,n.K2)(k,"calcLabelPosition");var C=(0,n.K2)(((t,e=2)=>{const r=Math.pow(10,e);return Math.round(t*r)/r}),"roundNumber"),w=(0,n.K2)(((t,e)=>{let r,n=e;for(const i of t){if(r){const t=x(i,r);if(t<n)n-=t;else{const e=n/t;if(e<=0)return r;if(e>=1)return{x:i.x,y:i.y};if(e>0&&e<1)return{x:C((1-e)*r.x+e*i.x,5),y:C((1-e)*r.y+e*i.y,5)}}}r=i}throw new Error("Could not find a suitable point for the given distance")}),"calculatePoint"),_=(0,n.K2)(((t,e,r)=>{n.Rm.info(`our points ${JSON.stringify(e)}`),e[0]!==r&&(e=e.reverse());const i=w(e,25),a=t?10:5,o=Math.atan2(e[0].y-i.y,e[0].x-i.x),s={x:0,y:0};return s.x=Math.sin(o)*a+(e[0].x+i.x)/2,s.y=-Math.cos(o)*a+(e[0].y+i.y)/2,s}),"calcCardinalityPosition");function v(t,e,r){const i=structuredClone(r);n.Rm.info("our points",i),"start_left"!==e&&"start_right"!==e&&i.reverse();const a=w(i,25+t),o=10+.5*t,s=Math.atan2(i[0].y-a.y,i[0].x-a.x),l={x:0,y:0};return"start_left"===e?(l.x=Math.sin(s+Math.PI)*o+(i[0].x+a.x)/2,l.y=-Math.cos(s+Math.PI)*o+(i[0].y+a.y)/2):"end_right"===e?(l.x=Math.sin(s-Math.PI)*o+(i[0].x+a.x)/2-5,l.y=-Math.cos(s-Math.PI)*o+(i[0].y+a.y)/2-5):"end_left"===e?(l.x=Math.sin(s)*o+(i[0].x+a.x)/2-5,l.y=-Math.cos(s)*o+(i[0].y+a.y)/2-5):(l.x=Math.sin(s)*o+(i[0].x+a.x)/2,l.y=-Math.cos(s)*o+(i[0].y+a.y)/2),l}function S(t){let e="",r="";for(const n of t)void 0!==n&&(n.startsWith("color:")||n.startsWith("text-align:")?r=r+n+";":e=e+n+";");return{style:e,labelStyle:r}}(0,n.K2)(v,"calcTerminalLabelPosition"),(0,n.K2)(S,"getStylesFromArray");var A=0,T=(0,n.K2)((()=>(A++,"id-"+Math.random().toString(36).substr(2,12)+"-"+A)),"generateId");function M(t){let e="";const r="0123456789abcdef";for(let n=0;n<t;n++)e+=r.charAt(Math.floor(16*Math.random()));return e}(0,n.K2)(M,"makeRandomHex");var B=(0,n.K2)((t=>M(t.length)),"random"),L=(0,n.K2)((function(){return{x:0,y:0,fill:void 0,anchor:"start",style:"#666",width:100,height:100,textMargin:0,rx:0,ry:0,valign:void 0,text:""}}),"getTextObj"),F=(0,n.K2)((function(t,e){const r=e.text.replace(n.Y2.lineBreakRegex," "),[,i]=K(e.fontSize),a=t.append("text");a.attr("x",e.x),a.attr("y",e.y),a.style("text-anchor",e.anchor),a.style("font-family",e.fontFamily),a.style("font-size",i),a.style("font-weight",e.fontWeight),a.attr("fill",e.fill),void 0!==e.class&&a.attr("class",e.class);const o=a.append("tspan");return o.attr("x",e.x+2*e.textMargin),o.attr("fill",e.fill),o.text(r),a}),"drawSimpleText"),$=(0,o.A)(((t,e,r)=>{if(!t)return t;if(r=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",joinWith:"<br/>"},r),n.Y2.lineBreakRegex.test(t))return t;const i=t.split(" ").filter(Boolean),a=[];let o="";return i.forEach(((t,n)=>{const s=D(`${t} `,r),l=D(o,r);if(s>e){const{hyphenatedStrings:n,remainingWord:i}=E(t,e,"-",r);a.push(o,...n),o=i}else l+s>=e?(a.push(o),o=t):o=[o,t].filter(Boolean).join(" ");n+1===i.length&&a.push(o)})),a.filter((t=>""!==t)).join(r.joinWith)}),((t,e,r)=>`${t}${e}${r.fontSize}${r.fontWeight}${r.fontFamily}${r.joinWith}`)),E=(0,o.A)(((t,e,r="-",n)=>{n=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",margin:0},n);const i=[...t],a=[];let o="";return i.forEach(((t,s)=>{const l=`${o}${t}`;if(D(l,n)>=e){const t=s+1,e=i.length===t,n=`${l}${r}`;a.push(e?l:n),o=""}else o=l})),{hyphenatedStrings:a,remainingWord:o}}),((t,e,r="-",n)=>`${t}${e}${r}${n.fontSize}${n.fontWeight}${n.fontFamily}`));function N(t,e){return I(t,e).height}function D(t,e){return I(t,e).width}(0,n.K2)(N,"calculateTextHeight"),(0,n.K2)(D,"calculateTextWidth");var j,I=(0,o.A)(((t,e)=>{const{fontSize:r=12,fontFamily:i="Arial",fontWeight:o=400}=e;if(!t)return{width:0,height:0};const[,s]=K(r),c=["sans-serif",i],h=t.split(n.Y2.lineBreakRegex),u=[],d=(0,a.Ltv)("body");if(!d.remove)return{width:0,height:0,lineHeight:0};const p=d.append("svg");for(const n of c){let t=0;const e={width:0,height:0,lineHeight:0};for(const r of h){const i=L();i.text=r||l;const a=F(p,i).style("font-size",s).style("font-weight",o).style("font-family",n),c=(a._groups||a)[0][0].getBBox();if(0===c.width&&0===c.height)throw new Error("svg element not in render tree");e.width=Math.round(Math.max(e.width,c.width)),t=Math.round(c.height),e.height+=t,e.lineHeight=Math.round(Math.max(e.lineHeight,t))}u.push(e)}p.remove();return u[isNaN(u[1].height)||isNaN(u[1].width)||isNaN(u[1].lineHeight)||u[0].height>u[1].height&&u[0].width>u[1].width&&u[0].lineHeight>u[1].lineHeight?0:1]}),((t,e)=>`${t}${e.fontSize}${e.fontWeight}${e.fontFamily}`)),O=class{constructor(t=!1,e){this.count=0,this.count=e?e.length:0,this.next=t?()=>this.count++:()=>Date.now()}static{(0,n.K2)(this,"InitIDGenerator")}},R=(0,n.K2)((function(t){return j=j||document.createElement("div"),t=escape(t).replace(/%26/g,"&").replace(/%23/g,"#").replace(/%3B/g,";"),j.innerHTML=t,unescape(j.textContent)}),"entityDecode");function P(t){return"str"in t}(0,n.K2)(P,"isDetailedError");var z=(0,n.K2)(((t,e,r,n)=>{if(!n)return;const i=t.node()?.getBBox();i&&t.append("text").text(n).attr("text-anchor","middle").attr("x",i.x+i.width/2).attr("y",-r).attr("class",e)}),"insertTitle"),K=(0,n.K2)((t=>{if("number"==typeof t)return[t,t+"px"];const e=parseInt(t??"",10);return Number.isNaN(e)?[void 0,void 0]:t===String(e)?[e,t+"px"]:[e,t]}),"parseFontSize");function q(t,e){return(0,s.A)({},t,e)}(0,n.K2)(q,"cleanAndMerge");var W={assignWithDepth:n.hH,wrapLabel:$,calculateTextHeight:N,calculateTextWidth:D,calculateTextDimensions:I,cleanAndMerge:q,detectInit:u,detectDirective:d,isSubstringInArray:f,interpolateToCurve:g,calcLabelPosition:k,calcCardinalityPosition:_,calcTerminalLabelPosition:v,formatUrl:m,getStylesFromArray:S,generateId:T,random:B,runFunc:y,entityDecode:R,insertTitle:z,parseFontSize:K,InitIDGenerator:O},H=(0,n.K2)((function(t){let e=t;return e=e.replace(/style.*:\S*#.*;/g,(function(t){return t.substring(0,t.length-1)})),e=e.replace(/classDef.*:\S*#.*;/g,(function(t){return t.substring(0,t.length-1)})),e=e.replace(/#\w+;/g,(function(t){const e=t.substring(1,t.length-1);return/^\+?\d+$/.test(e)?"\ufb02\xb0\xb0"+e+"\xb6\xdf":"\ufb02\xb0"+e+"\xb6\xdf"})),e}),"encodeEntities"),U=(0,n.K2)((function(t){return t.replace(/\ufb02\xb0\xb0/g,"&#").replace(/\ufb02\xb0/g,"&").replace(/\xb6\xdf/g,";")}),"decodeEntities"),Y=(0,n.K2)(((t,e,{counter:r=0,prefix:n,suffix:i})=>`${n?`${n}_`:""}${t}_${e}_${r}${i?`_${i}`:""}`),"getEdgeId");function V(t){return t??null}(0,n.K2)(V,"handleUndefinedAttr")},1282:(t,e,r)=>{"use strict";r.d(e,{DA:()=>k,IU:()=>N,U:()=>E,U7:()=>we,U_:()=>ve,Zk:()=>h,aP:()=>be,gh:()=>_e,lC:()=>d,on:()=>Ce});var n=r(64532),i=r(33115),a=r(10483),o=r(8159),s=r(10009),l=r(20007),c=r(29893),h=(0,s.K2)((async(t,e,r)=>{let n;const i=e.useHtmlLabels||(0,s._3)((0,s.D7)()?.htmlLabels);n=r||"node default";const c=t.insert("g").attr("class",n).attr("id",e.domId||e.id),h=c.insert("g").attr("class","label").attr("style",(0,o.KL)(e.labelStyle));let u;u=void 0===e.label?"":"string"==typeof e.label?e.label:e.label[0];const d=await(0,a.GZ)(h,(0,s.jZ)((0,o.Sm)(u),(0,s.D7)()),{useHtmlLabels:i,width:e.width||(0,s.D7)().flowchart?.wrappingWidth,cssClasses:"markdown-node-label",style:e.labelStyle,addSvgBackground:!!e.icon||!!e.img});let p=d.getBBox();const f=(e?.padding??0)/2;if(i){const t=d.children[0],e=(0,l.Ltv)(d),r=t.getElementsByTagName("img");if(r){const t=""===u.replace(/<img[^>]*>/g,"").trim();await Promise.all([...r].map((e=>new Promise((r=>{function n(){if(e.style.display="flex",e.style.flexDirection="column",t){const t=(0,s.D7)().fontSize?(0,s.D7)().fontSize:window.getComputedStyle(document.body).fontSize,r=5,[n=s.UI.fontSize]=(0,o.I5)(t),i=n*r+"px";e.style.minWidth=i,e.style.maxWidth=i}else e.style.width="100%";r(e)}(0,s.K2)(n,"setupImage"),setTimeout((()=>{e.complete&&n()})),e.addEventListener("error",n),e.addEventListener("load",n)})))))}p=t.getBoundingClientRect(),e.attr("width",p.width),e.attr("height",p.height)}return i?h.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"):h.attr("transform","translate(0, "+-p.height/2+")"),e.centerLabel&&h.attr("transform","translate("+-p.width/2+", "+-p.height/2+")"),h.insert("rect",":first-child"),{shapeSvg:c,bbox:p,halfPadding:f,label:h}}),"labelHelper"),u=(0,s.K2)((async(t,e,r)=>{const n=r.useHtmlLabels||(0,s._3)((0,s.D7)()?.flowchart?.htmlLabels),i=t.insert("g").attr("class","label").attr("style",r.labelStyle||""),c=await(0,a.GZ)(i,(0,s.jZ)((0,o.Sm)(e),(0,s.D7)()),{useHtmlLabels:n,width:r.width||(0,s.D7)()?.flowchart?.wrappingWidth,style:r.labelStyle,addSvgBackground:!!r.icon||!!r.img});let h=c.getBBox();const u=r.padding/2;if((0,s._3)((0,s.D7)()?.flowchart?.htmlLabels)){const t=c.children[0],e=(0,l.Ltv)(c);h=t.getBoundingClientRect(),e.attr("width",h.width),e.attr("height",h.height)}return n?i.attr("transform","translate("+-h.width/2+", "+-h.height/2+")"):i.attr("transform","translate(0, "+-h.height/2+")"),r.centerLabel&&i.attr("transform","translate("+-h.width/2+", "+-h.height/2+")"),i.insert("rect",":first-child"),{shapeSvg:t,bbox:h,halfPadding:u,label:i}}),"insertLabel"),d=(0,s.K2)(((t,e)=>{const r=e.node().getBBox();t.width=r.width,t.height=r.height}),"updateNodeBounds"),p=(0,s.K2)(((t,e)=>("handDrawn"===t.look?"rough-node":"node")+" "+t.cssClasses+" "+(e||"")),"getNodeClasses");function f(t){const e=t.map(((t,e)=>`${0===e?"M":"L"}${t.x},${t.y}`));return e.push("Z"),e.join(" ")}function g(t,e,r,n,i,a){const o=[],s=r-t,l=n-e,c=s/a,h=2*Math.PI/c,u=e+l/2;for(let d=0;d<=50;d++){const e=t+d/50*s,r=u+i*Math.sin(h*(e-t));o.push({x:e,y:r})}return o}function m(t,e,r,n,i,a){const o=[],s=i*Math.PI/180,l=(a*Math.PI/180-s)/(n-1);for(let c=0;c<n;c++){const n=s+c*l,i=t+r*Math.cos(n),a=e+r*Math.sin(n);o.push({x:-i,y:-a})}return o}(0,s.K2)(f,"createPathFromPoints"),(0,s.K2)(g,"generateFullSineWavePoints"),(0,s.K2)(m,"generateCirclePoints");var y=(0,s.K2)(((t,e)=>{var r,n,i=t.x,a=t.y,o=e.x-i,s=e.y-a,l=t.width/2,c=t.height/2;return Math.abs(s)*l>Math.abs(o)*c?(s<0&&(c=-c),r=0===s?0:c*o/s,n=c):(o<0&&(l=-l),r=l,n=0===o?0:l*s/o),{x:i+r,y:a+n}}),"intersectRect");function x(t,e){e&&t.attr("style",e)}async function b(t){const e=(0,l.Ltv)(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),r=e.append("xhtml:div");let n=t.label;t.label&&(0,s.Wi)(t.label)&&(n=await(0,s.VJ)(t.label.replace(s.Y2.lineBreakRegex,"\n"),(0,s.D7)()));const i=t.isNode?"nodeLabel":"edgeLabel";return r.html('<span class="'+i+'" '+(t.labelStyle?'style="'+t.labelStyle+'"':"")+">"+n+"</span>"),x(r,t.labelStyle),r.style("display","inline-block"),r.style("padding-right","1px"),r.style("white-space","nowrap"),r.attr("xmlns","http://www.w3.org/1999/xhtml"),e.node()}(0,s.K2)(x,"applyStyle"),(0,s.K2)(b,"addHtmlLabel");var k=(0,s.K2)((async(t,e,r,n)=>{let i=t||"";if("object"==typeof i&&(i=i[0]),(0,s._3)((0,s.D7)().flowchart.htmlLabels)){i=i.replace(/\\n|\n/g,"<br />"),s.Rm.info("vertexText"+i);const t={isNode:n,label:(0,o.Sm)(i).replace(/fa[blrs]?:fa-[\w-]+/g,(t=>`<i class='${t.replace(":"," ")}'></i>`)),labelStyle:e?e.replace("fill:","color:"):e};return await b(t)}{const t=document.createElementNS("http://www.w3.org/2000/svg","text");t.setAttribute("style",e.replace("color:","fill:"));let n=[];n="string"==typeof i?i.split(/\\n|\n|<br\s*\/?>/gi):Array.isArray(i)?i:[];for(const e of n){const n=document.createElementNS("http://www.w3.org/2000/svg","tspan");n.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),n.setAttribute("dy","1em"),n.setAttribute("x","0"),r?n.setAttribute("class","title-row"):n.setAttribute("class","row"),n.textContent=e.trim(),t.appendChild(n)}return t}}),"createLabel"),C=(0,s.K2)(((t,e,r,n,i)=>["M",t+i,e,"H",t+r-i,"A",i,i,0,0,1,t+r,e+i,"V",e+n-i,"A",i,i,0,0,1,t+r-i,e+n,"H",t+i,"A",i,i,0,0,1,t,e+n-i,"V",e+i,"A",i,i,0,0,1,t+i,e,"Z"].join(" ")),"createRoundedRectPathD"),w=(0,s.K2)((t=>{const{handDrawnSeed:e}=(0,s.D7)();return{fill:t,hachureAngle:120,hachureGap:4,fillWeight:2,roughness:.7,stroke:t,seed:e}}),"solidStateFill"),_=(0,s.K2)((t=>{const e=v([...t.cssCompiledStyles||[],...t.cssStyles||[]]);return{stylesMap:e,stylesArray:[...e]}}),"compileStyles"),v=(0,s.K2)((t=>{const e=new Map;return t.forEach((t=>{const[r,n]=t.split(":");e.set(r.trim(),n?.trim())})),e}),"styles2Map"),S=(0,s.K2)((t=>{const{stylesArray:e}=_(t),r=[],n=[],i=[],a=[];return e.forEach((t=>{const e=t[0];"color"===e||"font-size"===e||"font-family"===e||"font-weight"===e||"font-style"===e||"text-decoration"===e||"text-align"===e||"text-transform"===e||"line-height"===e||"letter-spacing"===e||"word-spacing"===e||"text-shadow"===e||"text-overflow"===e||"white-space"===e||"word-wrap"===e||"word-break"===e||"overflow-wrap"===e||"hyphens"===e?r.push(t.join(":")+" !important"):(n.push(t.join(":")+" !important"),e.includes("stroke")&&i.push(t.join(":")+" !important"),"fill"===e&&a.push(t.join(":")+" !important"))})),{labelStyles:r.join(";"),nodeStyles:n.join(";"),stylesArray:e,borderStyles:i,backgroundStyles:a}}),"styles2String"),A=(0,s.K2)(((t,e)=>{const{themeVariables:r,handDrawnSeed:n}=(0,s.D7)(),{nodeBorder:i,mainBkg:a}=r,{stylesMap:o}=_(t);return Object.assign({roughness:.7,fill:o.get("fill")||a,fillStyle:"hachure",fillWeight:4,hachureGap:5.2,stroke:o.get("stroke")||i,seed:n,strokeWidth:o.get("stroke-width")?.replace("px","")||1.3,fillLineDash:[0,0]},e)}),"userNodeOverrides"),T=(0,s.K2)((async(t,e)=>{s.Rm.info("Creating subgraph rect for ",e.id,e);const r=(0,s.D7)(),{themeVariables:n,handDrawnSeed:o}=r,{clusterBkg:h,clusterBorder:u}=n,{labelStyles:d,nodeStyles:p,borderStyles:f,backgroundStyles:g}=S(e),m=t.insert("g").attr("class","cluster "+e.cssClasses).attr("id",e.id).attr("data-look",e.look),x=(0,s._3)(r.flowchart.htmlLabels),b=m.insert("g").attr("class","cluster-label "),k=await(0,a.GZ)(b,e.label,{style:e.labelStyle,useHtmlLabels:x,isNode:!0});let w=k.getBBox();if((0,s._3)(r.flowchart.htmlLabels)){const t=k.children[0],e=(0,l.Ltv)(k);w=t.getBoundingClientRect(),e.attr("width",w.width),e.attr("height",w.height)}const _=e.width<=w.width+e.padding?w.width+e.padding:e.width;e.width<=w.width+e.padding?e.diff=(_-e.width)/2-e.padding:e.diff=-e.padding;const v=e.height,T=e.x-_/2,M=e.y-v/2;let B;if(s.Rm.trace("Data ",e,JSON.stringify(e)),"handDrawn"===e.look){const t=c.A.svg(m),r=A(e,{roughness:.7,fill:h,stroke:u,fillWeight:3,seed:o}),n=t.path(C(T,M,_,v,0),r);B=m.insert((()=>(s.Rm.debug("Rough node insert CXC",n),n)),":first-child"),B.select("path:nth-child(2)").attr("style",f.join(";")),B.select("path").attr("style",g.join(";").replace("fill","stroke"))}else B=m.insert("rect",":first-child"),B.attr("style",p).attr("rx",e.rx).attr("ry",e.ry).attr("x",T).attr("y",M).attr("width",_).attr("height",v);const{subGraphTitleTopMargin:L}=(0,i.O)(r);if(b.attr("transform",`translate(${e.x-w.width/2}, ${e.y-e.height/2+L})`),d){const t=b.select("span");t&&t.attr("style",d)}const F=B.node().getBBox();return e.offsetX=0,e.width=F.width,e.height=F.height,e.offsetY=w.height-e.padding/2,e.intersect=function(t){return y(e,t)},{cluster:m,labelBBox:w}}),"rect"),M=(0,s.K2)(((t,e)=>{const r=t.insert("g").attr("class","note-cluster").attr("id",e.id),n=r.insert("rect",":first-child"),i=0*e.padding,a=i/2;n.attr("rx",e.rx).attr("ry",e.ry).attr("x",e.x-e.width/2-a).attr("y",e.y-e.height/2-a).attr("width",e.width+i).attr("height",e.height+i).attr("fill","none");const o=n.node().getBBox();return e.width=o.width,e.height=o.height,e.intersect=function(t){return y(e,t)},{cluster:r,labelBBox:{width:0,height:0}}}),"noteGroup"),B=(0,s.K2)((async(t,e)=>{const r=(0,s.D7)(),{themeVariables:n,handDrawnSeed:i}=r,{altBackground:a,compositeBackground:o,compositeTitleBackground:h,nodeBorder:u}=n,d=t.insert("g").attr("class",e.cssClasses).attr("id",e.id).attr("data-id",e.id).attr("data-look",e.look),p=d.insert("g",":first-child"),f=d.insert("g").attr("class","cluster-label");let g=d.append("rect");const m=f.node().appendChild(await k(e.label,e.labelStyle,void 0,!0));let x=m.getBBox();if((0,s._3)(r.flowchart.htmlLabels)){const t=m.children[0],e=(0,l.Ltv)(m);x=t.getBoundingClientRect(),e.attr("width",x.width),e.attr("height",x.height)}const b=0*e.padding,w=b/2,_=(e.width<=x.width+e.padding?x.width+e.padding:e.width)+b;e.width<=x.width+e.padding?e.diff=(_-e.width)/2-e.padding:e.diff=-e.padding;const v=e.height+b,S=e.height+b-x.height-6,A=e.x-_/2,T=e.y-v/2;e.width=_;const M=e.y-e.height/2-w+x.height+2;let B;if("handDrawn"===e.look){const t=e.cssClasses.includes("statediagram-cluster-alt"),r=c.A.svg(d),n=e.rx||e.ry?r.path(C(A,T,_,v,10),{roughness:.7,fill:h,fillStyle:"solid",stroke:u,seed:i}):r.rectangle(A,T,_,v,{seed:i});B=d.insert((()=>n),":first-child");const s=r.rectangle(A,M,_,S,{fill:t?a:o,fillStyle:t?"hachure":"solid",stroke:u,seed:i});B=d.insert((()=>n),":first-child"),g=d.insert((()=>s))}else{B=p.insert("rect",":first-child");const t="outer";B.attr("class",t).attr("x",A).attr("y",T).attr("width",_).attr("height",v).attr("data-look",e.look),g.attr("class","inner").attr("x",A).attr("y",M).attr("width",_).attr("height",S)}f.attr("transform",`translate(${e.x-x.width/2}, ${T+1-((0,s._3)(r.flowchart.htmlLabels)?0:3)})`);const L=B.node().getBBox();return e.height=L.height,e.offsetX=0,e.offsetY=x.height-e.padding/2,e.labelBBox=x,e.intersect=function(t){return y(e,t)},{cluster:d,labelBBox:x}}),"roundedWithTitle"),L=(0,s.K2)((async(t,e)=>{s.Rm.info("Creating subgraph rect for ",e.id,e);const r=(0,s.D7)(),{themeVariables:n,handDrawnSeed:o}=r,{clusterBkg:h,clusterBorder:u}=n,{labelStyles:d,nodeStyles:p,borderStyles:f,backgroundStyles:g}=S(e),m=t.insert("g").attr("class","cluster "+e.cssClasses).attr("id",e.id).attr("data-look",e.look),x=(0,s._3)(r.flowchart.htmlLabels),b=m.insert("g").attr("class","cluster-label "),k=await(0,a.GZ)(b,e.label,{style:e.labelStyle,useHtmlLabels:x,isNode:!0,width:e.width});let w=k.getBBox();if((0,s._3)(r.flowchart.htmlLabels)){const t=k.children[0],e=(0,l.Ltv)(k);w=t.getBoundingClientRect(),e.attr("width",w.width),e.attr("height",w.height)}const _=e.width<=w.width+e.padding?w.width+e.padding:e.width;e.width<=w.width+e.padding?e.diff=(_-e.width)/2-e.padding:e.diff=-e.padding;const v=e.height,T=e.x-_/2,M=e.y-v/2;let B;if(s.Rm.trace("Data ",e,JSON.stringify(e)),"handDrawn"===e.look){const t=c.A.svg(m),r=A(e,{roughness:.7,fill:h,stroke:u,fillWeight:4,seed:o}),n=t.path(C(T,M,_,v,e.rx),r);B=m.insert((()=>(s.Rm.debug("Rough node insert CXC",n),n)),":first-child"),B.select("path:nth-child(2)").attr("style",f.join(";")),B.select("path").attr("style",g.join(";").replace("fill","stroke"))}else B=m.insert("rect",":first-child"),B.attr("style",p).attr("rx",e.rx).attr("ry",e.ry).attr("x",T).attr("y",M).attr("width",_).attr("height",v);const{subGraphTitleTopMargin:L}=(0,i.O)(r);if(b.attr("transform",`translate(${e.x-w.width/2}, ${e.y-e.height/2+L})`),d){const t=b.select("span");t&&t.attr("style",d)}const F=B.node().getBBox();return e.offsetX=0,e.width=F.width,e.height=F.height,e.offsetY=w.height-e.padding/2,e.intersect=function(t){return y(e,t)},{cluster:m,labelBBox:w}}),"kanbanSection"),F={rect:T,squareRect:T,roundedWithTitle:B,noteGroup:M,divider:(0,s.K2)(((t,e)=>{const r=(0,s.D7)(),{themeVariables:n,handDrawnSeed:i}=r,{nodeBorder:a}=n,o=t.insert("g").attr("class",e.cssClasses).attr("id",e.id).attr("data-look",e.look),l=o.insert("g",":first-child"),h=0*e.padding,u=e.width+h;e.diff=-e.padding;const d=e.height+h,p=e.x-u/2,f=e.y-d/2;let g;if(e.width=u,"handDrawn"===e.look){const t=c.A.svg(o).rectangle(p,f,u,d,{fill:"lightgrey",roughness:.5,strokeLineDash:[5],stroke:a,seed:i});g=o.insert((()=>t),":first-child")}else{g=l.insert("rect",":first-child");const t="divider";g.attr("class",t).attr("x",p).attr("y",f).attr("width",u).attr("height",d).attr("data-look",e.look)}const m=g.node().getBBox();return e.height=m.height,e.offsetX=0,e.offsetY=0,e.intersect=function(t){return y(e,t)},{cluster:o,labelBBox:{}}}),"divider"),kanbanSection:L},$=new Map,E=(0,s.K2)((async(t,e)=>{const r=e.shape||"rect",n=await F[r](t,e);return $.set(e.id,n),n}),"insertCluster"),N=(0,s.K2)((()=>{$=new Map}),"clear");function D(t,e){return t.intersect(e)}(0,s.K2)(D,"intersectNode");var j=D;function I(t,e,r,n){var i=t.x,a=t.y,o=i-n.x,s=a-n.y,l=Math.sqrt(e*e*s*s+r*r*o*o),c=Math.abs(e*r*o/l);n.x<i&&(c=-c);var h=Math.abs(e*r*s/l);return n.y<a&&(h=-h),{x:i+c,y:a+h}}(0,s.K2)(I,"intersectEllipse");var O=I;function R(t,e,r){return O(t,e,e,r)}(0,s.K2)(R,"intersectCircle");var P=R;function z(t,e,r,n){var i,a,o,s,l,c,h,u,d,p,f,g,m;if(i=e.y-t.y,o=t.x-e.x,l=e.x*t.y-t.x*e.y,d=i*r.x+o*r.y+l,p=i*n.x+o*n.y+l,!(0!==d&&0!==p&&K(d,p)||(a=n.y-r.y,s=r.x-n.x,c=n.x*r.y-r.x*n.y,h=a*t.x+s*t.y+c,u=a*e.x+s*e.y+c,0!==h&&0!==u&&K(h,u)||0==(f=i*s-a*o))))return g=Math.abs(f/2),{x:(m=o*c-s*l)<0?(m-g)/f:(m+g)/f,y:(m=a*l-i*c)<0?(m-g)/f:(m+g)/f}}function K(t,e){return t*e>0}(0,s.K2)(z,"intersectLine"),(0,s.K2)(K,"sameSign");var q=z;function W(t,e,r){let n=t.x,i=t.y,a=[],o=Number.POSITIVE_INFINITY,s=Number.POSITIVE_INFINITY;"function"==typeof e.forEach?e.forEach((function(t){o=Math.min(o,t.x),s=Math.min(s,t.y)})):(o=Math.min(o,e.x),s=Math.min(s,e.y));let l=n-t.width/2-o,c=i-t.height/2-s;for(let h=0;h<e.length;h++){let n=e[h],i=e[h<e.length-1?h+1:0],o=q(t,r,{x:l+n.x,y:c+n.y},{x:l+i.x,y:c+i.y});o&&a.push(o)}return a.length?(a.length>1&&a.sort((function(t,e){let n=t.x-r.x,i=t.y-r.y,a=Math.sqrt(n*n+i*i),o=e.x-r.x,s=e.y-r.y,l=Math.sqrt(o*o+s*s);return a<l?-1:a===l?0:1})),a[0]):t}(0,s.K2)(W,"intersectPolygon");var H={node:j,circle:P,ellipse:O,polygon:W,rect:y};function U(t,e){const{labelStyles:r}=S(e);e.labelStyle=r;const n=p(e);let i=n;n||(i="anchor");const a=t.insert("g").attr("class",i).attr("id",e.domId||e.id),{cssStyles:l}=e,h=c.A.svg(a),u=A(e,{fill:"black",stroke:"none",fillStyle:"solid"});"handDrawn"!==e.look&&(u.roughness=0);const f=h.circle(0,0,2,u),g=a.insert((()=>f),":first-child");return g.attr("class","anchor").attr("style",(0,o.KL)(l)),d(e,g),e.intersect=function(t){return s.Rm.info("Circle intersect",e,1,t),H.circle(e,1,t)},a}function Y(t,e,r,n,i,a,o){const s=(t+r)/2,l=(e+n)/2,c=Math.atan2(n-e,r-t),h=(r-t)/2/i,u=(n-e)/2/a,d=Math.sqrt(h**2+u**2);if(d>1)throw new Error("The given radii are too small to create an arc between the points.");const p=Math.sqrt(1-d**2),f=s+p*a*Math.sin(c)*(o?-1:1),g=l-p*i*Math.cos(c)*(o?-1:1),m=Math.atan2((e-g)/a,(t-f)/i);let y=Math.atan2((n-g)/a,(r-f)/i)-m;o&&y<0&&(y+=2*Math.PI),!o&&y>0&&(y-=2*Math.PI);const x=[];for(let b=0;b<20;b++){const t=m+b/19*y,e=f+i*Math.cos(t),r=g+a*Math.sin(t);x.push({x:e,y:r})}return x}async function V(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=a.width+e.padding+20,s=a.height+e.padding,l=s/2,u=l/(2.5+s/50),{cssStyles:g}=e,m=[{x:o/2,y:-s/2},{x:-o/2,y:-s/2},...Y(-o/2,-s/2,-o/2,s/2,u,l,!1),{x:o/2,y:s/2},...Y(o/2,s/2,o/2,-s/2,u,l,!0)],y=c.A.svg(i),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=f(m),k=y.path(b,x),C=i.insert((()=>k),":first-child");return C.attr("class","basic label-container"),g&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",g),n&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",n),C.attr("transform",`translate(${u/2}, 0)`),d(e,C),e.intersect=function(t){return H.polygon(e,m,t)},i}function G(t,e,r,n){return t.insert("polygon",":first-child").attr("points",n.map((function(t){return t.x+","+t.y})).join(" ")).attr("class","label-container").attr("transform","translate("+-e/2+","+r/2+")")}async function Z(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=a.height+e.padding,s=a.width+e.padding+12,l=-o,u=[{x:12,y:l},{x:s,y:l},{x:s,y:0},{x:0,y:0},{x:0,y:l+12},{x:12,y:l}];let g;const{cssStyles:m}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=f(u),a=t.path(n,r);g=i.insert((()=>a),":first-child").attr("transform",`translate(${-s/2}, ${o/2})`),m&&g.attr("style",m)}else g=G(i,s,o,u);return n&&g.attr("style",n),d(e,g),e.intersect=function(t){return H.polygon(e,u,t)},i}function X(t,e){const{nodeStyles:r}=S(e);e.label="";const n=t.insert("g").attr("class",p(e)).attr("id",e.domId??e.id),{cssStyles:i}=e,a=Math.max(28,e.width??0),o=[{x:0,y:a/2},{x:a/2,y:0},{x:0,y:-a/2},{x:-a/2,y:0}],s=c.A.svg(n),l=A(e,{});"handDrawn"!==e.look&&(l.roughness=0,l.fillStyle="solid");const h=f(o),u=s.path(h,l),d=n.insert((()=>u),":first-child");return i&&"handDrawn"!==e.look&&d.selectAll("path").attr("style",i),r&&"handDrawn"!==e.look&&d.selectAll("path").attr("style",r),e.width=28,e.height=28,e.intersect=function(t){return H.polygon(e,o,t)},n}async function Q(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,halfPadding:l}=await h(t,e,p(e)),u=a.width/2+l;let f;const{cssStyles:g}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=t.circle(0,0,2*u,r);f=i.insert((()=>n),":first-child"),f.attr("class","basic label-container").attr("style",(0,o.KL)(g))}else f=i.insert("circle",":first-child").attr("class","basic label-container").attr("style",n).attr("r",u).attr("cx",0).attr("cy",0);return d(e,f),e.intersect=function(t){return s.Rm.info("Circle intersect",e,u,t),H.circle(e,u,t)},i}function J(t){const e=Math.cos(Math.PI/4),r=Math.sin(Math.PI/4),n=2*t;return`M ${-n/2*e},${n/2*r} L ${n/2*e},${-n/2*r}\n M ${n/2*e},${n/2*r} L ${-n/2*e},${-n/2*r}`}function tt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r,e.label="";const i=t.insert("g").attr("class",p(e)).attr("id",e.domId??e.id),a=Math.max(30,e?.width??0),{cssStyles:o}=e,l=c.A.svg(i),h=A(e,{});"handDrawn"!==e.look&&(h.roughness=0,h.fillStyle="solid");const u=l.circle(0,0,2*a,h),f=J(a),g=l.path(f,h),m=i.insert((()=>u),":first-child");return m.insert((()=>g)),o&&"handDrawn"!==e.look&&m.selectAll("path").attr("style",o),n&&"handDrawn"!==e.look&&m.selectAll("path").attr("style",n),d(e,m),e.intersect=function(t){s.Rm.info("crossedCircle intersect",e,{radius:a,point:t});return H.circle(e,a,t)},i}function et(t,e,r,n=100,i=0,a=180){const o=[],s=i*Math.PI/180,l=(a*Math.PI/180-s)/(n-1);for(let c=0;c<n;c++){const n=s+c*l,i=t+r*Math.cos(n),a=e+r*Math.sin(n);o.push({x:-i,y:-a})}return o}async function rt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=a.width+(e.padding??0),l=a.height+(e.padding??0),u=Math.max(5,.1*l),{cssStyles:g}=e,m=[...et(s/2,-l/2,u,30,-90,0),{x:-s/2-u,y:u},...et(s/2+2*u,-u,u,20,-180,-270),...et(s/2+2*u,u,u,20,-90,-180),{x:-s/2-u,y:-l/2},...et(s/2,l/2,u,20,0,90)],y=[{x:s/2,y:-l/2-u},{x:-s/2,y:-l/2-u},...et(s/2,-l/2,u,20,-90,0),{x:-s/2-u,y:-u},...et(s/2+.1*s,-u,u,20,-180,-270),...et(s/2+.1*s,u,u,20,-90,-180),{x:-s/2-u,y:l/2},...et(s/2,l/2,u,20,0,90),{x:-s/2,y:l/2+u},{x:s/2,y:l/2+u}],x=c.A.svg(i),b=A(e,{fill:"none"});"handDrawn"!==e.look&&(b.roughness=0,b.fillStyle="solid");const k=f(m).replace("Z",""),C=x.path(k,b),w=f(y),_=x.path(w,{...b}),v=i.insert("g",":first-child");return v.insert((()=>_),":first-child").attr("stroke-opacity",0),v.insert((()=>C),":first-child"),v.attr("class","text"),g&&"handDrawn"!==e.look&&v.selectAll("path").attr("style",g),n&&"handDrawn"!==e.look&&v.selectAll("path").attr("style",n),v.attr("transform",`translate(${u}, 0)`),o.attr("transform",`translate(${-s/2+u-(a.x-(a.left??0))},${-l/2+(e.padding??0)/2-(a.y-(a.top??0))})`),d(e,v),e.intersect=function(t){return H.polygon(e,y,t)},i}function nt(t,e,r,n=100,i=0,a=180){const o=[],s=i*Math.PI/180,l=(a*Math.PI/180-s)/(n-1);for(let c=0;c<n;c++){const n=s+c*l,i=t+r*Math.cos(n),a=e+r*Math.sin(n);o.push({x:i,y:a})}return o}async function it(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=a.width+(e.padding??0),l=a.height+(e.padding??0),u=Math.max(5,.1*l),{cssStyles:g}=e,m=[...nt(s/2,-l/2,u,20,-90,0),{x:s/2+u,y:-u},...nt(s/2+2*u,-u,u,20,-180,-270),...nt(s/2+2*u,u,u,20,-90,-180),{x:s/2+u,y:l/2},...nt(s/2,l/2,u,20,0,90)],y=[{x:-s/2,y:-l/2-u},{x:s/2,y:-l/2-u},...nt(s/2,-l/2,u,20,-90,0),{x:s/2+u,y:-u},...nt(s/2+2*u,-u,u,20,-180,-270),...nt(s/2+2*u,u,u,20,-90,-180),{x:s/2+u,y:l/2},...nt(s/2,l/2,u,20,0,90),{x:s/2,y:l/2+u},{x:-s/2,y:l/2+u}],x=c.A.svg(i),b=A(e,{fill:"none"});"handDrawn"!==e.look&&(b.roughness=0,b.fillStyle="solid");const k=f(m).replace("Z",""),C=x.path(k,b),w=f(y),_=x.path(w,{...b}),v=i.insert("g",":first-child");return v.insert((()=>_),":first-child").attr("stroke-opacity",0),v.insert((()=>C),":first-child"),v.attr("class","text"),g&&"handDrawn"!==e.look&&v.selectAll("path").attr("style",g),n&&"handDrawn"!==e.look&&v.selectAll("path").attr("style",n),v.attr("transform",`translate(${-u}, 0)`),o.attr("transform",`translate(${-s/2+(e.padding??0)/2-(a.x-(a.left??0))},${-l/2+(e.padding??0)/2-(a.y-(a.top??0))})`),d(e,v),e.intersect=function(t){return H.polygon(e,y,t)},i}function at(t,e,r,n=100,i=0,a=180){const o=[],s=i*Math.PI/180,l=(a*Math.PI/180-s)/(n-1);for(let c=0;c<n;c++){const n=s+c*l,i=t+r*Math.cos(n),a=e+r*Math.sin(n);o.push({x:-i,y:-a})}return o}async function ot(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=a.width+(e.padding??0),l=a.height+(e.padding??0),u=Math.max(5,.1*l),{cssStyles:g}=e,m=[...at(s/2,-l/2,u,30,-90,0),{x:-s/2-u,y:u},...at(s/2+2*u,-u,u,20,-180,-270),...at(s/2+2*u,u,u,20,-90,-180),{x:-s/2-u,y:-l/2},...at(s/2,l/2,u,20,0,90)],y=[...at(-s/2+u+u/2,-l/2,u,20,-90,-180),{x:s/2-u/2,y:u},...at(-s/2-u/2,-u,u,20,0,90),...at(-s/2-u/2,u,u,20,-90,0),{x:s/2-u/2,y:-u},...at(-s/2+u+u/2,l/2,u,30,-180,-270)],x=[{x:s/2,y:-l/2-u},{x:-s/2,y:-l/2-u},...at(s/2,-l/2,u,20,-90,0),{x:-s/2-u,y:-u},...at(s/2+2*u,-u,u,20,-180,-270),...at(s/2+2*u,u,u,20,-90,-180),{x:-s/2-u,y:l/2},...at(s/2,l/2,u,20,0,90),{x:-s/2,y:l/2+u},{x:s/2-u-u/2,y:l/2+u},...at(-s/2+u+u/2,-l/2,u,20,-90,-180),{x:s/2-u/2,y:u},...at(-s/2-u/2,-u,u,20,0,90),...at(-s/2-u/2,u,u,20,-90,0),{x:s/2-u/2,y:-u},...at(-s/2+u+u/2,l/2,u,30,-180,-270)],b=c.A.svg(i),k=A(e,{fill:"none"});"handDrawn"!==e.look&&(k.roughness=0,k.fillStyle="solid");const C=f(m).replace("Z",""),w=b.path(C,k),_=f(y).replace("Z",""),v=b.path(_,k),T=f(x),M=b.path(T,{...k}),B=i.insert("g",":first-child");return B.insert((()=>M),":first-child").attr("stroke-opacity",0),B.insert((()=>w),":first-child"),B.insert((()=>v),":first-child"),B.attr("class","text"),g&&"handDrawn"!==e.look&&B.selectAll("path").attr("style",g),n&&"handDrawn"!==e.look&&B.selectAll("path").attr("style",n),B.attr("transform",`translate(${u-u/4}, 0)`),o.attr("transform",`translate(${-s/2+(e.padding??0)/2-(a.x-(a.left??0))},${-l/2+(e.padding??0)/2-(a.y-(a.top??0))})`),d(e,B),e.intersect=function(t){return H.polygon(e,x,t)},i}async function st(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(80,1.25*(a.width+2*(e.padding??0)),e?.width??0),s=Math.max(20,a.height+2*(e.padding??0),e?.height??0),l=s/2,{cssStyles:u}=e,g=c.A.svg(i),y=A(e,{});"handDrawn"!==e.look&&(y.roughness=0,y.fillStyle="solid");const x=o-l,b=s/4,k=[{x:x,y:0},{x:b,y:0},{x:0,y:s/2},{x:b,y:s},{x:x,y:s},...m(-x,-s/2,l,50,270,90)],C=f(k),w=g.path(C,y),_=i.insert((()=>w),":first-child");return _.attr("class","basic label-container"),u&&"handDrawn"!==e.look&&_.selectChildren("path").attr("style",u),n&&"handDrawn"!==e.look&&_.selectChildren("path").attr("style",n),_.attr("transform",`translate(${-o/2}, ${-s/2})`),d(e,_),e.intersect=function(t){return H.polygon(e,k,t)},i}(0,s.K2)(U,"anchor"),(0,s.K2)(Y,"generateArcPoints"),(0,s.K2)(V,"bowTieRect"),(0,s.K2)(G,"insertPolygonShape"),(0,s.K2)(Z,"card"),(0,s.K2)(X,"choice"),(0,s.K2)(Q,"circle"),(0,s.K2)(J,"createLine"),(0,s.K2)(tt,"crossedCircle"),(0,s.K2)(et,"generateCirclePoints"),(0,s.K2)(rt,"curlyBraceLeft"),(0,s.K2)(nt,"generateCirclePoints"),(0,s.K2)(it,"curlyBraceRight"),(0,s.K2)(at,"generateCirclePoints"),(0,s.K2)(ot,"curlyBraces"),(0,s.K2)(st,"curvedTrapezoid");var lt=(0,s.K2)(((t,e,r,n,i,a)=>[`M${t},${e+a}`,`a${i},${a} 0,0,0 ${r},0`,`a${i},${a} 0,0,0 ${-r},0`,`l0,${n}`,`a${i},${a} 0,0,0 ${r},0`,"l0,"+-n].join(" ")),"createCylinderPathD"),ct=(0,s.K2)(((t,e,r,n,i,a)=>[`M${t},${e+a}`,`M${t+r},${e+a}`,`a${i},${a} 0,0,0 ${-r},0`,`l0,${n}`,`a${i},${a} 0,0,0 ${r},0`,"l0,"+-n].join(" ")),"createOuterCylinderPathD"),ht=(0,s.K2)(((t,e,r,n,i,a)=>[`M${t-r/2},${-n/2}`,`a${i},${a} 0,0,0 ${r},0`].join(" ")),"createInnerCylinderPathD");async function ut(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:s}=await h(t,e,p(e)),l=Math.max(a.width+e.padding,e.width??0),u=l/2,f=u/(2.5+l/50),g=Math.max(a.height+f+e.padding,e.height??0);let m;const{cssStyles:y}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=ct(0,0,l,g,u,f),n=ht(0,f,l,g,u,f),a=t.path(r,A(e,{})),o=t.path(n,A(e,{fill:"none"}));m=i.insert((()=>o),":first-child"),m=i.insert((()=>a),":first-child"),m.attr("class","basic label-container"),y&&m.attr("style",y)}else{const t=lt(0,0,l,g,u,f);m=i.insert("path",":first-child").attr("d",t).attr("class","basic label-container").attr("style",(0,o.KL)(y)).attr("style",n)}return m.attr("label-offset-y",f),m.attr("transform",`translate(${-l/2}, ${-(g/2+f)})`),d(e,m),s.attr("transform",`translate(${-a.width/2-(a.x-(a.left??0))}, ${-a.height/2+(e.padding??0)/1.5-(a.y-(a.top??0))})`),e.intersect=function(t){const r=H.rect(e,t),n=r.x-(e.x??0);if(0!=u&&(Math.abs(n)<(e.width??0)/2||Math.abs(n)==(e.width??0)/2&&Math.abs(r.y-(e.y??0))>(e.height??0)/2-f)){let i=f*f*(1-n*n/(u*u));i>0&&(i=Math.sqrt(i)),i=f-i,t.y-(e.y??0)>0&&(i=-i),r.y+=i}return r},i}async function dt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=a.width+e.padding,l=a.height+e.padding,u=.2*l,f=-s/2,g=-l/2-u/2,{cssStyles:m}=e,y=c.A.svg(i),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=[{x:f,y:g+u},{x:-f,y:g+u},{x:-f,y:-g},{x:f,y:-g},{x:f,y:g},{x:-f,y:g},{x:-f,y:g+u}],k=y.polygon(b.map((t=>[t.x,t.y])),x),C=i.insert((()=>k),":first-child");return C.attr("class","basic label-container"),m&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",m),n&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",n),o.attr("transform",`translate(${f+(e.padding??0)/2-(a.x-(a.left??0))}, ${g+u+(e.padding??0)/2-(a.y-(a.top??0))})`),d(e,C),e.intersect=function(t){return H.rect(e,t)},i}async function pt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,halfPadding:l}=await h(t,e,p(e)),u=a.width/2+l+5,f=a.width/2+l;let g;const{cssStyles:m}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{roughness:.2,strokeWidth:2.5}),n=A(e,{roughness:.2,strokeWidth:1.5}),a=t.circle(0,0,2*u,r),s=t.circle(0,0,2*f,n);g=i.insert("g",":first-child"),g.attr("class",(0,o.KL)(e.cssClasses)).attr("style",(0,o.KL)(m)),g.node()?.appendChild(a),g.node()?.appendChild(s)}else{g=i.insert("g",":first-child");const t=g.insert("circle",":first-child"),e=g.insert("circle");g.attr("class","basic label-container").attr("style",n),t.attr("class","outer-circle").attr("style",n).attr("r",u).attr("cx",0).attr("cy",0),e.attr("class","inner-circle").attr("style",n).attr("r",f).attr("cx",0).attr("cy",0)}return d(e,g),e.intersect=function(t){return s.Rm.info("DoubleCircle intersect",e,u,t),H.circle(e,u,t)},i}function ft(t,e,{config:{themeVariables:r}}){const{labelStyles:n,nodeStyles:i}=S(e);e.label="",e.labelStyle=n;const a=t.insert("g").attr("class",p(e)).attr("id",e.domId??e.id),{cssStyles:o}=e,l=c.A.svg(a),{nodeBorder:h}=r,u=A(e,{fillStyle:"solid"});"handDrawn"!==e.look&&(u.roughness=0);const f=l.circle(0,0,14,u),g=a.insert((()=>f),":first-child");return g.selectAll("path").attr("style",`fill: ${h} !important;`),o&&o.length>0&&"handDrawn"!==e.look&&g.selectAll("path").attr("style",o),i&&"handDrawn"!==e.look&&g.selectAll("path").attr("style",i),d(e,g),e.intersect=function(t){s.Rm.info("filledCircle intersect",e,{radius:7,point:t});return H.circle(e,7,t)},a}async function gt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),l=a.width+(e.padding??0),u=l+a.height,g=l+a.height,m=[{x:0,y:-u},{x:g,y:-u},{x:g/2,y:0}],{cssStyles:y}=e,x=c.A.svg(i),b=A(e,{});"handDrawn"!==e.look&&(b.roughness=0,b.fillStyle="solid");const k=f(m),C=x.path(k,b),w=i.insert((()=>C),":first-child").attr("transform",`translate(${-u/2}, ${u/2})`);return y&&"handDrawn"!==e.look&&w.selectChildren("path").attr("style",y),n&&"handDrawn"!==e.look&&w.selectChildren("path").attr("style",n),e.width=l,e.height=u,d(e,w),o.attr("transform",`translate(${-a.width/2-(a.x-(a.left??0))}, ${-u/2+(e.padding??0)/2+(a.y-(a.top??0))})`),e.intersect=function(t){return s.Rm.info("Triangle intersect",e,m,t),H.polygon(e,m,t)},i}function mt(t,e,{dir:r,config:{state:n,themeVariables:i}}){const{nodeStyles:a}=S(e);e.label="";const o=t.insert("g").attr("class",p(e)).attr("id",e.domId??e.id),{cssStyles:s}=e;let l=Math.max(70,e?.width??0),h=Math.max(10,e?.height??0);"LR"===r&&(l=Math.max(10,e?.width??0),h=Math.max(70,e?.height??0));const u=-1*l/2,f=-1*h/2,g=c.A.svg(o),m=A(e,{stroke:i.lineColor,fill:i.lineColor});"handDrawn"!==e.look&&(m.roughness=0,m.fillStyle="solid");const y=g.rectangle(u,f,l,h,m),x=o.insert((()=>y),":first-child");s&&"handDrawn"!==e.look&&x.selectAll("path").attr("style",s),a&&"handDrawn"!==e.look&&x.selectAll("path").attr("style",a),d(e,x);const b=n?.padding??0;return e.width&&e.height&&(e.width+=b/2||0,e.height+=b/2||0),e.intersect=function(t){return H.rect(e,t)},o}async function yt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(80,a.width+2*(e.padding??0),e?.width??0),l=Math.max(50,a.height+2*(e.padding??0),e?.height??0),u=l/2,{cssStyles:g}=e,y=c.A.svg(i),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=[{x:-o/2,y:-l/2},{x:o/2-u,y:-l/2},...m(-o/2+u,0,u,50,90,270),{x:o/2-u,y:l/2},{x:-o/2,y:l/2}],k=f(b),C=y.path(k,x),w=i.insert((()=>C),":first-child");return w.attr("class","basic label-container"),g&&"handDrawn"!==e.look&&w.selectChildren("path").attr("style",g),n&&"handDrawn"!==e.look&&w.selectChildren("path").attr("style",n),d(e,w),e.intersect=function(t){s.Rm.info("Pill intersect",e,{radius:u,point:t});return H.polygon(e,b,t)},i}(0,s.K2)(ut,"cylinder"),(0,s.K2)(dt,"dividedRectangle"),(0,s.K2)(pt,"doublecircle"),(0,s.K2)(ft,"filledCircle"),(0,s.K2)(gt,"flippedTriangle"),(0,s.K2)(mt,"forkJoin"),(0,s.K2)(yt,"halfRoundedRectangle");var xt=(0,s.K2)(((t,e,r,n,i)=>[`M${t+i},${e}`,`L${t+r-i},${e}`,`L${t+r},${e-n/2}`,`L${t+r-i},${e-n}`,`L${t+i},${e-n}`,`L${t},${e-n/2}`,"Z"].join(" ")),"createHexagonPathD");async function bt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=a.height+e.padding,s=o/4,l=a.width+2*s+e.padding,u=[{x:s,y:0},{x:l-s,y:0},{x:l,y:-o/2},{x:l-s,y:-o},{x:s,y:-o},{x:0,y:-o/2}];let f;const{cssStyles:g}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=xt(0,0,l,o,s),a=t.path(n,r);f=i.insert((()=>a),":first-child").attr("transform",`translate(${-l/2}, ${o/2})`),g&&f.attr("style",g)}else f=G(i,l,o,u);return n&&f.attr("style",n),e.width=l,e.height=o,d(e,f),e.intersect=function(t){return H.polygon(e,u,t)},i}async function kt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.label="",e.labelStyle=r;const{shapeSvg:i}=await h(t,e,p(e)),a=Math.max(30,e?.width??0),o=Math.max(30,e?.height??0),{cssStyles:l}=e,u=c.A.svg(i),g=A(e,{});"handDrawn"!==e.look&&(g.roughness=0,g.fillStyle="solid");const m=[{x:0,y:0},{x:a,y:0},{x:0,y:o},{x:a,y:o}],y=f(m),x=u.path(y,g),b=i.insert((()=>x),":first-child");return b.attr("class","basic label-container"),l&&"handDrawn"!==e.look&&b.selectChildren("path").attr("style",l),n&&"handDrawn"!==e.look&&b.selectChildren("path").attr("style",n),b.attr("transform",`translate(${-a/2}, ${-o/2})`),d(e,b),e.intersect=function(t){s.Rm.info("Pill intersect",e,{points:m});return H.polygon(e,m,t)},i}async function Ct(t,e,{config:{themeVariables:r,flowchart:i}}){const{labelStyles:a}=S(e);e.labelStyle=a;const o=e.assetHeight??48,l=e.assetWidth??48,u=Math.max(o,l),p=i?.wrappingWidth;e.width=Math.max(u,p??0);const{shapeSvg:f,bbox:g,label:m}=await h(t,e,"icon-shape default"),y="t"===e.pos,x=u,b=u,{nodeBorder:k}=r,{stylesMap:C}=_(e),w=-b/2,v=-x/2,T=e.label?8:0,M=c.A.svg(f),B=A(e,{stroke:"none",fill:"none"});"handDrawn"!==e.look&&(B.roughness=0,B.fillStyle="solid");const L=M.rectangle(w,v,b,x,B),F=Math.max(b,g.width),$=x+g.height+T,E=M.rectangle(-F/2,-$/2,F,$,{...B,fill:"transparent",stroke:"none"}),N=f.insert((()=>L),":first-child"),D=f.insert((()=>E));if(e.icon){const t=f.append("g");t.html(`<g>${await(0,n.WY)(e.icon,{height:u,width:u,fallbackPrefix:""})}</g>`);const r=t.node().getBBox(),i=r.width,a=r.height,o=r.x,s=r.y;t.attr("transform",`translate(${-i/2-o},${y?g.height/2+T/2-a/2-s:-g.height/2-T/2-a/2-s})`),t.attr("style",`color: ${C.get("stroke")??k};`)}return m.attr("transform",`translate(${-g.width/2-(g.x-(g.left??0))},${y?-$/2:$/2-g.height})`),N.attr("transform",`translate(0,${y?g.height/2+T/2:-g.height/2-T/2})`),d(e,D),e.intersect=function(t){if(s.Rm.info("iconSquare intersect",e,t),!e.label)return H.rect(e,t);const r=e.x??0,n=e.y??0,i=e.height??0;let a=[];a=y?[{x:r-g.width/2,y:n-i/2},{x:r+g.width/2,y:n-i/2},{x:r+g.width/2,y:n-i/2+g.height+T},{x:r+b/2,y:n-i/2+g.height+T},{x:r+b/2,y:n+i/2},{x:r-b/2,y:n+i/2},{x:r-b/2,y:n-i/2+g.height+T},{x:r-g.width/2,y:n-i/2+g.height+T}]:[{x:r-b/2,y:n-i/2},{x:r+b/2,y:n-i/2},{x:r+b/2,y:n-i/2+x},{x:r+g.width/2,y:n-i/2+x},{x:r+g.width/2/2,y:n+i/2},{x:r-g.width/2,y:n+i/2},{x:r-g.width/2,y:n-i/2+x},{x:r-b/2,y:n-i/2+x}];return H.polygon(e,a,t)},f}async function wt(t,e,{config:{themeVariables:r,flowchart:i}}){const{labelStyles:a}=S(e);e.labelStyle=a;const o=e.assetHeight??48,l=e.assetWidth??48,u=Math.max(o,l),p=i?.wrappingWidth;e.width=Math.max(u,p??0);const{shapeSvg:f,bbox:g,label:m}=await h(t,e,"icon-shape default"),y=e.label?8:0,x="t"===e.pos,{nodeBorder:b,mainBkg:k}=r,{stylesMap:C}=_(e),w=c.A.svg(f),v=A(e,{});"handDrawn"!==e.look&&(v.roughness=0,v.fillStyle="solid");const T=C.get("fill");v.stroke=T??k;const M=f.append("g");e.icon&&M.html(`<g>${await(0,n.WY)(e.icon,{height:u,width:u,fallbackPrefix:""})}</g>`);const B=M.node().getBBox(),L=B.width,F=B.height,$=B.x,E=B.y,N=Math.max(L,F)*Math.SQRT2+40,D=w.circle(0,0,N,v),j=Math.max(N,g.width),I=N+g.height+y,O=w.rectangle(-j/2,-I/2,j,I,{...v,fill:"transparent",stroke:"none"}),R=f.insert((()=>D),":first-child"),P=f.insert((()=>O));return M.attr("transform",`translate(${-L/2-$},${x?g.height/2+y/2-F/2-E:-g.height/2-y/2-F/2-E})`),M.attr("style",`color: ${C.get("stroke")??b};`),m.attr("transform",`translate(${-g.width/2-(g.x-(g.left??0))},${x?-I/2:I/2-g.height})`),R.attr("transform",`translate(0,${x?g.height/2+y/2:-g.height/2-y/2})`),d(e,P),e.intersect=function(t){s.Rm.info("iconSquare intersect",e,t);return H.rect(e,t)},f}async function _t(t,e,{config:{themeVariables:r,flowchart:i}}){const{labelStyles:a}=S(e);e.labelStyle=a;const o=e.assetHeight??48,l=e.assetWidth??48,u=Math.max(o,l),p=i?.wrappingWidth;e.width=Math.max(u,p??0);const{shapeSvg:f,bbox:g,halfPadding:m,label:y}=await h(t,e,"icon-shape default"),x="t"===e.pos,b=u+2*m,k=u+2*m,{nodeBorder:w,mainBkg:v}=r,{stylesMap:T}=_(e),M=-k/2,B=-b/2,L=e.label?8:0,F=c.A.svg(f),$=A(e,{});"handDrawn"!==e.look&&($.roughness=0,$.fillStyle="solid");const E=T.get("fill");$.stroke=E??v;const N=F.path(C(M,B,k,b,5),$),D=Math.max(k,g.width),j=b+g.height+L,I=F.rectangle(-D/2,-j/2,D,j,{...$,fill:"transparent",stroke:"none"}),O=f.insert((()=>N),":first-child").attr("class","icon-shape2"),R=f.insert((()=>I));if(e.icon){const t=f.append("g");t.html(`<g>${await(0,n.WY)(e.icon,{height:u,width:u,fallbackPrefix:""})}</g>`);const r=t.node().getBBox(),i=r.width,a=r.height,o=r.x,s=r.y;t.attr("transform",`translate(${-i/2-o},${x?g.height/2+L/2-a/2-s:-g.height/2-L/2-a/2-s})`),t.attr("style",`color: ${T.get("stroke")??w};`)}return y.attr("transform",`translate(${-g.width/2-(g.x-(g.left??0))},${x?-j/2:j/2-g.height})`),O.attr("transform",`translate(0,${x?g.height/2+L/2:-g.height/2-L/2})`),d(e,R),e.intersect=function(t){if(s.Rm.info("iconSquare intersect",e,t),!e.label)return H.rect(e,t);const r=e.x??0,n=e.y??0,i=e.height??0;let a=[];a=x?[{x:r-g.width/2,y:n-i/2},{x:r+g.width/2,y:n-i/2},{x:r+g.width/2,y:n-i/2+g.height+L},{x:r+k/2,y:n-i/2+g.height+L},{x:r+k/2,y:n+i/2},{x:r-k/2,y:n+i/2},{x:r-k/2,y:n-i/2+g.height+L},{x:r-g.width/2,y:n-i/2+g.height+L}]:[{x:r-k/2,y:n-i/2},{x:r+k/2,y:n-i/2},{x:r+k/2,y:n-i/2+b},{x:r+g.width/2,y:n-i/2+b},{x:r+g.width/2/2,y:n+i/2},{x:r-g.width/2,y:n+i/2},{x:r-g.width/2,y:n-i/2+b},{x:r-k/2,y:n-i/2+b}];return H.polygon(e,a,t)},f}async function vt(t,e,{config:{themeVariables:r,flowchart:i}}){const{labelStyles:a}=S(e);e.labelStyle=a;const o=e.assetHeight??48,l=e.assetWidth??48,u=Math.max(o,l),p=i?.wrappingWidth;e.width=Math.max(u,p??0);const{shapeSvg:f,bbox:g,halfPadding:m,label:y}=await h(t,e,"icon-shape default"),x="t"===e.pos,b=u+2*m,k=u+2*m,{nodeBorder:w,mainBkg:v}=r,{stylesMap:T}=_(e),M=-k/2,B=-b/2,L=e.label?8:0,F=c.A.svg(f),$=A(e,{});"handDrawn"!==e.look&&($.roughness=0,$.fillStyle="solid");const E=T.get("fill");$.stroke=E??v;const N=F.path(C(M,B,k,b,.1),$),D=Math.max(k,g.width),j=b+g.height+L,I=F.rectangle(-D/2,-j/2,D,j,{...$,fill:"transparent",stroke:"none"}),O=f.insert((()=>N),":first-child"),R=f.insert((()=>I));if(e.icon){const t=f.append("g");t.html(`<g>${await(0,n.WY)(e.icon,{height:u,width:u,fallbackPrefix:""})}</g>`);const r=t.node().getBBox(),i=r.width,a=r.height,o=r.x,s=r.y;t.attr("transform",`translate(${-i/2-o},${x?g.height/2+L/2-a/2-s:-g.height/2-L/2-a/2-s})`),t.attr("style",`color: ${T.get("stroke")??w};`)}return y.attr("transform",`translate(${-g.width/2-(g.x-(g.left??0))},${x?-j/2:j/2-g.height})`),O.attr("transform",`translate(0,${x?g.height/2+L/2:-g.height/2-L/2})`),d(e,R),e.intersect=function(t){if(s.Rm.info("iconSquare intersect",e,t),!e.label)return H.rect(e,t);const r=e.x??0,n=e.y??0,i=e.height??0;let a=[];a=x?[{x:r-g.width/2,y:n-i/2},{x:r+g.width/2,y:n-i/2},{x:r+g.width/2,y:n-i/2+g.height+L},{x:r+k/2,y:n-i/2+g.height+L},{x:r+k/2,y:n+i/2},{x:r-k/2,y:n+i/2},{x:r-k/2,y:n-i/2+g.height+L},{x:r-g.width/2,y:n-i/2+g.height+L}]:[{x:r-k/2,y:n-i/2},{x:r+k/2,y:n-i/2},{x:r+k/2,y:n-i/2+b},{x:r+g.width/2,y:n-i/2+b},{x:r+g.width/2/2,y:n+i/2},{x:r-g.width/2,y:n+i/2},{x:r-g.width/2,y:n-i/2+b},{x:r-k/2,y:n-i/2+b}];return H.polygon(e,a,t)},f}async function St(t,e,{config:{flowchart:r}}){const n=new Image;n.src=e?.img??"",await n.decode();const i=Number(n.naturalWidth.toString().replace("px","")),a=Number(n.naturalHeight.toString().replace("px",""));e.imageAspectRatio=i/a;const{labelStyles:o}=S(e);e.labelStyle=o;const l=r?.wrappingWidth;e.defaultWidth=r?.wrappingWidth;const u=Math.max(e.label?l??0:0,e?.assetWidth??i),p="on"===e.constraint&&e?.assetHeight?e.assetHeight*e.imageAspectRatio:u,f="on"===e.constraint?p/e.imageAspectRatio:e?.assetHeight??a;e.width=Math.max(p,l??0);const{shapeSvg:g,bbox:m,label:y}=await h(t,e,"image-shape default"),x="t"===e.pos,b=-p/2,k=-f/2,C=e.label?8:0,w=c.A.svg(g),_=A(e,{});"handDrawn"!==e.look&&(_.roughness=0,_.fillStyle="solid");const v=w.rectangle(b,k,p,f,_),T=Math.max(p,m.width),M=f+m.height+C,B=w.rectangle(-T/2,-M/2,T,M,{..._,fill:"none",stroke:"none"}),L=g.insert((()=>v),":first-child"),F=g.insert((()=>B));if(e.img){const t=g.append("image");t.attr("href",e.img),t.attr("width",p),t.attr("height",f),t.attr("preserveAspectRatio","none"),t.attr("transform",`translate(${-p/2},${x?M/2-f:-M/2})`)}return y.attr("transform",`translate(${-m.width/2-(m.x-(m.left??0))},${x?-f/2-m.height/2-C/2:f/2-m.height/2+C/2})`),L.attr("transform",`translate(0,${x?m.height/2+C/2:-m.height/2-C/2})`),d(e,F),e.intersect=function(t){if(s.Rm.info("iconSquare intersect",e,t),!e.label)return H.rect(e,t);const r=e.x??0,n=e.y??0,i=e.height??0;let a=[];a=x?[{x:r-m.width/2,y:n-i/2},{x:r+m.width/2,y:n-i/2},{x:r+m.width/2,y:n-i/2+m.height+C},{x:r+p/2,y:n-i/2+m.height+C},{x:r+p/2,y:n+i/2},{x:r-p/2,y:n+i/2},{x:r-p/2,y:n-i/2+m.height+C},{x:r-m.width/2,y:n-i/2+m.height+C}]:[{x:r-p/2,y:n-i/2},{x:r+p/2,y:n-i/2},{x:r+p/2,y:n-i/2+f},{x:r+m.width/2,y:n-i/2+f},{x:r+m.width/2/2,y:n+i/2},{x:r-m.width/2,y:n+i/2},{x:r-m.width/2,y:n-i/2+f},{x:r-p/2,y:n-i/2+f}];return H.polygon(e,a,t)},g}async function At(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(a.width+2*(e.padding??0),e?.width??0),s=Math.max(a.height+2*(e.padding??0),e?.height??0),l=[{x:0,y:0},{x:o,y:0},{x:o+3*s/6,y:-s},{x:-3*s/6,y:-s}];let u;const{cssStyles:g}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=f(l),a=t.path(n,r);u=i.insert((()=>a),":first-child").attr("transform",`translate(${-o/2}, ${s/2})`),g&&u.attr("style",g)}else u=G(i,o,s,l);return n&&u.attr("style",n),e.width=o,e.height=s,d(e,u),e.intersect=function(t){return H.polygon(e,l,t)},i}async function Tt(t,e,r){const{labelStyles:n,nodeStyles:i}=S(e);e.labelStyle=n;const{shapeSvg:a,bbox:s}=await h(t,e,p(e)),l=Math.max(s.width+2*r.labelPaddingX,e?.width||0),u=Math.max(s.height+2*r.labelPaddingY,e?.height||0),f=-l/2,g=-u/2;let m,{rx:y,ry:x}=e;const{cssStyles:b}=e;if(r?.rx&&r.ry&&(y=r.rx,x=r.ry),"handDrawn"===e.look){const t=c.A.svg(a),r=A(e,{}),n=y||x?t.path(C(f,g,l,u,y||0),r):t.rectangle(f,g,l,u,r);m=a.insert((()=>n),":first-child"),m.attr("class","basic label-container").attr("style",(0,o.KL)(b))}else m=a.insert("rect",":first-child"),m.attr("class","basic label-container").attr("style",i).attr("rx",(0,o.KL)(y)).attr("ry",(0,o.KL)(x)).attr("x",f).attr("y",g).attr("width",l).attr("height",u);return d(e,m),e.intersect=function(t){return H.rect(e,t)},a}async function Mt(t,e){const{shapeSvg:r,bbox:n,label:i}=await h(t,e,"label"),a=r.insert("rect",":first-child");return a.attr("width",.1).attr("height",.1),r.attr("class","label edgeLabel"),i.attr("transform",`translate(${-n.width/2-(n.x-(n.left??0))}, ${-n.height/2-(n.y-(n.top??0))})`),d(e,a),e.intersect=function(t){return H.rect(e,t)},r}async function Bt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(a.width+(e.padding??0),e?.width??0),s=Math.max(a.height+(e.padding??0),e?.height??0),l=[{x:0,y:0},{x:o+3*s/6,y:0},{x:o,y:-s},{x:-3*s/6,y:-s}];let u;const{cssStyles:g}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=f(l),a=t.path(n,r);u=i.insert((()=>a),":first-child").attr("transform",`translate(${-o/2}, ${s/2})`),g&&u.attr("style",g)}else u=G(i,o,s,l);return n&&u.attr("style",n),e.width=o,e.height=s,d(e,u),e.intersect=function(t){return H.polygon(e,l,t)},i}async function Lt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(a.width+(e.padding??0),e?.width??0),s=Math.max(a.height+(e.padding??0),e?.height??0),l=[{x:-3*s/6,y:0},{x:o,y:0},{x:o+3*s/6,y:-s},{x:0,y:-s}];let u;const{cssStyles:g}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=f(l),a=t.path(n,r);u=i.insert((()=>a),":first-child").attr("transform",`translate(${-o/2}, ${s/2})`),g&&u.attr("style",g)}else u=G(i,o,s,l);return n&&u.attr("style",n),e.width=o,e.height=s,d(e,u),e.intersect=function(t){return H.polygon(e,l,t)},i}function Ft(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.label="",e.labelStyle=r;const i=t.insert("g").attr("class",p(e)).attr("id",e.domId??e.id),{cssStyles:a}=e,o=Math.max(35,e?.width??0),l=Math.max(35,e?.height??0),h=[{x:o,y:0},{x:0,y:l+3.5},{x:o-14,y:l+3.5},{x:0,y:2*l},{x:o,y:l-3.5},{x:14,y:l-3.5}],u=c.A.svg(i),g=A(e,{});"handDrawn"!==e.look&&(g.roughness=0,g.fillStyle="solid");const m=f(h),y=u.path(m,g),x=i.insert((()=>y),":first-child");return a&&"handDrawn"!==e.look&&x.selectAll("path").attr("style",a),n&&"handDrawn"!==e.look&&x.selectAll("path").attr("style",n),x.attr("transform",`translate(-${o/2},${-l})`),d(e,x),e.intersect=function(t){s.Rm.info("lightningBolt intersect",e,t);return H.polygon(e,h,t)},i}(0,s.K2)(bt,"hexagon"),(0,s.K2)(kt,"hourglass"),(0,s.K2)(Ct,"icon"),(0,s.K2)(wt,"iconCircle"),(0,s.K2)(_t,"iconRounded"),(0,s.K2)(vt,"iconSquare"),(0,s.K2)(St,"imageSquare"),(0,s.K2)(At,"inv_trapezoid"),(0,s.K2)(Tt,"drawRect"),(0,s.K2)(Mt,"labelRect"),(0,s.K2)(Bt,"lean_left"),(0,s.K2)(Lt,"lean_right"),(0,s.K2)(Ft,"lightningBolt");var $t=(0,s.K2)(((t,e,r,n,i,a,o)=>[`M${t},${e+a}`,`a${i},${a} 0,0,0 ${r},0`,`a${i},${a} 0,0,0 ${-r},0`,`l0,${n}`,`a${i},${a} 0,0,0 ${r},0`,"l0,"+-n,`M${t},${e+a+o}`,`a${i},${a} 0,0,0 ${r},0`].join(" ")),"createCylinderPathD"),Et=(0,s.K2)(((t,e,r,n,i,a,o)=>[`M${t},${e+a}`,`M${t+r},${e+a}`,`a${i},${a} 0,0,0 ${-r},0`,`l0,${n}`,`a${i},${a} 0,0,0 ${r},0`,"l0,"+-n,`M${t},${e+a+o}`,`a${i},${a} 0,0,0 ${r},0`].join(" ")),"createOuterCylinderPathD"),Nt=(0,s.K2)(((t,e,r,n,i,a)=>[`M${t-r/2},${-n/2}`,`a${i},${a} 0,0,0 ${r},0`].join(" ")),"createInnerCylinderPathD");async function Dt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:s}=await h(t,e,p(e)),l=Math.max(a.width+(e.padding??0),e.width??0),u=l/2,f=u/(2.5+l/50),g=Math.max(a.height+f+(e.padding??0),e.height??0),m=.1*g;let y;const{cssStyles:x}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=Et(0,0,l,g,u,f,m),n=Nt(0,f,l,g,u,f),a=A(e,{}),o=t.path(r,a),s=t.path(n,a);i.insert((()=>s),":first-child").attr("class","line"),y=i.insert((()=>o),":first-child"),y.attr("class","basic label-container"),x&&y.attr("style",x)}else{const t=$t(0,0,l,g,u,f,m);y=i.insert("path",":first-child").attr("d",t).attr("class","basic label-container").attr("style",(0,o.KL)(x)).attr("style",n)}return y.attr("label-offset-y",f),y.attr("transform",`translate(${-l/2}, ${-(g/2+f)})`),d(e,y),s.attr("transform",`translate(${-a.width/2-(a.x-(a.left??0))}, ${-a.height/2+f-(a.y-(a.top??0))})`),e.intersect=function(t){const r=H.rect(e,t),n=r.x-(e.x??0);if(0!=u&&(Math.abs(n)<(e.width??0)/2||Math.abs(n)==(e.width??0)/2&&Math.abs(r.y-(e.y??0))>(e.height??0)/2-f)){let i=f*f*(1-n*n/(u*u));i>0&&(i=Math.sqrt(i)),i=f-i,t.y-(e.y??0)>0&&(i=-i),r.y+=i}return r},i}async function jt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=l/4,f=l+u,{cssStyles:m}=e,y=c.A.svg(i),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=[{x:-s/2-s/2*.1,y:-f/2},{x:-s/2-s/2*.1,y:f/2},...g(-s/2-s/2*.1,f/2,s/2+s/2*.1,f/2,u,.8),{x:s/2+s/2*.1,y:-f/2},{x:-s/2-s/2*.1,y:-f/2},{x:-s/2,y:-f/2},{x:-s/2,y:f/2*1.1},{x:-s/2,y:-f/2}],k=y.polygon(b.map((t=>[t.x,t.y])),x),C=i.insert((()=>k),":first-child");return C.attr("class","basic label-container"),m&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",m),n&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",n),C.attr("transform",`translate(0,${-u/2})`),o.attr("transform",`translate(${-s/2+(e.padding??0)+s/2*.1/2-(a.x-(a.left??0))},${-l/2+(e.padding??0)-u/2-(a.y-(a.top??0))})`),d(e,C),e.intersect=function(t){return H.polygon(e,b,t)},i}async function It(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=-s/2,g=-l/2,{cssStyles:m}=e,y=c.A.svg(i),x=A(e,{}),b=[{x:u-5,y:g+5},{x:u-5,y:g+l+5},{x:u+s-5,y:g+l+5},{x:u+s-5,y:g+l},{x:u+s,y:g+l},{x:u+s,y:g+l-5},{x:u+s+5,y:g+l-5},{x:u+s+5,y:g-5},{x:u+5,y:g-5},{x:u+5,y:g},{x:u,y:g},{x:u,y:g+5}],k=[{x:u,y:g+5},{x:u+s-5,y:g+5},{x:u+s-5,y:g+l},{x:u+s,y:g+l},{x:u+s,y:g},{x:u,y:g}];"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const C=f(b),w=y.path(C,x),_=f(k),v=y.path(_,{...x,fill:"none"}),T=i.insert((()=>v),":first-child");return T.insert((()=>w),":first-child"),T.attr("class","basic label-container"),m&&"handDrawn"!==e.look&&T.selectAll("path").attr("style",m),n&&"handDrawn"!==e.look&&T.selectAll("path").attr("style",n),o.attr("transform",`translate(${-a.width/2-5-(a.x-(a.left??0))}, ${-a.height/2+5-(a.y-(a.top??0))})`),d(e,T),e.intersect=function(t){return H.polygon(e,b,t)},i}async function Ot(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=l/4,m=l+u,y=-s/2,x=-m/2,{cssStyles:b}=e,k=g(y-5,x+m+5,y+s-5,x+m+5,u,.8),C=k?.[k.length-1],w=[{x:y-5,y:x+5},{x:y-5,y:x+m+5},...k,{x:y+s-5,y:C.y-5},{x:y+s,y:C.y-5},{x:y+s,y:C.y-10},{x:y+s+5,y:C.y-10},{x:y+s+5,y:x-5},{x:y+5,y:x-5},{x:y+5,y:x},{x:y,y:x},{x:y,y:x+5}],_=[{x:y,y:x+5},{x:y+s-5,y:x+5},{x:y+s-5,y:C.y-5},{x:y+s,y:C.y-5},{x:y+s,y:x},{x:y,y:x}],v=c.A.svg(i),T=A(e,{});"handDrawn"!==e.look&&(T.roughness=0,T.fillStyle="solid");const M=f(w),B=v.path(M,T),L=f(_),F=v.path(L,T),$=i.insert((()=>B),":first-child");return $.insert((()=>F)),$.attr("class","basic label-container"),b&&"handDrawn"!==e.look&&$.selectAll("path").attr("style",b),n&&"handDrawn"!==e.look&&$.selectAll("path").attr("style",n),$.attr("transform",`translate(0,${-u/2})`),o.attr("transform",`translate(${-a.width/2-5-(a.x-(a.left??0))}, ${-a.height/2+5-u/2-(a.y-(a.top??0))})`),d(e,$),e.intersect=function(t){return H.polygon(e,w,t)},i}async function Rt(t,e,{config:{themeVariables:r}}){const{labelStyles:n,nodeStyles:i}=S(e);e.labelStyle=n;e.useHtmlLabels||!1!==(0,s.zj)().flowchart?.htmlLabels||(e.centerLabel=!0);const{shapeSvg:a,bbox:o}=await h(t,e,p(e)),l=Math.max(o.width+2*(e.padding??0),e?.width??0),u=Math.max(o.height+2*(e.padding??0),e?.height??0),f=-l/2,g=-u/2,{cssStyles:m}=e,y=c.A.svg(a),x=A(e,{fill:r.noteBkgColor,stroke:r.noteBorderColor});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=y.rectangle(f,g,l,u,x),k=a.insert((()=>b),":first-child");return k.attr("class","basic label-container"),m&&"handDrawn"!==e.look&&k.selectAll("path").attr("style",m),i&&"handDrawn"!==e.look&&k.selectAll("path").attr("style",i),d(e,k),e.intersect=function(t){return H.rect(e,t)},a}(0,s.K2)(Dt,"linedCylinder"),(0,s.K2)(jt,"linedWaveEdgedRect"),(0,s.K2)(It,"multiRect"),(0,s.K2)(Ot,"multiWaveEdgedRectangle"),(0,s.K2)(Rt,"note");var Pt=(0,s.K2)(((t,e,r)=>[`M${t+r/2},${e}`,`L${t+r},${e-r/2}`,`L${t+r/2},${e-r}`,`L${t},${e-r/2}`,"Z"].join(" ")),"createDecisionBoxPathD");async function zt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=a.width+e.padding+(a.height+e.padding),l=[{x:o/2,y:0},{x:o,y:-o/2},{x:o/2,y:-o},{x:0,y:-o/2}];let u;const{cssStyles:f}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=Pt(0,0,o),a=t.path(n,r);u=i.insert((()=>a),":first-child").attr("transform",`translate(${-o/2}, ${o/2})`),f&&u.attr("style",f)}else u=G(i,o,o,l);return n&&u.attr("style",n),d(e,u),e.intersect=function(t){return s.Rm.debug("APA12 Intersect called SPLIT\npoint:",t,"\nnode:\n",e,"\nres:",H.polygon(e,l,t)),H.polygon(e,l,t)},i}async function Kt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=-Math.max(a.width+(e.padding??0),e?.width??0)/2,l=-Math.max(a.height+(e.padding??0),e?.height??0)/2,u=l/2,g=[{x:s+u,y:l},{x:s,y:0},{x:s+u,y:-l},{x:-s,y:-l},{x:-s,y:l}],{cssStyles:m}=e,y=c.A.svg(i),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=f(g),k=y.path(b,x),C=i.insert((()=>k),":first-child");return C.attr("class","basic label-container"),m&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",m),n&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",n),C.attr("transform",`translate(${-u/2},0)`),o.attr("transform",`translate(${-u/2-a.width/2-(a.x-(a.left??0))}, ${-a.height/2-(a.y-(a.top??0))})`),d(e,C),e.intersect=function(t){return H.polygon(e,g,t)},i}async function qt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);let i;e.labelStyle=r,i=e.cssClasses?"node "+e.cssClasses:"node default";const a=t.insert("g").attr("class",i).attr("id",e.domId||e.id),o=a.insert("g"),h=a.insert("g").attr("class","label").attr("style",n),u=e.description,p=e.label,f=h.node().appendChild(await k(p,e.labelStyle,!0,!0));let g={width:0,height:0};if((0,s._3)((0,s.D7)()?.flowchart?.htmlLabels)){const t=f.children[0],e=(0,l.Ltv)(f);g=t.getBoundingClientRect(),e.attr("width",g.width),e.attr("height",g.height)}s.Rm.info("Text 2",u);const m=u||[],y=f.getBBox(),x=h.node().appendChild(await k(m.join?m.join("<br/>"):m,e.labelStyle,!0,!0)),b=x.children[0],w=(0,l.Ltv)(x);g=b.getBoundingClientRect(),w.attr("width",g.width),w.attr("height",g.height);const _=(e.padding||0)/2;(0,l.Ltv)(x).attr("transform","translate( "+(g.width>y.width?0:(y.width-g.width)/2)+", "+(y.height+_+5)+")"),(0,l.Ltv)(f).attr("transform","translate( "+(g.width<y.width?0:-(y.width-g.width)/2)+", 0)"),g=h.node().getBBox(),h.attr("transform","translate("+-g.width/2+", "+(-g.height/2-_+3)+")");const v=g.width+(e.padding||0),T=g.height+(e.padding||0),M=-g.width/2-_,B=-g.height/2-_;let L,F;if("handDrawn"===e.look){const t=c.A.svg(a),r=A(e,{}),n=t.path(C(M,B,v,T,e.rx||0),r),i=t.line(-g.width/2-_,-g.height/2-_+y.height+_,g.width/2+_,-g.height/2-_+y.height+_,r);F=a.insert((()=>(s.Rm.debug("Rough node insert CXC",n),i)),":first-child"),L=a.insert((()=>(s.Rm.debug("Rough node insert CXC",n),n)),":first-child")}else L=o.insert("rect",":first-child"),F=o.insert("line"),L.attr("class","outer title-state").attr("style",n).attr("x",-g.width/2-_).attr("y",-g.height/2-_).attr("width",g.width+(e.padding||0)).attr("height",g.height+(e.padding||0)),F.attr("class","divider").attr("x1",-g.width/2-_).attr("x2",g.width/2+_).attr("y1",-g.height/2-_+y.height+_).attr("y2",-g.height/2-_+y.height+_);return d(e,L),e.intersect=function(t){return H.rect(e,t)},a}async function Wt(t,e){return Tt(t,e,{rx:5,ry:5,classes:"",labelPaddingX:1*(e?.padding||0),labelPaddingY:1*(e?.padding||0)})}async function Ht(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:s}=await h(t,e,p(e)),l=e?.padding??0,u=Math.max(a.width+2*(e.padding??0),e?.width??0),f=Math.max(a.height+2*(e.padding??0),e?.height??0),g=-a.width/2-l,m=-a.height/2-l,{cssStyles:y}=e,x=c.A.svg(i),b=A(e,{});"handDrawn"!==e.look&&(b.roughness=0,b.fillStyle="solid");const k=[{x:g,y:m},{x:g+u+8,y:m},{x:g+u+8,y:m+f},{x:g-8,y:m+f},{x:g-8,y:m},{x:g,y:m},{x:g,y:m+f}],C=x.polygon(k.map((t=>[t.x,t.y])),b),w=i.insert((()=>C),":first-child");return w.attr("class","basic label-container").attr("style",(0,o.KL)(y)),n&&"handDrawn"!==e.look&&w.selectAll("path").attr("style",n),y&&"handDrawn"!==e.look&&w.selectAll("path").attr("style",n),s.attr("transform",`translate(${-u/2+4+(e.padding??0)-(a.x-(a.left??0))},${-f/2+(e.padding??0)-(a.y-(a.top??0))})`),d(e,w),e.intersect=function(t){return H.rect(e,t)},i}async function Ut(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=-s/2,g=-l/2,{cssStyles:m}=e,y=c.A.svg(i),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=[{x:u,y:g},{x:u,y:g+l},{x:u+s,y:g+l},{x:u+s,y:g-l/2}],k=f(b),C=y.path(k,x),w=i.insert((()=>C),":first-child");return w.attr("class","basic label-container"),m&&"handDrawn"!==e.look&&w.selectChildren("path").attr("style",m),n&&"handDrawn"!==e.look&&w.selectChildren("path").attr("style",n),w.attr("transform",`translate(0, ${l/4})`),o.attr("transform",`translate(${-s/2+(e.padding??0)-(a.x-(a.left??0))}, ${-l/4+(e.padding??0)-(a.y-(a.top??0))})`),d(e,w),e.intersect=function(t){return H.polygon(e,b,t)},i}async function Yt(t,e){return Tt(t,e,{rx:0,ry:0,classes:"",labelPaddingX:2*(e?.padding||0),labelPaddingY:1*(e?.padding||0)})}async function Vt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),s=a.height+e.padding,l=a.width+s/4+e.padding;let u;const{cssStyles:f}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=C(-l/2,-s/2,l,s,s/2),a=t.path(n,r);u=i.insert((()=>a),":first-child"),u.attr("class","basic label-container").attr("style",(0,o.KL)(f))}else u=i.insert("rect",":first-child"),u.attr("class","basic label-container").attr("style",n).attr("rx",s/2).attr("ry",s/2).attr("x",-l/2).attr("y",-s/2).attr("width",l).attr("height",s);return d(e,u),e.intersect=function(t){return H.rect(e,t)},i}async function Gt(t,e){return Tt(t,e,{rx:5,ry:5,classes:"flowchart-node"})}function Zt(t,e,{config:{themeVariables:r}}){const{labelStyles:n,nodeStyles:i}=S(e);e.labelStyle=n;const{cssStyles:a}=e,{lineColor:o,stateBorder:s,nodeBorder:l}=r,h=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),u=c.A.svg(h),p=A(e,{});"handDrawn"!==e.look&&(p.roughness=0,p.fillStyle="solid");const f=u.circle(0,0,14,{...p,stroke:o,strokeWidth:2}),g=s??l,m=u.circle(0,0,5,{...p,fill:g,stroke:g,strokeWidth:2,fillStyle:"solid"}),y=h.insert((()=>f),":first-child");return y.insert((()=>m)),a&&y.selectAll("path").attr("style",a),i&&y.selectAll("path").attr("style",i),d(e,y),e.intersect=function(t){return H.circle(e,7,t)},h}function Xt(t,e,{config:{themeVariables:r}}){const{lineColor:n}=r,i=t.insert("g").attr("class","node default").attr("id",e.domId||e.id);let a;if("handDrawn"===e.look){const t=c.A.svg(i).circle(0,0,14,w(n));a=i.insert((()=>t)),a.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14)}else a=i.insert("circle",":first-child"),a.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14);return d(e,a),e.intersect=function(t){return H.circle(e,7,t)},i}async function Qt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),s=(e?.padding||0)/2,l=a.width+e.padding,u=a.height+e.padding,f=-a.width/2-s,g=-a.height/2-s,m=[{x:0,y:0},{x:l,y:0},{x:l,y:-u},{x:0,y:-u},{x:0,y:0},{x:-8,y:0},{x:l+8,y:0},{x:l+8,y:-u},{x:-8,y:-u},{x:-8,y:0}];if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=t.rectangle(f-8,g,l+16,u,r),a=t.line(f,g,f,g+u,r),s=t.line(f+l,g,f+l,g+u,r);i.insert((()=>a),":first-child"),i.insert((()=>s),":first-child");const h=i.insert((()=>n),":first-child"),{cssStyles:p}=e;h.attr("class","basic label-container").attr("style",(0,o.KL)(p)),d(e,h)}else{const t=G(i,l,u,m);n&&t.attr("style",n),d(e,t)}return e.intersect=function(t){return H.polygon(e,m,t)},i}async function Jt(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(a.width+2*(e.padding??0),e?.width??0),s=Math.max(a.height+2*(e.padding??0),e?.height??0),l=-o/2,u=-s/2,g=.2*s,m=.2*s,{cssStyles:y}=e,x=c.A.svg(i),b=A(e,{}),k=[{x:l-g/2,y:u},{x:l+o+g/2,y:u},{x:l+o+g/2,y:u+s},{x:l-g/2,y:u+s}],C=[{x:l+o-g/2,y:u+s},{x:l+o+g/2,y:u+s},{x:l+o+g/2,y:u+s-m}];"handDrawn"!==e.look&&(b.roughness=0,b.fillStyle="solid");const w=f(k),_=x.path(w,b),v=f(C),T=x.path(v,{...b,fillStyle:"solid"}),M=i.insert((()=>T),":first-child");return M.insert((()=>_),":first-child"),M.attr("class","basic label-container"),y&&"handDrawn"!==e.look&&M.selectAll("path").attr("style",y),n&&"handDrawn"!==e.look&&M.selectAll("path").attr("style",n),d(e,M),e.intersect=function(t){return H.polygon(e,k,t)},i}async function te(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=l/4,m=.2*s,y=.2*l,x=l+u,{cssStyles:b}=e,k=c.A.svg(i),C=A(e,{});"handDrawn"!==e.look&&(C.roughness=0,C.fillStyle="solid");const w=[{x:-s/2-s/2*.1,y:x/2},...g(-s/2-s/2*.1,x/2,s/2+s/2*.1,x/2,u,.8),{x:s/2+s/2*.1,y:-x/2},{x:-s/2-s/2*.1,y:-x/2}],_=-s/2+s/2*.1,v=-x/2-.4*y,T=[{x:_+s-m,y:1.4*(v+l)},{x:_+s,y:v+l-y},{x:_+s,y:.9*(v+l)},...g(_+s,1.3*(v+l),_+s-m,1.5*(v+l),.03*-l,.5)],M=f(w),B=k.path(M,C),L=f(T),F=k.path(L,{...C,fillStyle:"solid"}),$=i.insert((()=>F),":first-child");return $.insert((()=>B),":first-child"),$.attr("class","basic label-container"),b&&"handDrawn"!==e.look&&$.selectAll("path").attr("style",b),n&&"handDrawn"!==e.look&&$.selectAll("path").attr("style",n),$.attr("transform",`translate(0,${-u/2})`),o.attr("transform",`translate(${-s/2+(e.padding??0)-(a.x-(a.left??0))},${-l/2+(e.padding??0)-u/2-(a.y-(a.top??0))})`),d(e,$),e.intersect=function(t){return H.polygon(e,w,t)},i}async function ee(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(a.width+e.padding,e?.width||0),s=Math.max(a.height+e.padding,e?.height||0),l=-o/2,c=-s/2,u=i.insert("rect",":first-child");return u.attr("class","text").attr("style",n).attr("rx",0).attr("ry",0).attr("x",l).attr("y",c).attr("width",o).attr("height",s),d(e,u),e.intersect=function(t){return H.rect(e,t)},i}(0,s.K2)(zt,"question"),(0,s.K2)(Kt,"rect_left_inv_arrow"),(0,s.K2)(qt,"rectWithTitle"),(0,s.K2)(Wt,"roundedRect"),(0,s.K2)(Ht,"shadedProcess"),(0,s.K2)(Ut,"slopedRect"),(0,s.K2)(Yt,"squareRect"),(0,s.K2)(Vt,"stadium"),(0,s.K2)(Gt,"state"),(0,s.K2)(Zt,"stateEnd"),(0,s.K2)(Xt,"stateStart"),(0,s.K2)(Qt,"subroutine"),(0,s.K2)(Jt,"taggedRect"),(0,s.K2)(te,"taggedWaveEdgedRectangle"),(0,s.K2)(ee,"text");var re=(0,s.K2)(((t,e,r,n,i,a)=>`M${t},${e}\n a${i},${a} 0,0,1 0,${-n}\n l${r},0\n a${i},${a} 0,0,1 0,${n}\n M${r},${-n}\n a${i},${a} 0,0,0 0,${n}\n l${-r},0`),"createCylinderPathD"),ne=(0,s.K2)(((t,e,r,n,i,a)=>[`M${t},${e}`,`M${t+r},${e}`,`a${i},${a} 0,0,0 0,${-n}`,`l${-r},0`,`a${i},${a} 0,0,0 0,${n}`,`l${r},0`].join(" ")),"createOuterCylinderPathD"),ie=(0,s.K2)(((t,e,r,n,i,a)=>[`M${t+r/2},${-n/2}`,`a${i},${a} 0,0,0 0,${n}`].join(" ")),"createInnerCylinderPathD");async function ae(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:s,halfPadding:l}=await h(t,e,p(e)),u="neo"===e.look?2*l:l,f=a.height+u,g=f/2,m=g/(2.5+f/50),y=a.width+m+u,{cssStyles:x}=e;let b;if("handDrawn"===e.look){const t=c.A.svg(i),r=ne(0,0,y,f,m,g),n=ie(0,0,y,f,m,g),a=t.path(r,A(e,{})),o=t.path(n,A(e,{fill:"none"}));b=i.insert((()=>o),":first-child"),b=i.insert((()=>a),":first-child"),b.attr("class","basic label-container"),x&&b.attr("style",x)}else{const t=re(0,0,y,f,m,g);b=i.insert("path",":first-child").attr("d",t).attr("class","basic label-container").attr("style",(0,o.KL)(x)).attr("style",n),b.attr("class","basic label-container"),x&&b.selectAll("path").attr("style",x),n&&b.selectAll("path").attr("style",n)}return b.attr("label-offset-x",m),b.attr("transform",`translate(${-y/2}, ${f/2} )`),s.attr("transform",`translate(${-a.width/2-m-(a.x-(a.left??0))}, ${-a.height/2-(a.y-(a.top??0))})`),d(e,b),e.intersect=function(t){const r=H.rect(e,t),n=r.y-(e.y??0);if(0!=g&&(Math.abs(n)<(e.height??0)/2||Math.abs(n)==(e.height??0)/2&&Math.abs(r.x-(e.x??0))>(e.width??0)/2-m)){let i=m*m*(1-n*n/(g*g));0!=i&&(i=Math.sqrt(Math.abs(i))),i=m-i,t.x-(e.x??0)>0&&(i=-i),r.x+=i}return r},i}async function oe(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=a.width+e.padding,s=a.height+e.padding,l=[{x:-3*s/6,y:0},{x:o+3*s/6,y:0},{x:o,y:-s},{x:0,y:-s}];let u;const{cssStyles:g}=e;if("handDrawn"===e.look){const t=c.A.svg(i),r=A(e,{}),n=f(l),a=t.path(n,r);u=i.insert((()=>a),":first-child").attr("transform",`translate(${-o/2}, ${s/2})`),g&&u.attr("style",g)}else u=G(i,o,s,l);return n&&u.attr("style",n),e.width=o,e.height=s,d(e,u),e.intersect=function(t){return H.polygon(e,l,t)},i}async function se(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(60,a.width+2*(e.padding??0),e?.width??0),s=Math.max(20,a.height+2*(e.padding??0),e?.height??0),{cssStyles:l}=e,u=c.A.svg(i),g=A(e,{});"handDrawn"!==e.look&&(g.roughness=0,g.fillStyle="solid");const m=[{x:-o/2*.8,y:-s/2},{x:o/2*.8,y:-s/2},{x:o/2,y:-s/2*.6},{x:o/2,y:s/2},{x:-o/2,y:s/2},{x:-o/2,y:-s/2*.6}],y=f(m),x=u.path(y,g),b=i.insert((()=>x),":first-child");return b.attr("class","basic label-container"),l&&"handDrawn"!==e.look&&b.selectChildren("path").attr("style",l),n&&"handDrawn"!==e.look&&b.selectChildren("path").attr("style",n),d(e,b),e.intersect=function(t){return H.polygon(e,m,t)},i}async function le(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),l=(0,s._3)((0,s.D7)().flowchart?.htmlLabels),u=a.width+(e.padding??0),g=u+a.height,m=u+a.height,y=[{x:0,y:0},{x:m,y:0},{x:m/2,y:-g}],{cssStyles:x}=e,b=c.A.svg(i),k=A(e,{});"handDrawn"!==e.look&&(k.roughness=0,k.fillStyle="solid");const C=f(y),w=b.path(C,k),_=i.insert((()=>w),":first-child").attr("transform",`translate(${-g/2}, ${g/2})`);return x&&"handDrawn"!==e.look&&_.selectChildren("path").attr("style",x),n&&"handDrawn"!==e.look&&_.selectChildren("path").attr("style",n),e.width=u,e.height=g,d(e,_),o.attr("transform",`translate(${-a.width/2-(a.x-(a.left??0))}, ${g/2-(a.height+(e.padding??0)/(l?2:1)-(a.y-(a.top??0)))})`),e.intersect=function(t){return s.Rm.info("Triangle intersect",e,y,t),H.polygon(e,y,t)},i}async function ce(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=l/8,m=l+u,{cssStyles:y}=e,x=70-s,b=x>0?x/2:0,k=c.A.svg(i),C=A(e,{});"handDrawn"!==e.look&&(C.roughness=0,C.fillStyle="solid");const w=[{x:-s/2-b,y:m/2},...g(-s/2-b,m/2,s/2+b,m/2,u,.8),{x:s/2+b,y:-m/2},{x:-s/2-b,y:-m/2}],_=f(w),v=k.path(_,C),T=i.insert((()=>v),":first-child");return T.attr("class","basic label-container"),y&&"handDrawn"!==e.look&&T.selectAll("path").attr("style",y),n&&"handDrawn"!==e.look&&T.selectAll("path").attr("style",n),T.attr("transform",`translate(0,${-u/2})`),o.attr("transform",`translate(${-s/2+(e.padding??0)-(a.x-(a.left??0))},${-l/2+(e.padding??0)-u-(a.y-(a.top??0))})`),d(e,T),e.intersect=function(t){return H.polygon(e,w,t)},i}async function he(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a}=await h(t,e,p(e)),o=Math.max(a.width+2*(e.padding??0),e?.width??0),s=Math.max(a.height+2*(e.padding??0),e?.height??0),l=o/s;let u=o,m=s;u>m*l?m=u/l:u=m*l,u=Math.max(u,100),m=Math.max(m,50);const y=Math.min(.2*m,m/4),x=m+2*y,{cssStyles:b}=e,k=c.A.svg(i),C=A(e,{});"handDrawn"!==e.look&&(C.roughness=0,C.fillStyle="solid");const w=[{x:-u/2,y:x/2},...g(-u/2,x/2,u/2,x/2,y,1),{x:u/2,y:-x/2},...g(u/2,-x/2,-u/2,-x/2,y,-1)],_=f(w),v=k.path(_,C),T=i.insert((()=>v),":first-child");return T.attr("class","basic label-container"),b&&"handDrawn"!==e.look&&T.selectAll("path").attr("style",b),n&&"handDrawn"!==e.look&&T.selectAll("path").attr("style",n),d(e,T),e.intersect=function(t){return H.polygon(e,w,t)},i}async function ue(t,e){const{labelStyles:r,nodeStyles:n}=S(e);e.labelStyle=r;const{shapeSvg:i,bbox:a,label:o}=await h(t,e,p(e)),s=Math.max(a.width+2*(e.padding??0),e?.width??0),l=Math.max(a.height+2*(e.padding??0),e?.height??0),u=-s/2,f=-l/2,{cssStyles:g}=e,m=c.A.svg(i),y=A(e,{}),x=[{x:u-5,y:f-5},{x:u-5,y:f+l},{x:u+s,y:f+l},{x:u+s,y:f-5}],b=`M${u-5},${f-5} L${u+s},${f-5} L${u+s},${f+l} L${u-5},${f+l} L${u-5},${f-5}\n M${u-5},${f} L${u+s},${f}\n M${u},${f-5} L${u},${f+l}`;"handDrawn"!==e.look&&(y.roughness=0,y.fillStyle="solid");const k=m.path(b,y),C=i.insert((()=>k),":first-child");return C.attr("transform","translate(2.5, 2.5)"),C.attr("class","basic label-container"),g&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",g),n&&"handDrawn"!==e.look&&C.selectAll("path").attr("style",n),o.attr("transform",`translate(${-a.width/2+2.5-(a.x-(a.left??0))}, ${-a.height/2+2.5-(a.y-(a.top??0))})`),d(e,C),e.intersect=function(t){return H.polygon(e,x,t)},i}async function de(t,e,r,n,i=r.class.padding??12){const a=n?0:3,o=t.insert("g").attr("class",p(e)).attr("id",e.domId||e.id);let s=null,l=null,c=null,h=null,u=0,d=0,f=0;if(s=o.insert("g").attr("class","annotation-group text"),e.annotations.length>0){const t=e.annotations[0];await pe(s,{text:`\xab${t}\xbb`},0);u=s.node().getBBox().height}l=o.insert("g").attr("class","label-group text"),await pe(l,e,0,["font-weight: bolder"]);const g=l.node().getBBox();d=g.height,c=o.insert("g").attr("class","members-group text");let m=0;for(const p of e.members){m+=await pe(c,p,m,[p.parseClassifier()])+a}f=c.node().getBBox().height,f<=0&&(f=i/2),h=o.insert("g").attr("class","methods-group text");let y=0;for(const p of e.methods){y+=await pe(h,p,y,[p.parseClassifier()])+a}let x=o.node().getBBox();if(null!==s){const t=s.node().getBBox();s.attr("transform",`translate(${-t.width/2})`)}return l.attr("transform",`translate(${-g.width/2}, ${u})`),x=o.node().getBBox(),c.attr("transform",`translate(0, ${u+d+2*i})`),x=o.node().getBBox(),h.attr("transform",`translate(0, ${u+d+(f?f+4*i:2*i)})`),x=o.node().getBBox(),{shapeSvg:o,bbox:x}}async function pe(t,e,r,n=[]){const i=t.insert("g").attr("class","label").attr("style",n.join("; ")),c=(0,s.zj)();let h="useHtmlLabels"in e?e.useHtmlLabels:(0,s._3)(c.htmlLabels)??!0,u="";u="text"in e?e.text:e.label,!h&&u.startsWith("\\")&&(u=u.substring(1)),(0,s.Wi)(u)&&(h=!0);const d=await(0,a.GZ)(i,(0,s.oB)((0,o.Sm)(u)),{width:(0,o.Un)(u,c)+50,classes:"markdown-node-label",useHtmlLabels:h},c);let p,f=1;if(h){const t=d.children[0],e=(0,l.Ltv)(d);f=t.innerHTML.split("<br>").length,t.innerHTML.includes("</math>")&&(f+=t.innerHTML.split("<mrow>").length-1);const r=t.getElementsByTagName("img");if(r){const t=""===u.replace(/<img[^>]*>/g,"").trim();await Promise.all([...r].map((e=>new Promise((r=>{function n(){if(e.style.display="flex",e.style.flexDirection="column",t){const t=c.fontSize?.toString()??window.getComputedStyle(document.body).fontSize,r=5,n=parseInt(t,10)*r+"px";e.style.minWidth=n,e.style.maxWidth=n}else e.style.width="100%";r(e)}(0,s.K2)(n,"setupImage"),setTimeout((()=>{e.complete&&n()})),e.addEventListener("error",n),e.addEventListener("load",n)})))))}p=t.getBoundingClientRect(),e.attr("width",p.width),e.attr("height",p.height)}else{n.includes("font-weight: bolder")&&(0,l.Ltv)(d).selectAll("tspan").attr("font-weight",""),f=d.children.length;const t=d.children[0];if(""===d.textContent||d.textContent.includes(">")){t.textContent=u[0]+u.substring(1).replaceAll(">",">").replaceAll("<","<").trim();" "===u[1]&&(t.textContent=t.textContent[0]+" "+t.textContent.substring(1))}"undefined"===t.textContent&&(t.textContent=""),p=d.getBBox()}return i.attr("transform","translate(0,"+(-p.height/(2*f)+r)+")"),p.height}async function fe(t,e){const r=(0,s.D7)(),n=r.class.padding??12,i=n,a=e.useHtmlLabels??(0,s._3)(r.htmlLabels)??!0,o=e;o.annotations=o.annotations??[],o.members=o.members??[],o.methods=o.methods??[];const{shapeSvg:h,bbox:u}=await de(t,e,r,a,i),{labelStyles:p,nodeStyles:f}=S(e);e.labelStyle=p,e.cssStyles=o.styles||"";const g=o.styles?.join(";")||f||"";e.cssStyles||(e.cssStyles=g.replaceAll("!important","").split(";"));const m=0===o.members.length&&0===o.methods.length&&!r.class?.hideEmptyMembersBox,y=c.A.svg(h),x=A(e,{});"handDrawn"!==e.look&&(x.roughness=0,x.fillStyle="solid");const b=u.width;let k=u.height;0===o.members.length&&0===o.methods.length?k+=i:o.members.length>0&&0===o.methods.length&&(k+=2*i);const C=-b/2,w=-k/2,_=y.rectangle(C-n,w-n-(m?n:0===o.members.length&&0===o.methods.length?-n/2:0),b+2*n,k+2*n+(m?2*n:0===o.members.length&&0===o.methods.length?-n:0),x),v=h.insert((()=>_),":first-child");v.attr("class","basic label-container");const T=v.node().getBBox();h.selectAll(".text").each(((t,e,r)=>{const i=(0,l.Ltv)(r[e]),s=i.attr("transform");let c=0;if(s){const t=RegExp(/translate\(([^,]+),([^)]+)\)/).exec(s);t&&(c=parseFloat(t[2]))}let u=c+w+n-(m?n:0===o.members.length&&0===o.methods.length?-n/2:0);a||(u-=4);let d=C;(i.attr("class").includes("label-group")||i.attr("class").includes("annotation-group"))&&(d=-i.node()?.getBBox().width/2||0,h.selectAll("text").each((function(t,e,r){"middle"===window.getComputedStyle(r[e]).textAnchor&&(d=0)}))),i.attr("transform",`translate(${d}, ${u})`)}));const M=h.select(".annotation-group").node().getBBox().height-(m?n/2:0)||0,B=h.select(".label-group").node().getBBox().height-(m?n/2:0)||0,L=h.select(".members-group").node().getBBox().height-(m?n/2:0)||0;if(o.members.length>0||o.methods.length>0||m){const t=y.line(T.x,M+B+w+n,T.x+T.width,M+B+w+n,x);h.insert((()=>t)).attr("class","divider").attr("style",g)}if(m||o.members.length>0||o.methods.length>0){const t=y.line(T.x,M+B+L+w+2*i+n,T.x+T.width,M+B+L+w+n+2*i,x);h.insert((()=>t)).attr("class","divider").attr("style",g)}if("handDrawn"!==o.look&&h.selectAll("path").attr("style",g),v.select(":nth-child(2)").attr("style",g),h.selectAll(".divider").select("path").attr("style",g),e.labelStyle?h.selectAll("span").attr("style",e.labelStyle):h.selectAll("span").attr("style",g),!a){const t=RegExp(/color\s*:\s*([^;]*)/),e=t.exec(g);if(e){const t=e[0].replace("color","fill");h.selectAll("tspan").attr("style",t)}else if(p){const e=t.exec(p);if(e){const t=e[0].replace("color","fill");h.selectAll("tspan").attr("style",t)}}}return d(e,v),e.intersect=function(t){return H.rect(e,t)},h}(0,s.K2)(ae,"tiltedCylinder"),(0,s.K2)(oe,"trapezoid"),(0,s.K2)(se,"trapezoidalPentagon"),(0,s.K2)(le,"triangle"),(0,s.K2)(ce,"waveEdgedRectangle"),(0,s.K2)(he,"waveRectangle"),(0,s.K2)(ue,"windowPane"),(0,s.K2)(de,"textHelper"),(0,s.K2)(pe,"addText"),(0,s.K2)(fe,"classBox");var ge=(0,s.K2)((t=>{switch(t){case"Very High":return"red";case"High":return"orange";case"Medium":return null;case"Low":return"blue";case"Very Low":return"lightblue"}}),"colorFromPriority");async function me(t,e,{config:r}){const{labelStyles:n,nodeStyles:i}=S(e);e.labelStyle=n||"";const a=e.width;e.width=(e.width??200)-10;const{shapeSvg:o,bbox:s,label:l}=await h(t,e,p(e)),f=e.padding||10;let g,m="";"ticket"in e&&e.ticket&&r?.kanban?.ticketBaseUrl&&(m=r?.kanban?.ticketBaseUrl.replace("#TICKET#",e.ticket),g=o.insert("svg:a",":first-child").attr("class","kanban-ticket-link").attr("xlink:href",m).attr("target","_blank"));const y={useHtmlLabels:e.useHtmlLabels,labelStyle:e.labelStyle||"",width:e.width,img:e.img,padding:e.padding||8,centerLabel:!1};let x,b;({label:x,bbox:b}=g?await u(g,"ticket"in e&&e.ticket||"",y):await u(o,"ticket"in e&&e.ticket||"",y));const{label:k,bbox:w}=await u(o,"assigned"in e&&e.assigned||"",y);e.width=a;const _=e?.width||0,v=Math.max(b.height,w.height)/2,T=Math.max(s.height+20,e?.height||0)+v,M=-_/2,B=-T/2;let L;l.attr("transform","translate("+(f-_/2)+", "+(-v-s.height/2)+")"),x.attr("transform","translate("+(f-_/2)+", "+(-v+s.height/2)+")"),k.attr("transform","translate("+(f+_/2-w.width-20)+", "+(-v+s.height/2)+")");const{rx:F,ry:$}=e,{cssStyles:E}=e;if("handDrawn"===e.look){const t=c.A.svg(o),r=A(e,{}),n=F||$?t.path(C(M,B,_,T,F||0),r):t.rectangle(M,B,_,T,r);L=o.insert((()=>n),":first-child"),L.attr("class","basic label-container").attr("style",E||null)}else{L=o.insert("rect",":first-child"),L.attr("class","basic label-container __APA__").attr("style",i).attr("rx",F??5).attr("ry",$??5).attr("x",M).attr("y",B).attr("width",_).attr("height",T);const t="priority"in e&&e.priority;if(t){const e=o.append("line"),r=M+2,n=B+Math.floor((F??0)/2),i=B+T-Math.floor((F??0)/2);e.attr("x1",r).attr("y1",n).attr("x2",r).attr("y2",i).attr("stroke-width","4").attr("stroke",ge(t))}}return d(e,L),e.height=T,e.intersect=function(t){return H.rect(e,t)},o}(0,s.K2)(me,"kanbanItem");var ye=[{semanticName:"Process",name:"Rectangle",shortName:"rect",description:"Standard process shape",aliases:["proc","process","rectangle"],internalAliases:["squareRect"],handler:Yt},{semanticName:"Event",name:"Rounded Rectangle",shortName:"rounded",description:"Represents an event",aliases:["event"],internalAliases:["roundedRect"],handler:Wt},{semanticName:"Terminal Point",name:"Stadium",shortName:"stadium",description:"Terminal point",aliases:["terminal","pill"],handler:Vt},{semanticName:"Subprocess",name:"Framed Rectangle",shortName:"fr-rect",description:"Subprocess",aliases:["subprocess","subproc","framed-rectangle","subroutine"],handler:Qt},{semanticName:"Database",name:"Cylinder",shortName:"cyl",description:"Database storage",aliases:["db","database","cylinder"],handler:ut},{semanticName:"Start",name:"Circle",shortName:"circle",description:"Starting point",aliases:["circ"],handler:Q},{semanticName:"Decision",name:"Diamond",shortName:"diam",description:"Decision-making step",aliases:["decision","diamond","question"],handler:zt},{semanticName:"Prepare Conditional",name:"Hexagon",shortName:"hex",description:"Preparation or condition step",aliases:["hexagon","prepare"],handler:bt},{semanticName:"Data Input/Output",name:"Lean Right",shortName:"lean-r",description:"Represents input or output",aliases:["lean-right","in-out"],internalAliases:["lean_right"],handler:Lt},{semanticName:"Data Input/Output",name:"Lean Left",shortName:"lean-l",description:"Represents output or input",aliases:["lean-left","out-in"],internalAliases:["lean_left"],handler:Bt},{semanticName:"Priority Action",name:"Trapezoid Base Bottom",shortName:"trap-b",description:"Priority action",aliases:["priority","trapezoid-bottom","trapezoid"],handler:oe},{semanticName:"Manual Operation",name:"Trapezoid Base Top",shortName:"trap-t",description:"Represents a manual task",aliases:["manual","trapezoid-top","inv-trapezoid"],internalAliases:["inv_trapezoid"],handler:At},{semanticName:"Stop",name:"Double Circle",shortName:"dbl-circ",description:"Represents a stop point",aliases:["double-circle"],internalAliases:["doublecircle"],handler:pt},{semanticName:"Text Block",name:"Text Block",shortName:"text",description:"Text block",handler:ee},{semanticName:"Card",name:"Notched Rectangle",shortName:"notch-rect",description:"Represents a card",aliases:["card","notched-rectangle"],handler:Z},{semanticName:"Lined/Shaded Process",name:"Lined Rectangle",shortName:"lin-rect",description:"Lined process shape",aliases:["lined-rectangle","lined-process","lin-proc","shaded-process"],handler:Ht},{semanticName:"Start",name:"Small Circle",shortName:"sm-circ",description:"Small starting point",aliases:["start","small-circle"],internalAliases:["stateStart"],handler:Xt},{semanticName:"Stop",name:"Framed Circle",shortName:"fr-circ",description:"Stop point",aliases:["stop","framed-circle"],internalAliases:["stateEnd"],handler:Zt},{semanticName:"Fork/Join",name:"Filled Rectangle",shortName:"fork",description:"Fork or join in process flow",aliases:["join"],internalAliases:["forkJoin"],handler:mt},{semanticName:"Collate",name:"Hourglass",shortName:"hourglass",description:"Represents a collate operation",aliases:["hourglass","collate"],handler:kt},{semanticName:"Comment",name:"Curly Brace",shortName:"brace",description:"Adds a comment",aliases:["comment","brace-l"],handler:rt},{semanticName:"Comment Right",name:"Curly Brace",shortName:"brace-r",description:"Adds a comment",handler:it},{semanticName:"Comment with braces on both sides",name:"Curly Braces",shortName:"braces",description:"Adds a comment",handler:ot},{semanticName:"Com Link",name:"Lightning Bolt",shortName:"bolt",description:"Communication link",aliases:["com-link","lightning-bolt"],handler:Ft},{semanticName:"Document",name:"Document",shortName:"doc",description:"Represents a document",aliases:["doc","document"],handler:ce},{semanticName:"Delay",name:"Half-Rounded Rectangle",shortName:"delay",description:"Represents a delay",aliases:["half-rounded-rectangle"],handler:yt},{semanticName:"Direct Access Storage",name:"Horizontal Cylinder",shortName:"h-cyl",description:"Direct access storage",aliases:["das","horizontal-cylinder"],handler:ae},{semanticName:"Disk Storage",name:"Lined Cylinder",shortName:"lin-cyl",description:"Disk storage",aliases:["disk","lined-cylinder"],handler:Dt},{semanticName:"Display",name:"Curved Trapezoid",shortName:"curv-trap",description:"Represents a display",aliases:["curved-trapezoid","display"],handler:st},{semanticName:"Divided Process",name:"Divided Rectangle",shortName:"div-rect",description:"Divided process shape",aliases:["div-proc","divided-rectangle","divided-process"],handler:dt},{semanticName:"Extract",name:"Triangle",shortName:"tri",description:"Extraction process",aliases:["extract","triangle"],handler:le},{semanticName:"Internal Storage",name:"Window Pane",shortName:"win-pane",description:"Internal storage",aliases:["internal-storage","window-pane"],handler:ue},{semanticName:"Junction",name:"Filled Circle",shortName:"f-circ",description:"Junction point",aliases:["junction","filled-circle"],handler:ft},{semanticName:"Loop Limit",name:"Trapezoidal Pentagon",shortName:"notch-pent",description:"Loop limit step",aliases:["loop-limit","notched-pentagon"],handler:se},{semanticName:"Manual File",name:"Flipped Triangle",shortName:"flip-tri",description:"Manual file operation",aliases:["manual-file","flipped-triangle"],handler:gt},{semanticName:"Manual Input",name:"Sloped Rectangle",shortName:"sl-rect",description:"Manual input step",aliases:["manual-input","sloped-rectangle"],handler:Ut},{semanticName:"Multi-Document",name:"Stacked Document",shortName:"docs",description:"Multiple documents",aliases:["documents","st-doc","stacked-document"],handler:Ot},{semanticName:"Multi-Process",name:"Stacked Rectangle",shortName:"st-rect",description:"Multiple processes",aliases:["procs","processes","stacked-rectangle"],handler:It},{semanticName:"Stored Data",name:"Bow Tie Rectangle",shortName:"bow-rect",description:"Stored data",aliases:["stored-data","bow-tie-rectangle"],handler:V},{semanticName:"Summary",name:"Crossed Circle",shortName:"cross-circ",description:"Summary",aliases:["summary","crossed-circle"],handler:tt},{semanticName:"Tagged Document",name:"Tagged Document",shortName:"tag-doc",description:"Tagged document",aliases:["tag-doc","tagged-document"],handler:te},{semanticName:"Tagged Process",name:"Tagged Rectangle",shortName:"tag-rect",description:"Tagged process",aliases:["tagged-rectangle","tag-proc","tagged-process"],handler:Jt},{semanticName:"Paper Tape",name:"Flag",shortName:"flag",description:"Paper tape",aliases:["paper-tape"],handler:he},{semanticName:"Odd",name:"Odd",shortName:"odd",description:"Odd shape",internalAliases:["rect_left_inv_arrow"],handler:Kt},{semanticName:"Lined Document",name:"Lined Document",shortName:"lin-doc",description:"Lined document",aliases:["lined-document"],handler:jt}],xe=(0,s.K2)((()=>{const t={state:Gt,choice:X,note:Rt,rectWithTitle:qt,labelRect:Mt,iconSquare:vt,iconCircle:wt,icon:Ct,iconRounded:_t,imageSquare:St,anchor:U,kanbanItem:me,classBox:fe},e=[...Object.entries(t),...ye.flatMap((t=>[t.shortName,..."aliases"in t?t.aliases:[],..."internalAliases"in t?t.internalAliases:[]].map((e=>[e,t.handler]))))];return Object.fromEntries(e)}),"generateShapeMap")();function be(t){return t in xe}(0,s.K2)(be,"isValidShape");var ke=new Map;async function Ce(t,e,r){let n,i;"rect"===e.shape&&(e.rx&&e.ry?e.shape="roundedRect":e.shape="squareRect");const a=e.shape?xe[e.shape]:void 0;if(!a)throw new Error(`No such shape: ${e.shape}. Please check your syntax.`);if(e.link){let o;"sandbox"===r.config.securityLevel?o="_top":e.linkTarget&&(o=e.linkTarget||"_blank"),n=t.insert("svg:a").attr("xlink:href",e.link).attr("target",o??null),i=await a(n,e,r)}else i=await a(t,e,r),n=i;return e.tooltip&&i.attr("title",e.tooltip),ke.set(e.id,n),e.haveCallback&&n.attr("class",n.attr("class")+" clickable"),n}(0,s.K2)(Ce,"insertNode");var we=(0,s.K2)(((t,e)=>{ke.set(e.id,t)}),"setNodeElem"),_e=(0,s.K2)((()=>{ke.clear()}),"clear"),ve=(0,s.K2)((t=>{const e=ke.get(t.id);s.Rm.trace("Transforming node",t.diff,t,"translate("+(t.x-t.width/2-5)+", "+t.width/2+")");const r=t.diff||0;return t.clusterNode?e.attr("transform","translate("+(t.x+r-t.width/2)+", "+(t.y-t.height/2-8)+")"):e.attr("transform","translate("+t.x+", "+t.y+")"),r}),"positionNode")},87308:(t,e,r)=>{"use strict";r.d(e,{XX:()=>h,q7:()=>u,sO:()=>c});var n=r(37938),i=r(1282),a=r(8159),o=r(10009),s={common:o.Y2,getConfig:o.zj,insertCluster:i.U,insertEdge:n.Jo,insertEdgeLabel:n.jP,insertMarkers:n.g0,insertNode:i.on,interpolateToCurve:a.Ib,labelHelper:i.Zk,log:o.Rm,positionEdgeLabel:n.T_},l={},c=(0,o.K2)((t=>{for(const e of t)l[e.name]=e}),"registerLayoutLoaders");(0,o.K2)((()=>{c([{name:"dagre",loader:(0,o.K2)((async()=>await Promise.all([r.e(3624),r.e(2334),r.e(4492)]).then(r.bind(r,84492))),"loader")}])}),"registerDefaultLayoutLoaders")();var h=(0,o.K2)((async(t,e)=>{if(!(t.layoutAlgorithm in l))throw new Error(`Unknown layout algorithm: ${t.layoutAlgorithm}`);const r=l[t.layoutAlgorithm];return(await r.loader()).render(t,e,s,{algorithm:r.algorithm})}),"render"),u=(0,o.K2)(((t="",{fallback:e="dagre"}={})=>{if(t in l)return t;if(e in l)return o.Rm.warn(`Layout algorithm ${t} is not registered. Using ${e} as fallback.`),e;throw new Error(`Both layout algorithms ${t} and ${e} are not registered.`)}),"getRegisteredLayoutAlgorithm")},77286:(t,e,r)=>{"use strict";r.d(e,{D:()=>a});var n=r(10009),i=r(20007),a=(0,n.K2)((t=>{const{securityLevel:e}=(0,n.D7)();let r=(0,i.Ltv)("body");if("sandbox"===e){const e=(0,i.Ltv)(`#i${t}`),n=e.node()?.contentDocument??document;r=(0,i.Ltv)(n.body)}return r.select(`#${t}`)}),"selectSvgElement")},6144:(t,e,r)=>{"use strict";r.d(e,{r:()=>n});var n="11.4.1"},64532:(t,e,r)=>{"use strict";r.d(e,{WY:()=>A,pC:()=>v,Gc:()=>C});var n=r(10009);const i=/^[a-z0-9]+(-[a-z0-9]+)*$/,a=(t,e)=>!!t&&!(""!==t.provider&&!t.provider.match(i)||!(e&&""===t.prefix||t.prefix.match(i))||!t.name.match(i)),o=Object.freeze({left:0,top:0,width:16,height:16}),s=Object.freeze({rotate:0,vFlip:!1,hFlip:!1}),l=Object.freeze({...o,...s}),c=Object.freeze({...l,body:"",hidden:!1});function h(t,e){const r=function(t,e){const r={};!t.hFlip!=!e.hFlip&&(r.hFlip=!0),!t.vFlip!=!e.vFlip&&(r.vFlip=!0);const n=((t.rotate||0)+(e.rotate||0))%4;return n&&(r.rotate=n),r}(t,e);for(const n in c)n in s?n in t&&!(n in r)&&(r[n]=s[n]):n in e?r[n]=e[n]:n in t&&(r[n]=t[n]);return r}function u(t,e,r){const n=t.icons,i=t.aliases||Object.create(null);let a={};function o(t){a=h(n[t]||i[t],a)}return o(e),r.forEach(o),h(t,a)}function d(t,e){if(t.icons[e])return u(t,e,[]);const r=function(t,e){const r=t.icons,n=t.aliases||Object.create(null),i=Object.create(null);return(e||Object.keys(r).concat(Object.keys(n))).forEach((function t(e){if(r[e])return i[e]=[];if(!(e in i)){i[e]=null;const r=n[e]&&n[e].parent,a=r&&t(r);a&&(i[e]=[r].concat(a))}return i[e]})),i}(t,[e])[e];return r?u(t,e,r):null}const p=Object.freeze({width:null,height:null}),f=Object.freeze({...p,...s}),g=/(-?[0-9.]*[0-9]+[0-9.]*)/g,m=/^-?[0-9.]*[0-9]+[0-9.]*$/g;function y(t,e,r){if(1===e)return t;if(r=r||100,"number"==typeof t)return Math.ceil(t*e*r)/r;if("string"!=typeof t)return t;const n=t.split(g);if(null===n||!n.length)return t;const i=[];let a=n.shift(),o=m.test(a);for(;;){if(o){const t=parseFloat(a);isNaN(t)?i.push(a):i.push(Math.ceil(t*e*r)/r)}else i.push(a);if(a=n.shift(),void 0===a)return i.join("");o=!o}}const x=/\sid="(\S+)"/g,b="IconifyId"+Date.now().toString(16)+(16777216*Math.random()|0).toString(16);let k=0;var C={body:'<g><rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/><text transform="translate(21.16 64.67)" style="fill: #fff; font-family: ArialMT, Arial; font-size: 67.75px;"><tspan x="0" y="0">?</tspan></text></g>',height:80,width:80},w=new Map,_=new Map,v=(0,n.K2)((t=>{for(const e of t){if(!e.name)throw new Error('Invalid icon loader. Must have a "name" property with non-empty string value.');if(n.Rm.debug("Registering icon pack:",e.name),"loader"in e)_.set(e.name,e.loader);else{if(!("icons"in e))throw n.Rm.error("Invalid icon loader:",e),new Error('Invalid icon loader. Must have either "icons" or "loader" property.');w.set(e.name,e.icons)}}}),"registerIconPacks"),S=(0,n.K2)((async(t,e)=>{const r=((t,e,r,n="")=>{const i=t.split(":");if("@"===t.slice(0,1)){if(i.length<2||i.length>3)return null;n=i.shift().slice(1)}if(i.length>3||!i.length)return null;if(i.length>1){const t=i.pop(),r=i.pop(),o={provider:i.length>0?i[0]:n,prefix:r,name:t};return e&&!a(o)?null:o}const o=i[0],s=o.split("-");if(s.length>1){const t={provider:n,prefix:s.shift(),name:s.join("-")};return e&&!a(t)?null:t}if(r&&""===n){const t={provider:n,prefix:"",name:o};return e&&!a(t,r)?null:t}return null})(t,!0,void 0!==e);if(!r)throw new Error(`Invalid icon name: ${t}`);const i=r.prefix||e;if(!i)throw new Error(`Icon name must contain a prefix: ${t}`);let o=w.get(i);if(!o){const t=_.get(i);if(!t)throw new Error(`Icon set not found: ${r.prefix}`);try{o={...await t(),prefix:i},w.set(i,o)}catch(l){throw n.Rm.error(l),new Error(`Failed to load icon set: ${r.prefix}`)}}const s=d(o,r.name);if(!s)throw new Error(`Icon not found: ${t}`);return s}),"getRegisteredIconData"),A=(0,n.K2)((async(t,e)=>{let r;try{r=await S(t,e?.fallbackPrefix)}catch(a){n.Rm.error(a),r=C}const i=function(t,e){const r={...l,...t},n={...f,...e},i={left:r.left,top:r.top,width:r.width,height:r.height};let a=r.body;[r,n].forEach((t=>{const e=[],r=t.hFlip,n=t.vFlip;let o,s=t.rotate;switch(r?n?s+=2:(e.push("translate("+(i.width+i.left).toString()+" "+(0-i.top).toString()+")"),e.push("scale(-1 1)"),i.top=i.left=0):n&&(e.push("translate("+(0-i.left).toString()+" "+(i.height+i.top).toString()+")"),e.push("scale(1 -1)"),i.top=i.left=0),s<0&&(s-=4*Math.floor(s/4)),s%=4,s){case 1:o=i.height/2+i.top,e.unshift("rotate(90 "+o.toString()+" "+o.toString()+")");break;case 2:e.unshift("rotate(180 "+(i.width/2+i.left).toString()+" "+(i.height/2+i.top).toString()+")");break;case 3:o=i.width/2+i.left,e.unshift("rotate(-90 "+o.toString()+" "+o.toString()+")")}s%2==1&&(i.left!==i.top&&(o=i.left,i.left=i.top,i.top=o),i.width!==i.height&&(o=i.width,i.width=i.height,i.height=o)),e.length&&(a=function(t,e,r){const n=function(t,e="defs"){let r="";const n=t.indexOf("<"+e);for(;n>=0;){const i=t.indexOf(">",n),a=t.indexOf("</"+e);if(-1===i||-1===a)break;const o=t.indexOf(">",a);if(-1===o)break;r+=t.slice(i+1,a).trim(),t=t.slice(0,n).trim()+t.slice(o+1)}return{defs:r,content:t}}(t);return i=n.defs,a=e+n.content+r,i?"<defs>"+i+"</defs>"+a:a;var i,a}(a,'<g transform="'+e.join(" ")+'">',"</g>"))}));const o=n.width,s=n.height,c=i.width,h=i.height;let u,d;null===o?(d=null===s?"1em":"auto"===s?h:s,u=y(d,c/h)):(u="auto"===o?c:o,d=null===s?y(u,h/c):"auto"===s?h:s);const p={},g=(t,e)=>{(t=>"unset"===t||"undefined"===t||"none"===t)(e)||(p[t]=e.toString())};g("width",u),g("height",d);const m=[i.left,i.top,c,h];return p.viewBox=m.join(" "),{attributes:p,viewBox:m,body:a}}(r,e);return function(t,e){let r=-1===t.indexOf("xlink:")?"":' xmlns:xlink="http://www.w3.org/1999/xlink"';for(const n in e)r+=" "+n+'="'+e[n]+'"';return'<svg xmlns="http://www.w3.org/2000/svg"'+r+">"+t+"</svg>"}(function(t,e=b){const r=[];let n;for(;n=x.exec(t);)r.push(n[1]);if(!r.length)return t;const i="suffix"+(16777216*Math.random()|Date.now()).toString(16);return r.forEach((r=>{const n="function"==typeof e?e(r):e+(k++).toString(),a=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");t=t.replace(new RegExp('([#;"])('+a+')([")]|\\.[a-z])',"g"),"$1"+n+i+"$3")})),t=t.replace(new RegExp(i,"g"),"")}(i.body),i.attributes)}),"getIconSVG")},59874:(t,e,r)=>{"use strict";r.d(e,{H:()=>rr,r:()=>er});var n=r(10009);function i(t){return null==t}function a(t){return"object"==typeof t&&null!==t}function o(t){return Array.isArray(t)?t:i(t)?[]:[t]}function s(t,e){var r,n,i,a;if(e)for(r=0,n=(a=Object.keys(e)).length;r<n;r+=1)t[i=a[r]]=e[i];return t}function l(t,e){var r,n="";for(r=0;r<e;r+=1)n+=t;return n}function c(t){return 0===t&&Number.NEGATIVE_INFINITY===1/t}(0,n.K2)(i,"isNothing"),(0,n.K2)(a,"isObject"),(0,n.K2)(o,"toArray"),(0,n.K2)(s,"extend"),(0,n.K2)(l,"repeat"),(0,n.K2)(c,"isNegativeZero");var h={isNothing:i,isObject:a,toArray:o,repeat:l,isNegativeZero:c,extend:s};function u(t,e){var r="",n=t.reason||"(unknown reason)";return t.mark?(t.mark.name&&(r+='in "'+t.mark.name+'" '),r+="("+(t.mark.line+1)+":"+(t.mark.column+1)+")",!e&&t.mark.snippet&&(r+="\n\n"+t.mark.snippet),n+" "+r):n}function d(t,e){Error.call(this),this.name="YAMLException",this.reason=t,this.mark=e,this.message=u(this,!1),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}(0,n.K2)(u,"formatError"),(0,n.K2)(d,"YAMLException$1"),d.prototype=Object.create(Error.prototype),d.prototype.constructor=d,d.prototype.toString=(0,n.K2)((function(t){return this.name+": "+u(this,t)}),"toString");var p=d;function f(t,e,r,n,i){var a="",o="",s=Math.floor(i/2)-1;return n-e>s&&(e=n-s+(a=" ... ").length),r-n>s&&(r=n+s-(o=" ...").length),{str:a+t.slice(e,r).replace(/\t/g,"\u2192")+o,pos:n-e+a.length}}function g(t,e){return h.repeat(" ",e-t.length)+t}function m(t,e){if(e=Object.create(e||null),!t.buffer)return null;e.maxLength||(e.maxLength=79),"number"!=typeof e.indent&&(e.indent=1),"number"!=typeof e.linesBefore&&(e.linesBefore=3),"number"!=typeof e.linesAfter&&(e.linesAfter=2);for(var r,n=/\r?\n|\r|\0/g,i=[0],a=[],o=-1;r=n.exec(t.buffer);)a.push(r.index),i.push(r.index+r[0].length),t.position<=r.index&&o<0&&(o=i.length-2);o<0&&(o=i.length-1);var s,l,c="",u=Math.min(t.line+e.linesAfter,a.length).toString().length,d=e.maxLength-(e.indent+u+3);for(s=1;s<=e.linesBefore&&!(o-s<0);s++)l=f(t.buffer,i[o-s],a[o-s],t.position-(i[o]-i[o-s]),d),c=h.repeat(" ",e.indent)+g((t.line-s+1).toString(),u)+" | "+l.str+"\n"+c;for(l=f(t.buffer,i[o],a[o],t.position,d),c+=h.repeat(" ",e.indent)+g((t.line+1).toString(),u)+" | "+l.str+"\n",c+=h.repeat("-",e.indent+u+3+l.pos)+"^\n",s=1;s<=e.linesAfter&&!(o+s>=a.length);s++)l=f(t.buffer,i[o+s],a[o+s],t.position-(i[o]-i[o+s]),d),c+=h.repeat(" ",e.indent)+g((t.line+s+1).toString(),u)+" | "+l.str+"\n";return c.replace(/\n$/,"")}(0,n.K2)(f,"getLine"),(0,n.K2)(g,"padStart"),(0,n.K2)(m,"makeSnippet");var y=m,x=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],b=["scalar","sequence","mapping"];function k(t){var e={};return null!==t&&Object.keys(t).forEach((function(r){t[r].forEach((function(t){e[String(t)]=r}))})),e}function C(t,e){if(e=e||{},Object.keys(e).forEach((function(e){if(-1===x.indexOf(e))throw new p('Unknown option "'+e+'" is met in definition of "'+t+'" YAML type.')})),this.options=e,this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(t){return t},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.representName=e.representName||null,this.defaultStyle=e.defaultStyle||null,this.multi=e.multi||!1,this.styleAliases=k(e.styleAliases||null),-1===b.indexOf(this.kind))throw new p('Unknown kind "'+this.kind+'" is specified for "'+t+'" YAML type.')}(0,n.K2)(k,"compileStyleAliases"),(0,n.K2)(C,"Type$1");var w=C;function _(t,e){var r=[];return t[e].forEach((function(t){var e=r.length;r.forEach((function(r,n){r.tag===t.tag&&r.kind===t.kind&&r.multi===t.multi&&(e=n)})),r[e]=t})),r}function v(){var t,e,r={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(t){t.multi?(r.multi[t.kind].push(t),r.multi.fallback.push(t)):r[t.kind][t.tag]=r.fallback[t.tag]=t}for((0,n.K2)(i,"collectType"),t=0,e=arguments.length;t<e;t+=1)arguments[t].forEach(i);return r}function S(t){return this.extend(t)}(0,n.K2)(_,"compileList"),(0,n.K2)(v,"compileMap"),(0,n.K2)(S,"Schema$1"),S.prototype.extend=(0,n.K2)((function(t){var e=[],r=[];if(t instanceof w)r.push(t);else if(Array.isArray(t))r=r.concat(t);else{if(!t||!Array.isArray(t.implicit)&&!Array.isArray(t.explicit))throw new p("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");t.implicit&&(e=e.concat(t.implicit)),t.explicit&&(r=r.concat(t.explicit))}e.forEach((function(t){if(!(t instanceof w))throw new p("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(t.loadKind&&"scalar"!==t.loadKind)throw new p("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(t.multi)throw new p("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),r.forEach((function(t){if(!(t instanceof w))throw new p("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var n=Object.create(S.prototype);return n.implicit=(this.implicit||[]).concat(e),n.explicit=(this.explicit||[]).concat(r),n.compiledImplicit=_(n,"implicit"),n.compiledExplicit=_(n,"explicit"),n.compiledTypeMap=v(n.compiledImplicit,n.compiledExplicit),n}),"extend");var A=new S({explicit:[new w("tag:yaml.org,2002:str",{kind:"scalar",construct:(0,n.K2)((function(t){return null!==t?t:""}),"construct")}),new w("tag:yaml.org,2002:seq",{kind:"sequence",construct:(0,n.K2)((function(t){return null!==t?t:[]}),"construct")}),new w("tag:yaml.org,2002:map",{kind:"mapping",construct:(0,n.K2)((function(t){return null!==t?t:{}}),"construct")})]});function T(t){if(null===t)return!0;var e=t.length;return 1===e&&"~"===t||4===e&&("null"===t||"Null"===t||"NULL"===t)}function M(){return null}function B(t){return null===t}(0,n.K2)(T,"resolveYamlNull"),(0,n.K2)(M,"constructYamlNull"),(0,n.K2)(B,"isNull");var L=new w("tag:yaml.org,2002:null",{kind:"scalar",resolve:T,construct:M,predicate:B,represent:{canonical:(0,n.K2)((function(){return"~"}),"canonical"),lowercase:(0,n.K2)((function(){return"null"}),"lowercase"),uppercase:(0,n.K2)((function(){return"NULL"}),"uppercase"),camelcase:(0,n.K2)((function(){return"Null"}),"camelcase"),empty:(0,n.K2)((function(){return""}),"empty")},defaultStyle:"lowercase"});function F(t){if(null===t)return!1;var e=t.length;return 4===e&&("true"===t||"True"===t||"TRUE"===t)||5===e&&("false"===t||"False"===t||"FALSE"===t)}function $(t){return"true"===t||"True"===t||"TRUE"===t}function E(t){return"[object Boolean]"===Object.prototype.toString.call(t)}(0,n.K2)(F,"resolveYamlBoolean"),(0,n.K2)($,"constructYamlBoolean"),(0,n.K2)(E,"isBoolean");var N=new w("tag:yaml.org,2002:bool",{kind:"scalar",resolve:F,construct:$,predicate:E,represent:{lowercase:(0,n.K2)((function(t){return t?"true":"false"}),"lowercase"),uppercase:(0,n.K2)((function(t){return t?"TRUE":"FALSE"}),"uppercase"),camelcase:(0,n.K2)((function(t){return t?"True":"False"}),"camelcase")},defaultStyle:"lowercase"});function D(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function j(t){return 48<=t&&t<=55}function I(t){return 48<=t&&t<=57}function O(t){if(null===t)return!1;var e,r=t.length,n=0,i=!1;if(!r)return!1;if("-"!==(e=t[n])&&"+"!==e||(e=t[++n]),"0"===e){if(n+1===r)return!0;if("b"===(e=t[++n])){for(n++;n<r;n++)if("_"!==(e=t[n])){if("0"!==e&&"1"!==e)return!1;i=!0}return i&&"_"!==e}if("x"===e){for(n++;n<r;n++)if("_"!==(e=t[n])){if(!D(t.charCodeAt(n)))return!1;i=!0}return i&&"_"!==e}if("o"===e){for(n++;n<r;n++)if("_"!==(e=t[n])){if(!j(t.charCodeAt(n)))return!1;i=!0}return i&&"_"!==e}}if("_"===e)return!1;for(;n<r;n++)if("_"!==(e=t[n])){if(!I(t.charCodeAt(n)))return!1;i=!0}return!(!i||"_"===e)}function R(t){var e,r=t,n=1;if(-1!==r.indexOf("_")&&(r=r.replace(/_/g,"")),"-"!==(e=r[0])&&"+"!==e||("-"===e&&(n=-1),e=(r=r.slice(1))[0]),"0"===r)return 0;if("0"===e){if("b"===r[1])return n*parseInt(r.slice(2),2);if("x"===r[1])return n*parseInt(r.slice(2),16);if("o"===r[1])return n*parseInt(r.slice(2),8)}return n*parseInt(r,10)}function P(t){return"[object Number]"===Object.prototype.toString.call(t)&&t%1==0&&!h.isNegativeZero(t)}(0,n.K2)(D,"isHexCode"),(0,n.K2)(j,"isOctCode"),(0,n.K2)(I,"isDecCode"),(0,n.K2)(O,"resolveYamlInteger"),(0,n.K2)(R,"constructYamlInteger"),(0,n.K2)(P,"isInteger");var z=new w("tag:yaml.org,2002:int",{kind:"scalar",resolve:O,construct:R,predicate:P,represent:{binary:(0,n.K2)((function(t){return t>=0?"0b"+t.toString(2):"-0b"+t.toString(2).slice(1)}),"binary"),octal:(0,n.K2)((function(t){return t>=0?"0o"+t.toString(8):"-0o"+t.toString(8).slice(1)}),"octal"),decimal:(0,n.K2)((function(t){return t.toString(10)}),"decimal"),hexadecimal:(0,n.K2)((function(t){return t>=0?"0x"+t.toString(16).toUpperCase():"-0x"+t.toString(16).toUpperCase().slice(1)}),"hexadecimal")},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),K=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function q(t){return null!==t&&!(!K.test(t)||"_"===t[t.length-1])}function W(t){var e,r;return r="-"===(e=t.replace(/_/g,"").toLowerCase())[0]?-1:1,"+-".indexOf(e[0])>=0&&(e=e.slice(1)),".inf"===e?1===r?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===e?NaN:r*parseFloat(e,10)}(0,n.K2)(q,"resolveYamlFloat"),(0,n.K2)(W,"constructYamlFloat");var H=/^[-+]?[0-9]+e/;function U(t,e){var r;if(isNaN(t))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===t)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(h.isNegativeZero(t))return"-0.0";return r=t.toString(10),H.test(r)?r.replace("e",".e"):r}function Y(t){return"[object Number]"===Object.prototype.toString.call(t)&&(t%1!=0||h.isNegativeZero(t))}(0,n.K2)(U,"representYamlFloat"),(0,n.K2)(Y,"isFloat");var V=new w("tag:yaml.org,2002:float",{kind:"scalar",resolve:q,construct:W,predicate:Y,represent:U,defaultStyle:"lowercase"}),G=A.extend({implicit:[L,N,z,V]}),Z=G,X=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),Q=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function J(t){return null!==t&&(null!==X.exec(t)||null!==Q.exec(t))}function tt(t){var e,r,n,i,a,o,s,l,c=0,h=null;if(null===(e=X.exec(t))&&(e=Q.exec(t)),null===e)throw new Error("Date resolve error");if(r=+e[1],n=+e[2]-1,i=+e[3],!e[4])return new Date(Date.UTC(r,n,i));if(a=+e[4],o=+e[5],s=+e[6],e[7]){for(c=e[7].slice(0,3);c.length<3;)c+="0";c=+c}return e[9]&&(h=6e4*(60*+e[10]+ +(e[11]||0)),"-"===e[9]&&(h=-h)),l=new Date(Date.UTC(r,n,i,a,o,s,c)),h&&l.setTime(l.getTime()-h),l}function et(t){return t.toISOString()}(0,n.K2)(J,"resolveYamlTimestamp"),(0,n.K2)(tt,"constructYamlTimestamp"),(0,n.K2)(et,"representYamlTimestamp");var rt=new w("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:J,construct:tt,instanceOf:Date,represent:et});function nt(t){return"<<"===t||null===t}(0,n.K2)(nt,"resolveYamlMerge");var it=new w("tag:yaml.org,2002:merge",{kind:"scalar",resolve:nt}),at="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";function ot(t){if(null===t)return!1;var e,r,n=0,i=t.length,a=at;for(r=0;r<i;r++)if(!((e=a.indexOf(t.charAt(r)))>64)){if(e<0)return!1;n+=6}return n%8==0}function st(t){var e,r,n=t.replace(/[\r\n=]/g,""),i=n.length,a=at,o=0,s=[];for(e=0;e<i;e++)e%4==0&&e&&(s.push(o>>16&255),s.push(o>>8&255),s.push(255&o)),o=o<<6|a.indexOf(n.charAt(e));return 0===(r=i%4*6)?(s.push(o>>16&255),s.push(o>>8&255),s.push(255&o)):18===r?(s.push(o>>10&255),s.push(o>>2&255)):12===r&&s.push(o>>4&255),new Uint8Array(s)}function lt(t){var e,r,n="",i=0,a=t.length,o=at;for(e=0;e<a;e++)e%3==0&&e&&(n+=o[i>>18&63],n+=o[i>>12&63],n+=o[i>>6&63],n+=o[63&i]),i=(i<<8)+t[e];return 0===(r=a%3)?(n+=o[i>>18&63],n+=o[i>>12&63],n+=o[i>>6&63],n+=o[63&i]):2===r?(n+=o[i>>10&63],n+=o[i>>4&63],n+=o[i<<2&63],n+=o[64]):1===r&&(n+=o[i>>2&63],n+=o[i<<4&63],n+=o[64],n+=o[64]),n}function ct(t){return"[object Uint8Array]"===Object.prototype.toString.call(t)}(0,n.K2)(ot,"resolveYamlBinary"),(0,n.K2)(st,"constructYamlBinary"),(0,n.K2)(lt,"representYamlBinary"),(0,n.K2)(ct,"isBinary");var ht=new w("tag:yaml.org,2002:binary",{kind:"scalar",resolve:ot,construct:st,predicate:ct,represent:lt}),ut=Object.prototype.hasOwnProperty,dt=Object.prototype.toString;function pt(t){if(null===t)return!0;var e,r,n,i,a,o=[],s=t;for(e=0,r=s.length;e<r;e+=1){if(n=s[e],a=!1,"[object Object]"!==dt.call(n))return!1;for(i in n)if(ut.call(n,i)){if(a)return!1;a=!0}if(!a)return!1;if(-1!==o.indexOf(i))return!1;o.push(i)}return!0}function ft(t){return null!==t?t:[]}(0,n.K2)(pt,"resolveYamlOmap"),(0,n.K2)(ft,"constructYamlOmap");var gt=new w("tag:yaml.org,2002:omap",{kind:"sequence",resolve:pt,construct:ft}),mt=Object.prototype.toString;function yt(t){if(null===t)return!0;var e,r,n,i,a,o=t;for(a=new Array(o.length),e=0,r=o.length;e<r;e+=1){if(n=o[e],"[object Object]"!==mt.call(n))return!1;if(1!==(i=Object.keys(n)).length)return!1;a[e]=[i[0],n[i[0]]]}return!0}function xt(t){if(null===t)return[];var e,r,n,i,a,o=t;for(a=new Array(o.length),e=0,r=o.length;e<r;e+=1)n=o[e],i=Object.keys(n),a[e]=[i[0],n[i[0]]];return a}(0,n.K2)(yt,"resolveYamlPairs"),(0,n.K2)(xt,"constructYamlPairs");var bt=new w("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:yt,construct:xt}),kt=Object.prototype.hasOwnProperty;function Ct(t){if(null===t)return!0;var e,r=t;for(e in r)if(kt.call(r,e)&&null!==r[e])return!1;return!0}function wt(t){return null!==t?t:{}}(0,n.K2)(Ct,"resolveYamlSet"),(0,n.K2)(wt,"constructYamlSet");var _t=new w("tag:yaml.org,2002:set",{kind:"mapping",resolve:Ct,construct:wt}),vt=Z.extend({implicit:[rt,it],explicit:[ht,gt,bt,_t]}),St=Object.prototype.hasOwnProperty,At=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,Tt=/[\x85\u2028\u2029]/,Mt=/[,\[\]\{\}]/,Bt=/^(?:!|!!|![a-z\-]+!)$/i,Lt=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function Ft(t){return Object.prototype.toString.call(t)}function $t(t){return 10===t||13===t}function Et(t){return 9===t||32===t}function Nt(t){return 9===t||32===t||10===t||13===t}function Dt(t){return 44===t||91===t||93===t||123===t||125===t}function jt(t){var e;return 48<=t&&t<=57?t-48:97<=(e=32|t)&&e<=102?e-97+10:-1}function It(t){return 120===t?2:117===t?4:85===t?8:0}function Ot(t){return 48<=t&&t<=57?t-48:-1}function Rt(t){return 48===t?"\0":97===t?"\x07":98===t?"\b":116===t||9===t?"\t":110===t?"\n":118===t?"\v":102===t?"\f":114===t?"\r":101===t?"\x1b":32===t?" ":34===t?'"':47===t?"/":92===t?"\\":78===t?"\x85":95===t?"\xa0":76===t?"\u2028":80===t?"\u2029":""}function Pt(t){return t<=65535?String.fromCharCode(t):String.fromCharCode(55296+(t-65536>>10),56320+(t-65536&1023))}(0,n.K2)(Ft,"_class"),(0,n.K2)($t,"is_EOL"),(0,n.K2)(Et,"is_WHITE_SPACE"),(0,n.K2)(Nt,"is_WS_OR_EOL"),(0,n.K2)(Dt,"is_FLOW_INDICATOR"),(0,n.K2)(jt,"fromHexCode"),(0,n.K2)(It,"escapedHexLen"),(0,n.K2)(Ot,"fromDecimalCode"),(0,n.K2)(Rt,"simpleEscapeSequence"),(0,n.K2)(Pt,"charFromCodepoint");var zt,Kt=new Array(256),qt=new Array(256);for(zt=0;zt<256;zt++)Kt[zt]=Rt(zt)?1:0,qt[zt]=Rt(zt);function Wt(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||vt,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function Ht(t,e){var r={name:t.filename,buffer:t.input.slice(0,-1),position:t.position,line:t.line,column:t.position-t.lineStart};return r.snippet=y(r),new p(e,r)}function Ut(t,e){throw Ht(t,e)}function Yt(t,e){t.onWarning&&t.onWarning.call(null,Ht(t,e))}(0,n.K2)(Wt,"State$1"),(0,n.K2)(Ht,"generateError"),(0,n.K2)(Ut,"throwError"),(0,n.K2)(Yt,"throwWarning");var Vt={YAML:(0,n.K2)((function(t,e,r){var n,i,a;null!==t.version&&Ut(t,"duplication of %YAML directive"),1!==r.length&&Ut(t,"YAML directive accepts exactly one argument"),null===(n=/^([0-9]+)\.([0-9]+)$/.exec(r[0]))&&Ut(t,"ill-formed argument of the YAML directive"),i=parseInt(n[1],10),a=parseInt(n[2],10),1!==i&&Ut(t,"unacceptable YAML version of the document"),t.version=r[0],t.checkLineBreaks=a<2,1!==a&&2!==a&&Yt(t,"unsupported YAML version of the document")}),"handleYamlDirective"),TAG:(0,n.K2)((function(t,e,r){var n,i;2!==r.length&&Ut(t,"TAG directive accepts exactly two arguments"),n=r[0],i=r[1],Bt.test(n)||Ut(t,"ill-formed tag handle (first argument) of the TAG directive"),St.call(t.tagMap,n)&&Ut(t,'there is a previously declared suffix for "'+n+'" tag handle'),Lt.test(i)||Ut(t,"ill-formed tag prefix (second argument) of the TAG directive");try{i=decodeURIComponent(i)}catch(a){Ut(t,"tag prefix is malformed: "+i)}t.tagMap[n]=i}),"handleTagDirective")};function Gt(t,e,r,n){var i,a,o,s;if(e<r){if(s=t.input.slice(e,r),n)for(i=0,a=s.length;i<a;i+=1)9===(o=s.charCodeAt(i))||32<=o&&o<=1114111||Ut(t,"expected valid JSON character");else At.test(s)&&Ut(t,"the stream contains non-printable characters");t.result+=s}}function Zt(t,e,r,n){var i,a,o,s;for(h.isObject(r)||Ut(t,"cannot merge mappings; the provided source object is unacceptable"),o=0,s=(i=Object.keys(r)).length;o<s;o+=1)a=i[o],St.call(e,a)||(e[a]=r[a],n[a]=!0)}function Xt(t,e,r,n,i,a,o,s,l){var c,h;if(Array.isArray(i))for(c=0,h=(i=Array.prototype.slice.call(i)).length;c<h;c+=1)Array.isArray(i[c])&&Ut(t,"nested arrays are not supported inside keys"),"object"==typeof i&&"[object Object]"===Ft(i[c])&&(i[c]="[object Object]");if("object"==typeof i&&"[object Object]"===Ft(i)&&(i="[object Object]"),i=String(i),null===e&&(e={}),"tag:yaml.org,2002:merge"===n)if(Array.isArray(a))for(c=0,h=a.length;c<h;c+=1)Zt(t,e,a[c],r);else Zt(t,e,a,r);else t.json||St.call(r,i)||!St.call(e,i)||(t.line=o||t.line,t.lineStart=s||t.lineStart,t.position=l||t.position,Ut(t,"duplicated mapping key")),"__proto__"===i?Object.defineProperty(e,i,{configurable:!0,enumerable:!0,writable:!0,value:a}):e[i]=a,delete r[i];return e}function Qt(t){var e;10===(e=t.input.charCodeAt(t.position))?t.position++:13===e?(t.position++,10===t.input.charCodeAt(t.position)&&t.position++):Ut(t,"a line break is expected"),t.line+=1,t.lineStart=t.position,t.firstTabInLine=-1}function Jt(t,e,r){for(var n=0,i=t.input.charCodeAt(t.position);0!==i;){for(;Et(i);)9===i&&-1===t.firstTabInLine&&(t.firstTabInLine=t.position),i=t.input.charCodeAt(++t.position);if(e&&35===i)do{i=t.input.charCodeAt(++t.position)}while(10!==i&&13!==i&&0!==i);if(!$t(i))break;for(Qt(t),i=t.input.charCodeAt(t.position),n++,t.lineIndent=0;32===i;)t.lineIndent++,i=t.input.charCodeAt(++t.position)}return-1!==r&&0!==n&&t.lineIndent<r&&Yt(t,"deficient indentation"),n}function te(t){var e,r=t.position;return!(45!==(e=t.input.charCodeAt(r))&&46!==e||e!==t.input.charCodeAt(r+1)||e!==t.input.charCodeAt(r+2)||(r+=3,0!==(e=t.input.charCodeAt(r))&&!Nt(e)))}function ee(t,e){1===e?t.result+=" ":e>1&&(t.result+=h.repeat("\n",e-1))}function re(t,e,r){var n,i,a,o,s,l,c,h,u=t.kind,d=t.result;if(Nt(h=t.input.charCodeAt(t.position))||Dt(h)||35===h||38===h||42===h||33===h||124===h||62===h||39===h||34===h||37===h||64===h||96===h)return!1;if((63===h||45===h)&&(Nt(n=t.input.charCodeAt(t.position+1))||r&&Dt(n)))return!1;for(t.kind="scalar",t.result="",i=a=t.position,o=!1;0!==h;){if(58===h){if(Nt(n=t.input.charCodeAt(t.position+1))||r&&Dt(n))break}else if(35===h){if(Nt(t.input.charCodeAt(t.position-1)))break}else{if(t.position===t.lineStart&&te(t)||r&&Dt(h))break;if($t(h)){if(s=t.line,l=t.lineStart,c=t.lineIndent,Jt(t,!1,-1),t.lineIndent>=e){o=!0,h=t.input.charCodeAt(t.position);continue}t.position=a,t.line=s,t.lineStart=l,t.lineIndent=c;break}}o&&(Gt(t,i,a,!1),ee(t,t.line-s),i=a=t.position,o=!1),Et(h)||(a=t.position+1),h=t.input.charCodeAt(++t.position)}return Gt(t,i,a,!1),!!t.result||(t.kind=u,t.result=d,!1)}function ne(t,e){var r,n,i;if(39!==(r=t.input.charCodeAt(t.position)))return!1;for(t.kind="scalar",t.result="",t.position++,n=i=t.position;0!==(r=t.input.charCodeAt(t.position));)if(39===r){if(Gt(t,n,t.position,!0),39!==(r=t.input.charCodeAt(++t.position)))return!0;n=t.position,t.position++,i=t.position}else $t(r)?(Gt(t,n,i,!0),ee(t,Jt(t,!1,e)),n=i=t.position):t.position===t.lineStart&&te(t)?Ut(t,"unexpected end of the document within a single quoted scalar"):(t.position++,i=t.position);Ut(t,"unexpected end of the stream within a single quoted scalar")}function ie(t,e){var r,n,i,a,o,s;if(34!==(s=t.input.charCodeAt(t.position)))return!1;for(t.kind="scalar",t.result="",t.position++,r=n=t.position;0!==(s=t.input.charCodeAt(t.position));){if(34===s)return Gt(t,r,t.position,!0),t.position++,!0;if(92===s){if(Gt(t,r,t.position,!0),$t(s=t.input.charCodeAt(++t.position)))Jt(t,!1,e);else if(s<256&&Kt[s])t.result+=qt[s],t.position++;else if((o=It(s))>0){for(i=o,a=0;i>0;i--)(o=jt(s=t.input.charCodeAt(++t.position)))>=0?a=(a<<4)+o:Ut(t,"expected hexadecimal character");t.result+=Pt(a),t.position++}else Ut(t,"unknown escape sequence");r=n=t.position}else $t(s)?(Gt(t,r,n,!0),ee(t,Jt(t,!1,e)),r=n=t.position):t.position===t.lineStart&&te(t)?Ut(t,"unexpected end of the document within a double quoted scalar"):(t.position++,n=t.position)}Ut(t,"unexpected end of the stream within a double quoted scalar")}function ae(t,e){var r,n,i,a,o,s,l,c,h,u,d,p,f=!0,g=t.tag,m=t.anchor,y=Object.create(null);if(91===(p=t.input.charCodeAt(t.position)))o=93,c=!1,a=[];else{if(123!==p)return!1;o=125,c=!0,a={}}for(null!==t.anchor&&(t.anchorMap[t.anchor]=a),p=t.input.charCodeAt(++t.position);0!==p;){if(Jt(t,!0,e),(p=t.input.charCodeAt(t.position))===o)return t.position++,t.tag=g,t.anchor=m,t.kind=c?"mapping":"sequence",t.result=a,!0;f?44===p&&Ut(t,"expected the node content, but found ','"):Ut(t,"missed comma between flow collection entries"),d=null,s=l=!1,63===p&&Nt(t.input.charCodeAt(t.position+1))&&(s=l=!0,t.position++,Jt(t,!0,e)),r=t.line,n=t.lineStart,i=t.position,de(t,e,1,!1,!0),u=t.tag,h=t.result,Jt(t,!0,e),p=t.input.charCodeAt(t.position),!l&&t.line!==r||58!==p||(s=!0,p=t.input.charCodeAt(++t.position),Jt(t,!0,e),de(t,e,1,!1,!0),d=t.result),c?Xt(t,a,y,u,h,d,r,n,i):s?a.push(Xt(t,null,y,u,h,d,r,n,i)):a.push(h),Jt(t,!0,e),44===(p=t.input.charCodeAt(t.position))?(f=!0,p=t.input.charCodeAt(++t.position)):f=!1}Ut(t,"unexpected end of the stream within a flow collection")}function oe(t,e){var r,n,i,a,o=1,s=!1,l=!1,c=e,u=0,d=!1;if(124===(a=t.input.charCodeAt(t.position)))n=!1;else{if(62!==a)return!1;n=!0}for(t.kind="scalar",t.result="";0!==a;)if(43===(a=t.input.charCodeAt(++t.position))||45===a)1===o?o=43===a?3:2:Ut(t,"repeat of a chomping mode identifier");else{if(!((i=Ot(a))>=0))break;0===i?Ut(t,"bad explicit indentation width of a block scalar; it cannot be less than one"):l?Ut(t,"repeat of an indentation width identifier"):(c=e+i-1,l=!0)}if(Et(a)){do{a=t.input.charCodeAt(++t.position)}while(Et(a));if(35===a)do{a=t.input.charCodeAt(++t.position)}while(!$t(a)&&0!==a)}for(;0!==a;){for(Qt(t),t.lineIndent=0,a=t.input.charCodeAt(t.position);(!l||t.lineIndent<c)&&32===a;)t.lineIndent++,a=t.input.charCodeAt(++t.position);if(!l&&t.lineIndent>c&&(c=t.lineIndent),$t(a))u++;else{if(t.lineIndent<c){3===o?t.result+=h.repeat("\n",s?1+u:u):1===o&&s&&(t.result+="\n");break}for(n?Et(a)?(d=!0,t.result+=h.repeat("\n",s?1+u:u)):d?(d=!1,t.result+=h.repeat("\n",u+1)):0===u?s&&(t.result+=" "):t.result+=h.repeat("\n",u):t.result+=h.repeat("\n",s?1+u:u),s=!0,l=!0,u=0,r=t.position;!$t(a)&&0!==a;)a=t.input.charCodeAt(++t.position);Gt(t,r,t.position,!1)}}return!0}function se(t,e){var r,n,i=t.tag,a=t.anchor,o=[],s=!1;if(-1!==t.firstTabInLine)return!1;for(null!==t.anchor&&(t.anchorMap[t.anchor]=o),n=t.input.charCodeAt(t.position);0!==n&&(-1!==t.firstTabInLine&&(t.position=t.firstTabInLine,Ut(t,"tab characters must not be used in indentation")),45===n)&&Nt(t.input.charCodeAt(t.position+1));)if(s=!0,t.position++,Jt(t,!0,-1)&&t.lineIndent<=e)o.push(null),n=t.input.charCodeAt(t.position);else if(r=t.line,de(t,e,3,!1,!0),o.push(t.result),Jt(t,!0,-1),n=t.input.charCodeAt(t.position),(t.line===r||t.lineIndent>e)&&0!==n)Ut(t,"bad indentation of a sequence entry");else if(t.lineIndent<e)break;return!!s&&(t.tag=i,t.anchor=a,t.kind="sequence",t.result=o,!0)}function le(t,e,r){var n,i,a,o,s,l,c,h=t.tag,u=t.anchor,d={},p=Object.create(null),f=null,g=null,m=null,y=!1,x=!1;if(-1!==t.firstTabInLine)return!1;for(null!==t.anchor&&(t.anchorMap[t.anchor]=d),c=t.input.charCodeAt(t.position);0!==c;){if(y||-1===t.firstTabInLine||(t.position=t.firstTabInLine,Ut(t,"tab characters must not be used in indentation")),n=t.input.charCodeAt(t.position+1),a=t.line,63!==c&&58!==c||!Nt(n)){if(o=t.line,s=t.lineStart,l=t.position,!de(t,r,2,!1,!0))break;if(t.line===a){for(c=t.input.charCodeAt(t.position);Et(c);)c=t.input.charCodeAt(++t.position);if(58===c)Nt(c=t.input.charCodeAt(++t.position))||Ut(t,"a whitespace character is expected after the key-value separator within a block mapping"),y&&(Xt(t,d,p,f,g,null,o,s,l),f=g=m=null),x=!0,y=!1,i=!1,f=t.tag,g=t.result;else{if(!x)return t.tag=h,t.anchor=u,!0;Ut(t,"can not read an implicit mapping pair; a colon is missed")}}else{if(!x)return t.tag=h,t.anchor=u,!0;Ut(t,"can not read a block mapping entry; a multiline key may not be an implicit key")}}else 63===c?(y&&(Xt(t,d,p,f,g,null,o,s,l),f=g=m=null),x=!0,y=!0,i=!0):y?(y=!1,i=!0):Ut(t,"incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line"),t.position+=1,c=n;if((t.line===a||t.lineIndent>e)&&(y&&(o=t.line,s=t.lineStart,l=t.position),de(t,e,4,!0,i)&&(y?g=t.result:m=t.result),y||(Xt(t,d,p,f,g,m,o,s,l),f=g=m=null),Jt(t,!0,-1),c=t.input.charCodeAt(t.position)),(t.line===a||t.lineIndent>e)&&0!==c)Ut(t,"bad indentation of a mapping entry");else if(t.lineIndent<e)break}return y&&Xt(t,d,p,f,g,null,o,s,l),x&&(t.tag=h,t.anchor=u,t.kind="mapping",t.result=d),x}function ce(t){var e,r,n,i,a=!1,o=!1;if(33!==(i=t.input.charCodeAt(t.position)))return!1;if(null!==t.tag&&Ut(t,"duplication of a tag property"),60===(i=t.input.charCodeAt(++t.position))?(a=!0,i=t.input.charCodeAt(++t.position)):33===i?(o=!0,r="!!",i=t.input.charCodeAt(++t.position)):r="!",e=t.position,a){do{i=t.input.charCodeAt(++t.position)}while(0!==i&&62!==i);t.position<t.length?(n=t.input.slice(e,t.position),i=t.input.charCodeAt(++t.position)):Ut(t,"unexpected end of the stream within a verbatim tag")}else{for(;0!==i&&!Nt(i);)33===i&&(o?Ut(t,"tag suffix cannot contain exclamation marks"):(r=t.input.slice(e-1,t.position+1),Bt.test(r)||Ut(t,"named tag handle cannot contain such characters"),o=!0,e=t.position+1)),i=t.input.charCodeAt(++t.position);n=t.input.slice(e,t.position),Mt.test(n)&&Ut(t,"tag suffix cannot contain flow indicator characters")}n&&!Lt.test(n)&&Ut(t,"tag name cannot contain such characters: "+n);try{n=decodeURIComponent(n)}catch(s){Ut(t,"tag name is malformed: "+n)}return a?t.tag=n:St.call(t.tagMap,r)?t.tag=t.tagMap[r]+n:"!"===r?t.tag="!"+n:"!!"===r?t.tag="tag:yaml.org,2002:"+n:Ut(t,'undeclared tag handle "'+r+'"'),!0}function he(t){var e,r;if(38!==(r=t.input.charCodeAt(t.position)))return!1;for(null!==t.anchor&&Ut(t,"duplication of an anchor property"),r=t.input.charCodeAt(++t.position),e=t.position;0!==r&&!Nt(r)&&!Dt(r);)r=t.input.charCodeAt(++t.position);return t.position===e&&Ut(t,"name of an anchor node must contain at least one character"),t.anchor=t.input.slice(e,t.position),!0}function ue(t){var e,r,n;if(42!==(n=t.input.charCodeAt(t.position)))return!1;for(n=t.input.charCodeAt(++t.position),e=t.position;0!==n&&!Nt(n)&&!Dt(n);)n=t.input.charCodeAt(++t.position);return t.position===e&&Ut(t,"name of an alias node must contain at least one character"),r=t.input.slice(e,t.position),St.call(t.anchorMap,r)||Ut(t,'unidentified alias "'+r+'"'),t.result=t.anchorMap[r],Jt(t,!0,-1),!0}function de(t,e,r,n,i){var a,o,s,l,c,h,u,d,p,f=1,g=!1,m=!1;if(null!==t.listener&&t.listener("open",t),t.tag=null,t.anchor=null,t.kind=null,t.result=null,a=o=s=4===r||3===r,n&&Jt(t,!0,-1)&&(g=!0,t.lineIndent>e?f=1:t.lineIndent===e?f=0:t.lineIndent<e&&(f=-1)),1===f)for(;ce(t)||he(t);)Jt(t,!0,-1)?(g=!0,s=a,t.lineIndent>e?f=1:t.lineIndent===e?f=0:t.lineIndent<e&&(f=-1)):s=!1;if(s&&(s=g||i),1!==f&&4!==r||(d=1===r||2===r?e:e+1,p=t.position-t.lineStart,1===f?s&&(se(t,p)||le(t,p,d))||ae(t,d)?m=!0:(o&&oe(t,d)||ne(t,d)||ie(t,d)?m=!0:ue(t)?(m=!0,null===t.tag&&null===t.anchor||Ut(t,"alias node should not have any properties")):re(t,d,1===r)&&(m=!0,null===t.tag&&(t.tag="?")),null!==t.anchor&&(t.anchorMap[t.anchor]=t.result)):0===f&&(m=s&&se(t,p))),null===t.tag)null!==t.anchor&&(t.anchorMap[t.anchor]=t.result);else if("?"===t.tag){for(null!==t.result&&"scalar"!==t.kind&&Ut(t,'unacceptable node kind for !<?> tag; it should be "scalar", not "'+t.kind+'"'),l=0,c=t.implicitTypes.length;l<c;l+=1)if((u=t.implicitTypes[l]).resolve(t.result)){t.result=u.construct(t.result),t.tag=u.tag,null!==t.anchor&&(t.anchorMap[t.anchor]=t.result);break}}else if("!"!==t.tag){if(St.call(t.typeMap[t.kind||"fallback"],t.tag))u=t.typeMap[t.kind||"fallback"][t.tag];else for(u=null,l=0,c=(h=t.typeMap.multi[t.kind||"fallback"]).length;l<c;l+=1)if(t.tag.slice(0,h[l].tag.length)===h[l].tag){u=h[l];break}u||Ut(t,"unknown tag !<"+t.tag+">"),null!==t.result&&u.kind!==t.kind&&Ut(t,"unacceptable node kind for !<"+t.tag+'> tag; it should be "'+u.kind+'", not "'+t.kind+'"'),u.resolve(t.result,t.tag)?(t.result=u.construct(t.result,t.tag),null!==t.anchor&&(t.anchorMap[t.anchor]=t.result)):Ut(t,"cannot resolve a node with !<"+t.tag+"> explicit tag")}return null!==t.listener&&t.listener("close",t),null!==t.tag||null!==t.anchor||m}function pe(t){var e,r,n,i,a=t.position,o=!1;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap=Object.create(null),t.anchorMap=Object.create(null);0!==(i=t.input.charCodeAt(t.position))&&(Jt(t,!0,-1),i=t.input.charCodeAt(t.position),!(t.lineIndent>0||37!==i));){for(o=!0,i=t.input.charCodeAt(++t.position),e=t.position;0!==i&&!Nt(i);)i=t.input.charCodeAt(++t.position);for(n=[],(r=t.input.slice(e,t.position)).length<1&&Ut(t,"directive name must not be less than one character in length");0!==i;){for(;Et(i);)i=t.input.charCodeAt(++t.position);if(35===i){do{i=t.input.charCodeAt(++t.position)}while(0!==i&&!$t(i));break}if($t(i))break;for(e=t.position;0!==i&&!Nt(i);)i=t.input.charCodeAt(++t.position);n.push(t.input.slice(e,t.position))}0!==i&&Qt(t),St.call(Vt,r)?Vt[r](t,r,n):Yt(t,'unknown document directive "'+r+'"')}Jt(t,!0,-1),0===t.lineIndent&&45===t.input.charCodeAt(t.position)&&45===t.input.charCodeAt(t.position+1)&&45===t.input.charCodeAt(t.position+2)?(t.position+=3,Jt(t,!0,-1)):o&&Ut(t,"directives end mark is expected"),de(t,t.lineIndent-1,4,!1,!0),Jt(t,!0,-1),t.checkLineBreaks&&Tt.test(t.input.slice(a,t.position))&&Yt(t,"non-ASCII line breaks are interpreted as content"),t.documents.push(t.result),t.position===t.lineStart&&te(t)?46===t.input.charCodeAt(t.position)&&(t.position+=3,Jt(t,!0,-1)):t.position<t.length-1&&Ut(t,"end of the stream or a document separator is expected")}function fe(t,e){e=e||{},0!==(t=String(t)).length&&(10!==t.charCodeAt(t.length-1)&&13!==t.charCodeAt(t.length-1)&&(t+="\n"),65279===t.charCodeAt(0)&&(t=t.slice(1)));var r=new Wt(t,e),n=t.indexOf("\0");for(-1!==n&&(r.position=n,Ut(r,"null byte is not allowed in input")),r.input+="\0";32===r.input.charCodeAt(r.position);)r.lineIndent+=1,r.position+=1;for(;r.position<r.length-1;)pe(r);return r.documents}function ge(t,e,r){null!==e&&"object"==typeof e&&void 0===r&&(r=e,e=null);var n=fe(t,r);if("function"!=typeof e)return n;for(var i=0,a=n.length;i<a;i+=1)e(n[i])}function me(t,e){var r=fe(t,e);if(0!==r.length){if(1===r.length)return r[0];throw new p("expected a single document in the stream, but found more")}}(0,n.K2)(Gt,"captureSegment"),(0,n.K2)(Zt,"mergeMappings"),(0,n.K2)(Xt,"storeMappingPair"),(0,n.K2)(Qt,"readLineBreak"),(0,n.K2)(Jt,"skipSeparationSpace"),(0,n.K2)(te,"testDocumentSeparator"),(0,n.K2)(ee,"writeFoldedLines"),(0,n.K2)(re,"readPlainScalar"),(0,n.K2)(ne,"readSingleQuotedScalar"),(0,n.K2)(ie,"readDoubleQuotedScalar"),(0,n.K2)(ae,"readFlowCollection"),(0,n.K2)(oe,"readBlockScalar"),(0,n.K2)(se,"readBlockSequence"),(0,n.K2)(le,"readBlockMapping"),(0,n.K2)(ce,"readTagProperty"),(0,n.K2)(he,"readAnchorProperty"),(0,n.K2)(ue,"readAlias"),(0,n.K2)(de,"composeNode"),(0,n.K2)(pe,"readDocument"),(0,n.K2)(fe,"loadDocuments"),(0,n.K2)(ge,"loadAll$1"),(0,n.K2)(me,"load$1");var ye={loadAll:ge,load:me},xe=Object.prototype.toString,be=Object.prototype.hasOwnProperty,ke=65279,Ce={0:"\\0",7:"\\a",8:"\\b",9:"\\t",10:"\\n",11:"\\v",12:"\\f",13:"\\r",27:"\\e",34:'\\"',92:"\\\\",133:"\\N",160:"\\_",8232:"\\L",8233:"\\P"},we=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"],_e=/^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/;function ve(t,e){var r,n,i,a,o,s,l;if(null===e)return{};for(r={},i=0,a=(n=Object.keys(e)).length;i<a;i+=1)o=n[i],s=String(e[o]),"!!"===o.slice(0,2)&&(o="tag:yaml.org,2002:"+o.slice(2)),(l=t.compiledTypeMap.fallback[o])&&be.call(l.styleAliases,s)&&(s=l.styleAliases[s]),r[o]=s;return r}function Se(t){var e,r,n;if(e=t.toString(16).toUpperCase(),t<=255)r="x",n=2;else if(t<=65535)r="u",n=4;else{if(!(t<=4294967295))throw new p("code point within a string may not be greater than 0xFFFFFFFF");r="U",n=8}return"\\"+r+h.repeat("0",n-e.length)+e}(0,n.K2)(ve,"compileStyleMap"),(0,n.K2)(Se,"encodeHex");function Ae(t){this.schema=t.schema||vt,this.indent=Math.max(1,t.indent||2),this.noArrayIndent=t.noArrayIndent||!1,this.skipInvalid=t.skipInvalid||!1,this.flowLevel=h.isNothing(t.flowLevel)?-1:t.flowLevel,this.styleMap=ve(this.schema,t.styles||null),this.sortKeys=t.sortKeys||!1,this.lineWidth=t.lineWidth||80,this.noRefs=t.noRefs||!1,this.noCompatMode=t.noCompatMode||!1,this.condenseFlow=t.condenseFlow||!1,this.quotingType='"'===t.quotingType?2:1,this.forceQuotes=t.forceQuotes||!1,this.replacer="function"==typeof t.replacer?t.replacer:null,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result="",this.duplicates=[],this.usedDuplicates=null}function Te(t,e){for(var r,n=h.repeat(" ",e),i=0,a=-1,o="",s=t.length;i<s;)-1===(a=t.indexOf("\n",i))?(r=t.slice(i),i=s):(r=t.slice(i,a+1),i=a+1),r.length&&"\n"!==r&&(o+=n),o+=r;return o}function Me(t,e){return"\n"+h.repeat(" ",t.indent*e)}function Be(t,e){var r,n;for(r=0,n=t.implicitTypes.length;r<n;r+=1)if(t.implicitTypes[r].resolve(e))return!0;return!1}function Le(t){return 32===t||9===t}function Fe(t){return 32<=t&&t<=126||161<=t&&t<=55295&&8232!==t&&8233!==t||57344<=t&&t<=65533&&t!==ke||65536<=t&&t<=1114111}function $e(t){return Fe(t)&&t!==ke&&13!==t&&10!==t}function Ee(t,e,r){var n=$e(t),i=n&&!Le(t);return(r?n:n&&44!==t&&91!==t&&93!==t&&123!==t&&125!==t)&&35!==t&&!(58===e&&!i)||$e(e)&&!Le(e)&&35===t||58===e&&i}function Ne(t){return Fe(t)&&t!==ke&&!Le(t)&&45!==t&&63!==t&&58!==t&&44!==t&&91!==t&&93!==t&&123!==t&&125!==t&&35!==t&&38!==t&&42!==t&&33!==t&&124!==t&&61!==t&&62!==t&&39!==t&&34!==t&&37!==t&&64!==t&&96!==t}function De(t){return!Le(t)&&58!==t}function je(t,e){var r,n=t.charCodeAt(e);return n>=55296&&n<=56319&&e+1<t.length&&(r=t.charCodeAt(e+1))>=56320&&r<=57343?1024*(n-55296)+r-56320+65536:n}function Ie(t){return/^\n* /.test(t)}(0,n.K2)(Ae,"State"),(0,n.K2)(Te,"indentString"),(0,n.K2)(Me,"generateNextLine"),(0,n.K2)(Be,"testImplicitResolving"),(0,n.K2)(Le,"isWhitespace"),(0,n.K2)(Fe,"isPrintable"),(0,n.K2)($e,"isNsCharOrWhitespace"),(0,n.K2)(Ee,"isPlainSafe"),(0,n.K2)(Ne,"isPlainSafeFirst"),(0,n.K2)(De,"isPlainSafeLast"),(0,n.K2)(je,"codePointAt"),(0,n.K2)(Ie,"needIndentIndicator");function Oe(t,e,r,n,i,a,o,s){var l,c=0,h=null,u=!1,d=!1,p=-1!==n,f=-1,g=Ne(je(t,0))&&De(je(t,t.length-1));if(e||o)for(l=0;l<t.length;c>=65536?l+=2:l++){if(!Fe(c=je(t,l)))return 5;g=g&&Ee(c,h,s),h=c}else{for(l=0;l<t.length;c>=65536?l+=2:l++){if(10===(c=je(t,l)))u=!0,p&&(d=d||l-f-1>n&&" "!==t[f+1],f=l);else if(!Fe(c))return 5;g=g&&Ee(c,h,s),h=c}d=d||p&&l-f-1>n&&" "!==t[f+1]}return u||d?r>9&&Ie(t)?5:o?2===a?5:2:d?4:3:!g||o||i(t)?2===a?5:2:1}function Re(t,e,r,i,a){t.dump=function(){if(0===e.length)return 2===t.quotingType?'""':"''";if(!t.noCompatMode&&(-1!==we.indexOf(e)||_e.test(e)))return 2===t.quotingType?'"'+e+'"':"'"+e+"'";var o=t.indent*Math.max(1,r),s=-1===t.lineWidth?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-o),l=i||t.flowLevel>-1&&r>=t.flowLevel;function c(e){return Be(t,e)}switch((0,n.K2)(c,"testAmbiguity"),Oe(e,l,t.indent,s,c,t.quotingType,t.forceQuotes&&!i,a)){case 1:return e;case 2:return"'"+e.replace(/'/g,"''")+"'";case 3:return"|"+Pe(e,t.indent)+ze(Te(e,o));case 4:return">"+Pe(e,t.indent)+ze(Te(Ke(e,s),o));case 5:return'"'+We(e)+'"';default:throw new p("impossible error: invalid scalar style")}}()}function Pe(t,e){var r=Ie(t)?String(e):"",n="\n"===t[t.length-1];return r+(n&&("\n"===t[t.length-2]||"\n"===t)?"+":n?"":"-")+"\n"}function ze(t){return"\n"===t[t.length-1]?t.slice(0,-1):t}function Ke(t,e){for(var r,n,i,a=/(\n+)([^\n]*)/g,o=(r=-1!==(r=t.indexOf("\n"))?r:t.length,a.lastIndex=r,qe(t.slice(0,r),e)),s="\n"===t[0]||" "===t[0];i=a.exec(t);){var l=i[1],c=i[2];n=" "===c[0],o+=l+(s||n||""===c?"":"\n")+qe(c,e),s=n}return o}function qe(t,e){if(""===t||" "===t[0])return t;for(var r,n,i=/ [^ ]/g,a=0,o=0,s=0,l="";r=i.exec(t);)(s=r.index)-a>e&&(n=o>a?o:s,l+="\n"+t.slice(a,n),a=n+1),o=s;return l+="\n",t.length-a>e&&o>a?l+=t.slice(a,o)+"\n"+t.slice(o+1):l+=t.slice(a),l.slice(1)}function We(t){for(var e,r="",n=0,i=0;i<t.length;n>=65536?i+=2:i++)n=je(t,i),!(e=Ce[n])&&Fe(n)?(r+=t[i],n>=65536&&(r+=t[i+1])):r+=e||Se(n);return r}function He(t,e,r){var n,i,a,o="",s=t.tag;for(n=0,i=r.length;n<i;n+=1)a=r[n],t.replacer&&(a=t.replacer.call(r,String(n),a)),(Ze(t,e,a,!1,!1)||void 0===a&&Ze(t,e,null,!1,!1))&&(""!==o&&(o+=","+(t.condenseFlow?"":" ")),o+=t.dump);t.tag=s,t.dump="["+o+"]"}function Ue(t,e,r,n){var i,a,o,s="",l=t.tag;for(i=0,a=r.length;i<a;i+=1)o=r[i],t.replacer&&(o=t.replacer.call(r,String(i),o)),(Ze(t,e+1,o,!0,!0,!1,!0)||void 0===o&&Ze(t,e+1,null,!0,!0,!1,!0))&&(n&&""===s||(s+=Me(t,e)),t.dump&&10===t.dump.charCodeAt(0)?s+="-":s+="- ",s+=t.dump);t.tag=l,t.dump=s||"[]"}function Ye(t,e,r){var n,i,a,o,s,l="",c=t.tag,h=Object.keys(r);for(n=0,i=h.length;n<i;n+=1)s="",""!==l&&(s+=", "),t.condenseFlow&&(s+='"'),o=r[a=h[n]],t.replacer&&(o=t.replacer.call(r,a,o)),Ze(t,e,a,!1,!1)&&(t.dump.length>1024&&(s+="? "),s+=t.dump+(t.condenseFlow?'"':"")+":"+(t.condenseFlow?"":" "),Ze(t,e,o,!1,!1)&&(l+=s+=t.dump));t.tag=c,t.dump="{"+l+"}"}function Ve(t,e,r,n){var i,a,o,s,l,c,h="",u=t.tag,d=Object.keys(r);if(!0===t.sortKeys)d.sort();else if("function"==typeof t.sortKeys)d.sort(t.sortKeys);else if(t.sortKeys)throw new p("sortKeys must be a boolean or a function");for(i=0,a=d.length;i<a;i+=1)c="",n&&""===h||(c+=Me(t,e)),s=r[o=d[i]],t.replacer&&(s=t.replacer.call(r,o,s)),Ze(t,e+1,o,!0,!0,!0)&&((l=null!==t.tag&&"?"!==t.tag||t.dump&&t.dump.length>1024)&&(t.dump&&10===t.dump.charCodeAt(0)?c+="?":c+="? "),c+=t.dump,l&&(c+=Me(t,e)),Ze(t,e+1,s,!0,l)&&(t.dump&&10===t.dump.charCodeAt(0)?c+=":":c+=": ",h+=c+=t.dump));t.tag=u,t.dump=h||"{}"}function Ge(t,e,r){var n,i,a,o,s,l;for(a=0,o=(i=r?t.explicitTypes:t.implicitTypes).length;a<o;a+=1)if(((s=i[a]).instanceOf||s.predicate)&&(!s.instanceOf||"object"==typeof e&&e instanceof s.instanceOf)&&(!s.predicate||s.predicate(e))){if(r?s.multi&&s.representName?t.tag=s.representName(e):t.tag=s.tag:t.tag="?",s.represent){if(l=t.styleMap[s.tag]||s.defaultStyle,"[object Function]"===xe.call(s.represent))n=s.represent(e,l);else{if(!be.call(s.represent,l))throw new p("!<"+s.tag+'> tag resolver accepts not "'+l+'" style');n=s.represent[l](e,l)}t.dump=n}return!0}return!1}function Ze(t,e,r,n,i,a,o){t.tag=null,t.dump=r,Ge(t,r,!1)||Ge(t,r,!0);var s,l=xe.call(t.dump),c=n;n&&(n=t.flowLevel<0||t.flowLevel>e);var h,u,d="[object Object]"===l||"[object Array]"===l;if(d&&(u=-1!==(h=t.duplicates.indexOf(r))),(null!==t.tag&&"?"!==t.tag||u||2!==t.indent&&e>0)&&(i=!1),u&&t.usedDuplicates[h])t.dump="*ref_"+h;else{if(d&&u&&!t.usedDuplicates[h]&&(t.usedDuplicates[h]=!0),"[object Object]"===l)n&&0!==Object.keys(t.dump).length?(Ve(t,e,t.dump,i),u&&(t.dump="&ref_"+h+t.dump)):(Ye(t,e,t.dump),u&&(t.dump="&ref_"+h+" "+t.dump));else if("[object Array]"===l)n&&0!==t.dump.length?(t.noArrayIndent&&!o&&e>0?Ue(t,e-1,t.dump,i):Ue(t,e,t.dump,i),u&&(t.dump="&ref_"+h+t.dump)):(He(t,e,t.dump),u&&(t.dump="&ref_"+h+" "+t.dump));else{if("[object String]"!==l){if("[object Undefined]"===l)return!1;if(t.skipInvalid)return!1;throw new p("unacceptable kind of an object to dump "+l)}"?"!==t.tag&&Re(t,t.dump,e,a,c)}null!==t.tag&&"?"!==t.tag&&(s=encodeURI("!"===t.tag[0]?t.tag.slice(1):t.tag).replace(/!/g,"%21"),s="!"===t.tag[0]?"!"+s:"tag:yaml.org,2002:"===s.slice(0,18)?"!!"+s.slice(18):"!<"+s+">",t.dump=s+" "+t.dump)}return!0}function Xe(t,e){var r,n,i=[],a=[];for(Qe(t,i,a),r=0,n=a.length;r<n;r+=1)e.duplicates.push(i[a[r]]);e.usedDuplicates=new Array(n)}function Qe(t,e,r){var n,i,a;if(null!==t&&"object"==typeof t)if(-1!==(i=e.indexOf(t)))-1===r.indexOf(i)&&r.push(i);else if(e.push(t),Array.isArray(t))for(i=0,a=t.length;i<a;i+=1)Qe(t[i],e,r);else for(i=0,a=(n=Object.keys(t)).length;i<a;i+=1)Qe(t[n[i]],e,r)}function Je(t,e){var r=new Ae(e=e||{});r.noRefs||Xe(t,r);var n=t;return r.replacer&&(n=r.replacer.call({"":n},"",n)),Ze(r,0,n,!0,!0)?r.dump+"\n":""}(0,n.K2)(Oe,"chooseScalarStyle"),(0,n.K2)(Re,"writeScalar"),(0,n.K2)(Pe,"blockHeader"),(0,n.K2)(ze,"dropEndingNewline"),(0,n.K2)(Ke,"foldString"),(0,n.K2)(qe,"foldLine"),(0,n.K2)(We,"escapeString"),(0,n.K2)(He,"writeFlowSequence"),(0,n.K2)(Ue,"writeBlockSequence"),(0,n.K2)(Ye,"writeFlowMapping"),(0,n.K2)(Ve,"writeBlockMapping"),(0,n.K2)(Ge,"detectType"),(0,n.K2)(Ze,"writeNode"),(0,n.K2)(Xe,"getDuplicateReferences"),(0,n.K2)(Qe,"inspectNode"),(0,n.K2)(Je,"dump$1");function tr(t,e){return function(){throw new Error("Function yaml."+t+" is removed in js-yaml 4. Use yaml."+e+" instead, which is now safe by default.")}}(0,n.K2)(tr,"renamed");var er=G,rr=ye.load;tr("safeLoad","load"),tr("safeLoadAll","loadAll"),tr("safeDump","dump")}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3764.c12c89cb.js.LICENSE.txt b/pr-preview/pr-1071/assets/js/3764.c12c89cb.js.LICENSE.txt deleted file mode 100644 index 49f86b38f2..0000000000 --- a/pr-preview/pr-1071/assets/js/3764.c12c89cb.js.LICENSE.txt +++ /dev/null @@ -1,7 +0,0 @@ -/*! @license DOMPurify 3.2.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.1/LICENSE */ - -/*! Bundled license information: - -js-yaml/dist/js-yaml.mjs: - (*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT *) -*/ diff --git a/pr-preview/pr-1071/assets/js/391.11ead156.js b/pr-preview/pr-1071/assets/js/391.11ead156.js deleted file mode 100644 index d9d184351e..0000000000 --- a/pr-preview/pr-1071/assets/js/391.11ead156.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[391],{90391:(s,r,a)=>{a.d(r,{diagram:()=>c});var e=a(66240),t=(a(96474),a(87308),a(37938),a(1282),a(64532),a(47588),a(33115),a(10483),a(8159),a(10009)),c={parser:e._$,db:e.z2,renderer:e.Lh,styles:e.tM,init:(0,t.K2)((s=>{s.class||(s.class={}),s.class.arrowMarkerAbsolute=s.arrowMarkerAbsolute,e.z2.clear()}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/39db4684.ca1f2305.js b/pr-preview/pr-1071/assets/js/39db4684.ca1f2305.js deleted file mode 100644 index 009771284d..0000000000 --- a/pr-preview/pr-1071/assets/js/39db4684.ca1f2305.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3459],{56860:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"about/index","title":"About","description":"","source":"@site/versioned_docs/version-0.7/about/index.md","sourceDirName":"about","slug":"/about/","permalink":"/contrast/pr-preview/pr-1071/0.7/about/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/about/index.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/0.7/features-limitations"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/0.7/about/telemetry"}}');var s=n(74848),o=n(28453),c=n(44074);const i={},a="About",l={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"about",children:"About"})}),"\n","\n",(0,s.jsx)(c.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>N});var r=n(96540),s=n(34164),o=n(45357),c=n(14783),i=n(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function m(){const e=d();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=n(74848);function b(e){let{href:t,children:n}=e;return(0,g.jsx)(c.A,{href:t,className:(0,s.A)("card padding--lg",x.cardContainer),children:n})}function j(e){let{href:t,icon:n,title:r,description:o}=e;return(0,g.jsxs)(b,{href:t,children:[(0,g.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",x.cardTitle),title:r,children:[n," ",r]}),o&&(0,g.jsx)("p",{className:(0,s.A)("text--truncate",x.cardDescription),title:o,children:o})]})}function v(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,g.jsx)(j,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function w(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,g.jsx)(j,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function y(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(w,{item:t});case"category":return(0,g.jsx)(v,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function A(e){let{className:t}=e;const n=(0,o.$S)();return(0,g.jsx)(N,{items:n.items,className:t})}function N(e){const{items:t,className:n}=e;if(!t)return(0,g.jsx)(A,{...e});const r=(0,o.d1)(t);return(0,g.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(y,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>i});var r=n(96540);const s={},o=r.createContext(s);function c(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3a77bb3e.49b3f8ee.js b/pr-preview/pr-1071/assets/js/3a77bb3e.49b3f8ee.js deleted file mode 100644 index cf155fe96f..0000000000 --- a/pr-preview/pr-1071/assets/js/3a77bb3e.49b3f8ee.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1889],{34690:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>i,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-0.5/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/getting-started/cluster-setup.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/install"},"next":{"title":"First steps","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps"}}');var t=r(74848),a=r(28453);const o={},c="Create a cluster",i={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.p,{children:["Install the latest version of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli",children:"Login to your account"}),", which has\nthe permissions to create an AKS cluster, by executing:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "$azResourceGroup" \\\n --location "$azLocation"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First create an AKS cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "$azResourceGroup" \\\n --name "$azClusterName" \\\n --kubernetes-version 1.29 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"We then add a second node pool with CoCo support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool add \\\n --resource-group "$azResourceGroup" \\\n --name nodepool2 \\\n --cluster-name "$azClusterName" \\\n --node-count 1 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "$azResourceGroup" \\\n --name "$azClusterName"\n'})}),"\n",(0,t.jsx)(n.p,{children:"For validation, list the available nodes using kubectl:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show two nodes:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\naks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "$azResourceGroup"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "$azResourceGroup" \\\n --name "$azClusterName"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>c});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3b29aa35.0ba1db01.js b/pr-preview/pr-1071/assets/js/3b29aa35.0ba1db01.js deleted file mode 100644 index 8396b70b69..0000000000 --- a/pr-preview/pr-1071/assets/js/3b29aa35.0ba1db01.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3641],{97607:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"getting-started/bare-metal","title":"Prepare a bare-metal instance","description":"Hardware and firmware setup","source":"@site/versioned_docs/version-1.2/getting-started/bare-metal.md","sourceDirName":"getting-started","slug":"/getting-started/bare-metal","permalink":"/contrast/pr-preview/pr-1071/getting-started/bare-metal","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/getting-started/bare-metal.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/getting-started/cluster-setup"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/examples/emojivoto"}}');var r=n(74848),a=n(28453);const i={},o="Prepare a bare-metal instance",l={},c=[{value:"Hardware and firmware setup",id:"hardware-and-firmware-setup",level:2},{value:"Kernel Setup",id:"kernel-setup",level:2},{value:"K3s Setup",id:"k3s-setup",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",...(0,a.R)(),...e.components},{TabItem:n,Tabs:s}=t;return n||u("TabItem",!0),s||u("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"prepare-a-bare-metal-instance",children:"Prepare a bare-metal instance"})}),"\n",(0,r.jsx)(t.h2,{id:"hardware-and-firmware-setup",children:"Hardware and firmware setup"}),"\n",(0,r.jsxs)(s,{queryString:"vendor",children:[(0,r.jsxs)(n,{value:"amd",label:"AMD SEV-SNP",children:[(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"Update your BIOS to a version that supports AMD SEV-SNP. Updating to the latest available version is recommended as newer versions will likely contain security patches for AMD SEV-SNP."}),"\n",(0,r.jsx)(t.li,{children:"Enter BIOS setup to enable SMEE, IOMMU, RMP coverage, and SEV-SNP. Set the SEV-ES ASID Space Limit to a non-zero number (higher is better)."}),"\n",(0,r.jsxs)(t.li,{children:["Download the latest firmware version for your processor from ",(0,r.jsx)(t.a,{href:"https://www.amd.com/de/developer/sev.html",children:"AMD"}),", unpack it, and place it in ",(0,r.jsx)(t.code,{children:"/lib/firmware/amd"}),"."]}),"\n"]}),(0,r.jsxs)(t.p,{children:["Consult AMD's ",(0,r.jsx)(t.a,{href:"https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/tuning-guides/58207-using-sev-with-amd-epyc-processors.pdf",children:"Using SEV with AMD EPYC Processors user guide"})," for more information."]})]}),(0,r.jsx)(n,{value:"intel",label:"Intel TDX",children:(0,r.jsxs)(t.p,{children:["Follow Canonical's instructions on ",(0,r.jsx)(t.a,{href:"https://github.com/canonical/tdx?tab=readme-ov-file#43-enable-intel-tdx-in-the-hosts-bios",children:"setting up Intel TDX in the host's BIOS"}),"."]})})]}),"\n",(0,r.jsx)(t.h2,{id:"kernel-setup",children:"Kernel Setup"}),"\n",(0,r.jsxs)(s,{queryString:"vendor",children:[(0,r.jsx)(n,{value:"amd",label:"AMD SEV-SNP",children:(0,r.jsx)(t.p,{children:"Install a kernel with version 6.11 or greater. If you're following this guide before 6.11 has been released, use 6.11-rc3. Don't use 6.11-rc4 - 6.11-rc6 as they contain a regression. 6.11-rc7+ might work."})}),(0,r.jsx)(n,{value:"intel",label:"Intel TDX",children:(0,r.jsxs)(t.p,{children:["Follow Canonical's instructions on ",(0,r.jsx)(t.a,{href:"https://github.com/canonical/tdx?tab=readme-ov-file#41-install-ubuntu-2404-server-image",children:"setting up Intel TDX on Ubuntu 24.04"}),". Note that Contrast currently only supports Intel TDX with Ubuntu 24.04."]})})]}),"\n",(0,r.jsxs)(t.p,{children:["Increase the ",(0,r.jsx)(t.code,{children:"user.max_inotify_instances"})," sysctl limit by adding ",(0,r.jsx)(t.code,{children:"user.max_inotify_instances=8192"})," to ",(0,r.jsx)(t.code,{children:"/etc/sysctl.d/99-sysctl.conf"})," and running ",(0,r.jsx)(t.code,{children:"sysctl --system"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"k3s-setup",children:"K3s Setup"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["Follow the ",(0,r.jsx)(t.a,{href:"https://docs.k3s.io/",children:"K3s setup instructions"})," to create a cluster."]}),"\n",(0,r.jsxs)(t.li,{children:["Install a block storage provider such as ",(0,r.jsx)(t.a,{href:"https://docs.k3s.io/storage#setting-up-longhorn",children:"Longhorn"})," and mark it as the default storage class."]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function u(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(96540);const r={},a=s.createContext(r);function i(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3d96af17.379760d6.js b/pr-preview/pr-1071/assets/js/3d96af17.379760d6.js deleted file mode 100644 index ba036bb88a..0000000000 --- a/pr-preview/pr-1071/assets/js/3d96af17.379760d6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4506],{78016:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-1.1/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/getting-started/cluster-setup.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/install"},"next":{"title":"Bare metal setup","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal"}}');var t=r(74848),a=r(28453);const o={},i="Create a cluster",c={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Install version 2.44.1 or newer of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),". Note that your package manager will likely install an outdated version."]}),"\n",(0,t.jsxs)(n.li,{children:["Install a recent version of ",(0,t.jsx)(n.a,{href:"https://kubernetes.io/docs/tasks/tools/",children:"kubectl"}),"."]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsx)(n.p,{children:"First, log in to your Azure subscription:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First, create a CoCo enabled AKS cluster with:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.30 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["For validation, list the available nodes using ",(0,t.jsx)(n.code,{children:"kubectl"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show a single node:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\n"})}),"\n",(0,t.jsxs)(n.p,{children:["\ud83e\udd73 Congratulations. You're now ready to set up your first application with Contrast. Follow this ",(0,t.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto",children:"example"})," to learn how."]}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>i});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3d9be0cc.722295e4.js b/pr-preview/pr-1071/assets/js/3d9be0cc.722295e4.js deleted file mode 100644 index cfdc0f087b..0000000000 --- a/pr-preview/pr-1071/assets/js/3d9be0cc.722295e4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5310],{51550:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-0.5/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/examples/emojivoto.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Examples","permalink":"/contrast/pr-preview/pr-1071/0.5/examples/"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.5/deployment"}}');var i=n(74848),a=n(28453);const s={},r="Confidential emoji voting",d={},l=[{value:"Motivation",id:"motivation",level:3},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Voter's perspective: Verifying the ballot",id:"voters-perspective-verifying-the-ballot",level:2},{value:"Attest the Coordinator",id:"attest-the-coordinator",level:3},{value:"Manifest history and artifact audit",id:"manifest-history-and-artifact-audit",level:3},{value:"Confidential connection to the attested workload",id:"confidential-connection-to-the-attested-workload",level:3},{value:"Certificate SAN and manifest update (optional)",id:"certificate-san-and-manifest-update-optional",level:2},{value:"Configure the service SAN in the manifest",id:"configure-the-service-san-in-the-manifest",level:3},{value:"Update the manifest",id:"update-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(94239).A+"",width:"1503",height:"732"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,i.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voters perspective."]})}),"\n",(0,i.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,i.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,i.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,i.jsx)(t.code,{children:"voting"}),"). The ",(0,i.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,i.jsx)(t.h3,{id:"motivation",children:"Motivation"}),"\n",(0,i.jsx)(t.p,{children:"Using a voting service, users' votes are considered highly sensitive data, as we require\na secret ballot. Also, users are likely interested in the fairness of the ballot. For\nboth requirements, we can use Confidential Computing and, specifically, workload attestation\nto prove to those interested in voting that the app is running in a protected environment\nwhere their votes are processed without leaking to the platform provider or workload owner."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Installed Contrast CLI."}),"\nSee the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/getting-started/install",children:"installation instructions"})," on how to get it."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Running cluster with Confidential Containers support."}),"\nPlease follow the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup",children:"cluster setup instructions"}),"\nto create a cluster."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Get the deployment."})," This is currently available as part of the preview bundle."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f coordinator.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,i.jsxs)(t.p,{children:["Run the ",(0,i.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,i.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"contrast generate deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:(0,i.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA runtime class ",(0,i.jsx)(t.code,{children:"kata-cc-isolation"})," was added to the pods to signal they should be run\nas Confidential Containers. In addition, the Contrast Initializer was added\nas an init container to these workloads to facilitate the attestation and certificate pulling\nbefore the actual workload is started."]})}),"\n",(0,i.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsx)(t.p,{children:"The CLI will use the embedded reference values to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, we're ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,i.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,i.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,i.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,i.jsx)(t.code,{children:"volumeMount"}),". The emojivoto version we're using is patched to only communicate\nvia mTLS (the original app talks plain HTTP). The different parts of the workload are configured\nto use the credentials from the ",(0,i.jsx)(t.code,{children:"volumeMount"})," when communicating with each other."]})}),"\n",(0,i.jsx)(t.h2,{id:"voters-perspective-verifying-the-ballot",children:"Voter's perspective: Verifying the ballot"}),"\n",(0,i.jsx)(t.p,{children:"As voters, we want to verify the fairness and confidentiality of the deployment before\ndeciding to vote. Regardless of the scale of our distributed deployment, Contrast only\nneeds a single remote attestation step to verify the deployment. By doing remote attestation\nof the Coordinator, we transitively verify those systems the Coordinator has already attested\nor will attest in the future. Successful verification of the Coordinator means that\nwe can be sure it will enforce the configured manifest."}),"\n",(0,i.jsx)(t.h3,{id:"attest-the-coordinator",children:"Attest the Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"A potential voter can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The CLI will attest the Coordinator using embedded reference values. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,i.jsx)(t.code,{children:"mesh-root.pem"}),") and the history of manifests, into the ",(0,i.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,i.jsx)(t.h3,{id:"manifest-history-and-artifact-audit",children:"Manifest history and artifact audit"}),"\n",(0,i.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,i.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,i.jsx)(t.h3,{id:"confidential-connection-to-the-attested-workload",children:"Confidential connection to the attested workload"}),"\n",(0,i.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, you can securely connect\nto the workloads using the Coordinator's ",(0,i.jsx)(t.code,{children:"mesh-root.pem"})," as a trusted CA certificate."]}),"\n",(0,i.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,i.jsx)(t.code,{children:"mesh-root.pem"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-root.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,i.jsx)(t.h2,{id:"certificate-san-and-manifest-update-optional",children:"Certificate SAN and manifest update (optional)"}),"\n",(0,i.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh root certificate with throw the following error:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-root.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,i.jsx)(t.h3,{id:"configure-the-service-san-in-the-manifest",children:"Configure the service SAN in the manifest"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,i.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,i.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n'})}),"\n",(0,i.jsx)(t.h3,{id:"update-the-manifest",children:"Update the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh root certificate on the manifest update. Workload certificates issued\nafter the manifest are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,i.jsx)(t.code,{children:"mesh-root.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,i.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,i.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,i.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,i.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-root.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},94239:(e,t,n)=>{n.d(t,{A:()=>o});const o=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>r});var o=n(96540);const i={},a=o.createContext(i);function s(e){const t=o.useContext(a);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),o.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/3e02a241.748d4906.js b/pr-preview/pr-1071/assets/js/3e02a241.748d4906.js deleted file mode 100644 index 899b13bc93..0000000000 --- a/pr-preview/pr-1071/assets/js/3e02a241.748d4906.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8117],{28072:(t,e,i)=>{i.r(e),i.d(e,{assets:()=>a,contentTitle:()=>o,default:()=>u,frontMatter:()=>c,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/certificates-and-identities/pki","title":"pki","description":"","source":"@site/versioned_docs/version-0.5/architecture/certificates-and-identities/pki.md","sourceDirName":"architecture/certificates-and-identities","slug":"/architecture/certificates-and-identities/pki","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/certificates-and-identities/pki.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificates and Identities","permalink":"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities"},"next":{"title":"Network Encryption","permalink":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption"}}');var r=i(74848),s=i(28453);const c={},o=void 0,a={},d=[];function p(t){return(0,r.jsx)(r.Fragment,{})}function u(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(p,{...t})}):p()}},28453:(t,e,i)=>{i.d(e,{R:()=>c,x:()=>o});var n=i(96540);const r={},s=n.createContext(r);function c(t){const e=n.useContext(s);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function o(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:c(t.components),n.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/41b31679.79aad1d5.js b/pr-preview/pr-1071/assets/js/41b31679.79aad1d5.js deleted file mode 100644 index 59241d04a8..0000000000 --- a/pr-preview/pr-1071/assets/js/41b31679.79aad1d5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4714],{65324:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>d});const o=JSON.parse('{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","source":"@site/versioned_docs/version-0.9/troubleshooting.md","sourceDirName":".","slug":"/troubleshooting","permalink":"/contrast/pr-preview/pr-1071/0.9/troubleshooting","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/troubleshooting.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.9/deployment"},"next":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/0.9/components/overview"}}');var i=t(74848),s=t(28453);const a={},r="Troubleshooting",c={},d=[{value:"Logging",id:"logging",level:2},{value:"CLI",id:"cli",level:3},{value:"Coordinator and Initializer",id:"coordinator-and-initializer",level:3},{value:"Pod fails to start",id:"pod-fails-to-start",level:2},{value:"Regenerating the policies",id:"regenerating-the-policies",level:3},{value:"Pin container images",id:"pin-container-images",level:3},{value:"Validate Contrast components match",id:"validate-contrast-components-match",level:3}];function l(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"troubleshooting",children:"Troubleshooting"})}),"\n",(0,i.jsx)(n.p,{children:"This section contains information on how to debug your Contrast deployment."}),"\n",(0,i.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,i.jsx)(n.p,{children:"Collecting logs can be a good first step to identify problems in your\ndeployment. Both the CLI and the Contrast Coordinator as well as the Initializer\ncan be configured to emit additional logs."}),"\n",(0,i.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,i.jsxs)(n.p,{children:["The CLI logs can be configured with the ",(0,i.jsx)(n.code,{children:"--log-level"})," command-line flag, which\ncan be set to either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"})," or ",(0,i.jsx)(n.code,{children:"error"}),". The default is ",(0,i.jsx)(n.code,{children:"info"}),".\nSetting this to ",(0,i.jsx)(n.code,{children:"debug"})," can get more fine-grained information as to where the\nproblem lies."]}),"\n",(0,i.jsx)(n.h3,{id:"coordinator-and-initializer",children:"Coordinator and Initializer"}),"\n",(0,i.jsxs)(n.p,{children:["The logs from the Coordinator and the Initializer can be configured via the\nenvironment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"}),", ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," and\n",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"})," can be set to one of either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"}),", or\n",(0,i.jsx)(n.code,{children:"error"}),", similar to the CLI (defaults to ",(0,i.jsx)(n.code,{children:"info"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," can be set to ",(0,i.jsx)(n.code,{children:"text"})," or ",(0,i.jsx)(n.code,{children:"json"}),", determining the output\nformat (defaults to ",(0,i.jsx)(n.code,{children:"text"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," is a comma-seperated list of subsystems that should\nbe enabled for logging, which are disabled by default. Subsystems include:\n",(0,i.jsx)(n.code,{children:"kds-getter"}),", ",(0,i.jsx)(n.code,{children:"issuer"})," and ",(0,i.jsx)(n.code,{children:"validator"}),".\nTo enable all subsystems, use ",(0,i.jsx)(n.code,{children:"*"})," as the value for this environment variable.\nWarnings and error messages from subsystems get printed regardless of whether\nthe subsystem is listed in the ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," environment variable."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"To configure debug logging with all subsystems for your Coordinator, add the\nfollowing variables to your container definition."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n containers:\n image: "ghcr.io/edgelesssys/contrast/coordinator:v0.9.0@sha256:7530dcd0bd16b5dbeda915c8ebfeb5d860c2f9e4661acbc70fdaae60bf174e20"\n name: coordinator\n env:\n - name: CONTRAST_LOG_LEVEL\n value: debug\n - name: CONTRAST_LOG_SUBSYSTEMS\n value: "*"\n # ...\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["While the Contrast Coordinator has a policy that allows certain configurations,\nthe Initializer and service mesh don't. When changing environment variables of other\nparts than the Coordinator, ensure to rerun ",(0,i.jsx)(n.code,{children:"contrast generate"})," to update the policy."]})}),"\n",(0,i.jsxs)(n.p,{children:["To access the logs generated by the Coordinator, you can use ",(0,i.jsx)(n.code,{children:"kubectl"})," with the\nfollowing command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl logs <coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.h2,{id:"pod-fails-to-start",children:"Pod fails to start"}),"\n",(0,i.jsxs)(n.p,{children:["If the Coordinator or a workload pod fails to even start, it can be helpful to\nlook at the events of the pod during the startup process using the ",(0,i.jsx)(n.code,{children:"describe"}),"\ncommand."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> events --for pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"Example output:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'LAST SEEN TYPE REASON OBJECT MESSAGE\n32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...\n'})}),"\n",(0,i.jsx)(n.p,{children:"A common error, as in this example, is that the container creation was blocked by the\npolicy. Potential reasons are a modification of the deployment YAML without updating\nthe policies afterward, or a version mismatch between Contrast components."}),"\n",(0,i.jsx)(n.h3,{id:"regenerating-the-policies",children:"Regenerating the policies"}),"\n",(0,i.jsx)(n.p,{children:"To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated\npolicies, rerun"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast generate\n"})}),"\n",(0,i.jsx)(n.p,{children:"on your deployment. If any of the policy annotations change, re-deploy with the updated policies."}),"\n",(0,i.jsx)(n.h3,{id:"pin-container-images",children:"Pin container images"}),"\n",(0,i.jsx)(n.p,{children:"When generating the policies, Contrast will download the images specified in your deployment\nYAML and include their cryptographic identity. If the image tag is moved to another\ncontainer image after the policy has been generated, the image downloaded at deploy time\nwill differ from the one at generation time, and the policy enforcement won't allow the\ncontainer to be started in the pod VM."}),"\n",(0,i.jsxs)(n.p,{children:["To ensure the correct image is always used, pin the container image to a fixed ",(0,i.jsx)(n.code,{children:"sha256"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This way, the same image will still be pulled when the container tag (",(0,i.jsx)(n.code,{children:"22.04"}),") is moved\nto another image."]}),"\n",(0,i.jsx)(n.h3,{id:"validate-contrast-components-match",children:"Validate Contrast components match"}),"\n",(0,i.jsx)(n.p,{children:"A version mismatch between Contrast components can cause policy validation or attestation\nto fail. Each Contrast runtime is identifiable based on its (shortened) measurement value\nused to name the runtime class version."}),"\n",(0,i.jsx)(n.p,{children:"First, analyze which runtime class is currently installed in your cluster by running"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl get runtimeclasses\n"})}),"\n",(0,i.jsx)(n.p,{children:"This should give you output similar to the following one."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"NAME HANDLER AGE\ncontrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h\nkata-cc-isolation kata-cc 45d\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided\nby the AKS CoCo preview, which isn't used by Contrast)."}),"\n",(0,i.jsx)(n.p,{children:"Next, check if the pod that won't start has the correct runtime class configured, and the\nCoordinator uses the exact same runtime:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>\nkubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output should list the runtime class the pod is using:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast-cc-aks-clh-snp-7173acb5\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Version information about the currently used CLI can be obtained via the ",(0,i.jsx)(n.code,{children:"version"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast --version\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast version v0.X.0\n\n runtime handler: contrast-cc-aks-clh-snp-7173acb5\n launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35\n genpolicy version: 3.2.0.azl1.genpolicy0\n image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...\n ghcr.io/edgelesssys/contrast/initializer@sha256:...\n"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(96540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4485.60f44ca9.js b/pr-preview/pr-1071/assets/js/4485.60f44ca9.js deleted file mode 100644 index 36cb26fbed..0000000000 --- a/pr-preview/pr-1071/assets/js/4485.60f44ca9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4485],{75937:(t,e,s)=>{s.d(e,{A:()=>i});var n=s(72453),r=s(74886);const i=(t,e)=>n.A.lang.round(r.A.parse(t)[e])},96474:(t,e,s)=>{s.d(e,{A:()=>i,P:()=>u});var n=s(10009),r=s(20007),i=(0,n.K2)(((t,e)=>{let s;"sandbox"===e&&(s=(0,r.Ltv)("#i"+t));return("sandbox"===e?(0,r.Ltv)(s.nodes()[0].contentDocument.body):(0,r.Ltv)("body")).select(`[id="${t}"]`)}),"getDiagramElement"),u=(0,n.K2)(((t,e,s,r)=>{t.attr("class",s);const{width:i,height:u,x:c,y:l}=a(t,e);(0,n.a$)(t,u,i,r);const h=o(c,l,i,u,e);t.attr("viewBox",h),n.Rm.debug(`viewBox configured: ${h} with padding: ${e}`)}),"setupViewPortForSVG"),a=(0,n.K2)(((t,e)=>{const s=t.node()?.getBBox()||{width:0,height:0,x:0,y:0};return{width:s.width+2*e,height:s.height+2*e,x:s.x,y:s.y}}),"calculateDimensionsWithPadding"),o=(0,n.K2)(((t,e,s,n,r)=>`${t-r} ${e-r} ${s} ${n}`),"createViewBox")},44485:(t,e,s)=>{s.d(e,{diagram:()=>Dt});var n,r,i=s(96474),u=s(59874),a=s(87308),o=(s(37938),s(1282)),c=(s(64532),s(47588),s(33115),s(10483),s(8159)),l=s(10009),h=s(20007),d=s(75937),p=s(25582),A=0,g=(0,l.D7)(),f=new Map,y=[],k=new Map,b=[],E=new Map,m=new Map,D=0,x=!0,C=[],T=(0,l.K2)((t=>l.Y2.sanitizeText(t,g)),"sanitizeText"),S=(0,l.K2)((function(t){for(const e of f.values())if(e.id===t)return e.domId;return t}),"lookUpDomId"),F=(0,l.K2)((function(t,e,s,n,r,i,a={},c){if(!t||0===t.trim().length)return;let h,d=f.get(t);if(void 0===d&&(d={id:t,labelType:"text",domId:"flowchart-"+t+"-"+A,styles:[],classes:[]},f.set(t,d)),A++,void 0!==e?(g=(0,l.D7)(),h=T(e.text.trim()),d.labelType=e.type,h.startsWith('"')&&h.endsWith('"')&&(h=h.substring(1,h.length-1)),d.text=h):void 0===d.text&&(d.text=t),void 0!==s&&(d.type=s),null!=n&&n.forEach((function(t){d.styles.push(t)})),null!=r&&r.forEach((function(t){d.classes.push(t)})),void 0!==i&&(d.dir=i),void 0===d.props?d.props=a:void 0!==a&&Object.assign(d.props,a),void 0!==c){let e;e=c.includes("\n")?c+"\n":"{\n"+c+"\n}";const s=(0,u.H)(e,{schema:u.r});if(s.shape){if(s.shape!==s.shape.toLowerCase()||s.shape.includes("_"))throw new Error(`No such shape: ${s.shape}. Shape names should be lowercase.`);if(!(0,o.aP)(s.shape))throw new Error(`No such shape: ${s.shape}.`);d.type=s?.shape}s?.label&&(d.text=s?.label),s?.icon&&(d.icon=s?.icon,s.label?.trim()||d.text!==t||(d.text="")),s?.form&&(d.form=s?.form),s?.pos&&(d.pos=s?.pos),s?.img&&(d.img=s?.img,s.label?.trim()||d.text!==t||(d.text="")),s?.constraint&&(d.constraint=s.constraint),s.w&&(d.assetWidth=Number(s.w)),s.h&&(d.assetHeight=Number(s.h))}}),"addVertex"),_=(0,l.K2)((function(t,e,s){const n={start:t,end:e,type:void 0,text:"",labelType:"text"};l.Rm.info("abc78 Got edge...",n);const r=s.text;if(void 0!==r&&(n.text=T(r.text.trim()),n.text.startsWith('"')&&n.text.endsWith('"')&&(n.text=n.text.substring(1,n.text.length-1)),n.labelType=r.type),void 0!==s&&(n.type=s.type,n.stroke=s.stroke,n.length=s.length>10?10:s.length),!(y.length<(g.maxEdges??500)))throw new Error(`Edge limit exceeded. ${y.length} edges found, but the limit is ${g.maxEdges}.\n\nInitialize mermaid with maxEdges set to a higher number to allow more edges.\nYou cannot set this config via configuration inside the diagram as it is a secure config.\nYou have to call mermaid.initialize.`);l.Rm.info("Pushing edge..."),y.push(n)}),"addSingleLink"),B=(0,l.K2)((function(t,e,s){l.Rm.info("addLink",t,e,s);for(const n of t)for(const t of e)_(n,t,s)}),"addLink"),v=(0,l.K2)((function(t,e){t.forEach((function(t){"default"===t?y.defaultInterpolate=e:y[t].interpolate=e}))}),"updateLinkInterpolate"),w=(0,l.K2)((function(t,e){t.forEach((function(t){if("number"==typeof t&&t>=y.length)throw new Error(`The index ${t} for linkStyle is out of bounds. Valid indices for linkStyle are between 0 and ${y.length-1}. (Help: Ensure that the index is within the range of existing edges.)`);"default"===t?y.defaultStyle=e:(y[t].style=e,(y[t]?.style?.length??0)>0&&!y[t]?.style?.some((t=>t?.startsWith("fill")))&&y[t]?.style?.push("fill:none"))}))}),"updateLink"),$=(0,l.K2)((function(t,e){t.split(",").forEach((function(t){let s=k.get(t);void 0===s&&(s={id:t,styles:[],textStyles:[]},k.set(t,s)),null!=e&&e.forEach((function(t){if(/color/.exec(t)){const e=t.replace("fill","bgFill");s.textStyles.push(e)}s.styles.push(t)}))}))}),"addClass"),L=(0,l.K2)((function(t){/.*</.exec(n=t)&&(n="RL"),/.*\^/.exec(n)&&(n="BT"),/.*>/.exec(n)&&(n="LR"),/.*v/.exec(n)&&(n="TB"),"TD"===n&&(n="TB")}),"setDirection"),R=(0,l.K2)((function(t,e){for(const s of t.split(",")){const t=f.get(s);t&&t.classes.push(e);const n=E.get(s);n&&n.classes.push(e)}}),"setClass"),I=(0,l.K2)((function(t,e){if(void 0!==e){e=T(e);for(const s of t.split(","))m.set("gen-1"===r?S(s):s,e)}}),"setTooltip"),K=(0,l.K2)((function(t,e,s){const n=S(t);if("loose"!==(0,l.D7)().securityLevel)return;if(void 0===e)return;let r=[];if("string"==typeof s){r=s.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let t=0;t<r.length;t++){let e=r[t].trim();e.startsWith('"')&&e.endsWith('"')&&(e=e.substr(1,e.length-2)),r[t]=e}}0===r.length&&r.push(t);const i=f.get(t);i&&(i.haveCallback=!0,C.push((function(){const t=document.querySelector(`[id="${n}"]`);null!==t&&t.addEventListener("click",(function(){c._K.runFunc(e,...r)}),!1)})))}),"setClickFun"),N=(0,l.K2)((function(t,e,s){t.split(",").forEach((function(t){const n=f.get(t);void 0!==n&&(n.link=c._K.formatUrl(e,g),n.linkTarget=s)})),R(t,"clickable")}),"setLink"),P=(0,l.K2)((function(t){return m.get(t)}),"getTooltip"),O=(0,l.K2)((function(t,e,s){t.split(",").forEach((function(t){K(t,e,s)})),R(t,"clickable")}),"setClickEvent"),M=(0,l.K2)((function(t){C.forEach((function(e){e(t)}))}),"bindFunctions"),V=(0,l.K2)((function(){return n.trim()}),"getDirection"),U=(0,l.K2)((function(){return f}),"getVertices"),G=(0,l.K2)((function(){return y}),"getEdges"),W=(0,l.K2)((function(){return k}),"getClasses"),Y=(0,l.K2)((function(t){let e=(0,h.Ltv)(".mermaidTooltip");null===(e._groups||e)[0][0]&&(e=(0,h.Ltv)("body").append("div").attr("class","mermaidTooltip").style("opacity",0));(0,h.Ltv)(t).select("svg").selectAll("g.node").on("mouseover",(function(){const t=(0,h.Ltv)(this);if(null===t.attr("title"))return;const s=this?.getBoundingClientRect();e.transition().duration(200).style("opacity",".9"),e.text(t.attr("title")).style("left",window.scrollX+s.left+(s.right-s.left)/2+"px").style("top",window.scrollY+s.bottom+"px"),e.html(e.html().replace(/<br\/>/g,"<br/>")),t.classed("hover",!0)})).on("mouseout",(function(){e.transition().duration(500).style("opacity",0);(0,h.Ltv)(this).classed("hover",!1)}))}),"setupToolTips");C.push(Y);var j=(0,l.K2)((function(t="gen-1"){f=new Map,k=new Map,y=[],C=[Y],b=[],E=new Map,D=0,m=new Map,x=!0,r=t,g=(0,l.D7)(),(0,l.IU)()}),"clear"),X=(0,l.K2)((t=>{r=t||"gen-2"}),"setGen"),z=(0,l.K2)((function(){return"fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;"}),"defaultStyle"),H=(0,l.K2)((function(t,e,s){let n=t.text.trim(),i=s.text;function u(t){const e={boolean:{},number:{},string:{}},s=[];let n;return{nodeList:t.filter((function(t){const r=typeof t;return t.stmt&&"dir"===t.stmt?(n=t.value,!1):""!==t.trim()&&(r in e?!e[r].hasOwnProperty(t)&&(e[r][t]=!0):!s.includes(t)&&s.push(t))})),dir:n}}t===s&&/\s/.exec(s.text)&&(n=void 0),(0,l.K2)(u,"uniq");const{nodeList:a,dir:o}=u(e.flat());if("gen-1"===r)for(let r=0;r<a.length;r++)a[r]=S(a[r]);n=n??"subGraph"+D,i=i||"",i=T(i),D+=1;const c={id:n,nodes:a,title:i.trim(),classes:[],dir:o,labelType:s.type};return l.Rm.info("Adding",c.id,c.nodes,c.dir),c.nodes=ct(c,b).nodes,b.push(c),E.set(n,c),n}),"addSubGraph"),q=(0,l.K2)((function(t){for(const[e,s]of b.entries())if(s.id===t)return e;return-1}),"getPosForId"),Q=-1,Z=[],J=(0,l.K2)((function(t,e){const s=b[e].nodes;if((Q+=1)>2e3)return{result:!1,count:0};if(Z[Q]=e,b[e].id===t)return{result:!0,count:0};let n=0,r=1;for(;n<s.length;){const e=q(s[n]);if(e>=0){const s=J(t,e);if(s.result)return{result:!0,count:r+s.count};r+=s.count}n+=1}return{result:!1,count:r}}),"indexNodes2"),tt=(0,l.K2)((function(t){return Z[t]}),"getDepthFirstPos"),et=(0,l.K2)((function(){Q=-1,b.length>0&&J("none",b.length-1)}),"indexNodes"),st=(0,l.K2)((function(){return b}),"getSubGraphs"),nt=(0,l.K2)((()=>!!x&&(x=!1,!0)),"firstGraph"),rt=(0,l.K2)((t=>{let e=t.trim(),s="arrow_open";switch(e[0]){case"<":s="arrow_point",e=e.slice(1);break;case"x":s="arrow_cross",e=e.slice(1);break;case"o":s="arrow_circle",e=e.slice(1)}let n="normal";return e.includes("=")&&(n="thick"),e.includes(".")&&(n="dotted"),{type:s,stroke:n}}),"destructStartLink"),it=(0,l.K2)(((t,e)=>{const s=e.length;let n=0;for(let r=0;r<s;++r)e[r]===t&&++n;return n}),"countChar"),ut=(0,l.K2)((t=>{const e=t.trim();let s=e.slice(0,-1),n="arrow_open";switch(e.slice(-1)){case"x":n="arrow_cross",e.startsWith("x")&&(n="double_"+n,s=s.slice(1));break;case">":n="arrow_point",e.startsWith("<")&&(n="double_"+n,s=s.slice(1));break;case"o":n="arrow_circle",e.startsWith("o")&&(n="double_"+n,s=s.slice(1))}let r="normal",i=s.length-1;s.startsWith("=")&&(r="thick"),s.startsWith("~")&&(r="invisible");const u=it(".",s);return u&&(r="dotted",i=u),{type:n,stroke:r,length:i}}),"destructEndLink"),at=(0,l.K2)(((t,e)=>{const s=ut(t);let n;if(e){if(n=rt(e),n.stroke!==s.stroke)return{type:"INVALID",stroke:"INVALID"};if("arrow_open"===n.type)n.type=s.type;else{if(n.type!==s.type)return{type:"INVALID",stroke:"INVALID"};n.type="double_"+n.type}return"double_arrow"===n.type&&(n.type="double_arrow_point"),n.length=s.length,n}return s}),"destructLink"),ot=(0,l.K2)(((t,e)=>{for(const s of t)if(s.nodes.includes(e))return!0;return!1}),"exists"),ct=(0,l.K2)(((t,e)=>{const s=[];return t.nodes.forEach(((n,r)=>{ot(e,n)||s.push(t.nodes[r])})),{nodes:s}}),"makeUniq"),lt={firstGraph:nt},ht=(0,l.K2)((t=>{if(t.img)return"imageSquare";if(t.icon)return"circle"===t.form?"iconCircle":"square"===t.form?"iconSquare":"rounded"===t.form?"iconRounded":"icon";switch(t.type){case"square":case void 0:return"squareRect";case"round":return"roundedRect";case"ellipse":return"ellipse";default:return t.type}}),"getTypeFromVertex"),dt=(0,l.K2)(((t,e)=>t.find((t=>t.id===e))),"findNode"),pt=(0,l.K2)((t=>{let e="none",s="arrow_point";switch(t){case"arrow_point":case"arrow_circle":case"arrow_cross":s=t;break;case"double_arrow_point":case"double_arrow_circle":case"double_arrow_cross":e=t.replace("double_",""),s=e}return{arrowTypeStart:e,arrowTypeEnd:s}}),"destructEdgeType"),At=(0,l.K2)(((t,e,s,n,r,i)=>{const u=s.get(t.id),a=n.get(t.id)??!1,o=dt(e,t.id);if(o)o.cssStyles=t.styles,o.cssCompiledStyles=gt(t.classes),o.cssClasses=t.classes.join(" ");else{const s={id:t.id,label:t.text,labelStyle:"",parentId:u,padding:r.flowchart?.padding||8,cssStyles:t.styles,cssCompiledStyles:gt(["default","node",...t.classes]),cssClasses:"default "+t.classes.join(" "),dir:t.dir,domId:t.domId,look:i,link:t.link,linkTarget:t.linkTarget,tooltip:P(t.id),icon:t.icon,pos:t.pos,img:t.img,assetWidth:t.assetWidth,assetHeight:t.assetHeight,constraint:t.constraint};a?e.push({...s,isGroup:!0,shape:"rect"}):e.push({...s,isGroup:!1,shape:ht(t)})}}),"addNodeFromVertex");function gt(t){let e=[];for(const s of t){const t=k.get(s);t?.styles&&(e=[...e,...t.styles??[]].map((t=>t.trim()))),t?.textStyles&&(e=[...e,...t.textStyles??[]].map((t=>t.trim())))}return e}(0,l.K2)(gt,"getCompiledStyles");var ft=(0,l.K2)((()=>{const t=(0,l.D7)(),e=[],s=[],n=st(),r=new Map,i=new Map;for(let a=n.length-1;a>=0;a--){const t=n[a];t.nodes.length>0&&i.set(t.id,!0);for(const e of t.nodes)r.set(e,t.id)}for(let a=n.length-1;a>=0;a--){const s=n[a];e.push({id:s.id,label:s.title,labelStyle:"",parentId:r.get(s.id),padding:8,cssCompiledStyles:gt(s.classes),cssClasses:s.classes.join(" "),shape:"rect",dir:s.dir,isGroup:!0,look:t.look})}U().forEach((s=>{At(s,e,r,i,t,t.look||"classic")}));const u=G();return u.forEach(((e,n)=>{const{arrowTypeStart:r,arrowTypeEnd:i}=pt(e.type),a=[...u.defaultStyle??[]];e.style&&a.push(...e.style);const o={id:(0,c.rY)(e.start,e.end,{counter:n,prefix:"L"}),start:e.start,end:e.end,type:e.type??"normal",label:e.text,labelpos:"c",thickness:e.stroke,minlen:e.length,classes:"invisible"===e?.stroke?"":"edge-thickness-normal edge-pattern-solid flowchart-link",arrowTypeStart:"invisible"===e?.stroke?"none":r,arrowTypeEnd:"invisible"===e?.stroke?"none":i,arrowheadStyle:"fill: #333",labelStyle:a,style:a,pattern:e.stroke,look:t.look};s.push(o)})),{nodes:e,edges:s,other:{},config:t}}),"getData"),yt={defaultConfig:(0,l.K2)((()=>l.ME.flowchart),"defaultConfig"),setAccTitle:l.SV,getAccTitle:l.iN,getAccDescription:l.m7,getData:ft,setAccDescription:l.EI,addVertex:F,lookUpDomId:S,addLink:B,updateLinkInterpolate:v,updateLink:w,addClass:$,setDirection:L,setClass:R,setTooltip:I,getTooltip:P,setClickEvent:O,setLink:N,bindFunctions:M,getDirection:V,getVertices:U,getEdges:G,getClasses:W,clear:j,setGen:X,defaultStyle:z,addSubGraph:H,getDepthFirstPos:tt,indexNodes:et,getSubGraphs:st,destructLink:at,lex:lt,exists:ot,makeUniq:ct,setDiagramTitle:l.ke,getDiagramTitle:l.ab},kt={getClasses:(0,l.K2)((function(t,e){return e.db.getClasses()}),"getClasses"),draw:(0,l.K2)((async function(t,e,s,n){l.Rm.info("REF0:"),l.Rm.info("Drawing state diagram (v2)",e);const{securityLevel:r,flowchart:u,layout:o}=(0,l.D7)();let d;"sandbox"===r&&(d=(0,h.Ltv)("#i"+e));const p="sandbox"===r?d.nodes()[0].contentDocument:document;l.Rm.debug("Before getData: ");const A=n.db.getData();l.Rm.debug("Data: ",A);const g=(0,i.A)(e,r),f=V();A.type=n.type,A.layoutAlgorithm=(0,a.q7)(o),"dagre"===A.layoutAlgorithm&&"elk"===o&&l.Rm.warn("flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](https://github.com/mermaid-js/mermaid/releases/tag/v11.0.0) for more details. This diagram will be rendered using `dagre` layout as a fallback."),A.direction=f,A.nodeSpacing=u?.nodeSpacing||50,A.rankSpacing=u?.rankSpacing||50,A.markers=["point","circle","cross"],A.diagramId=e,l.Rm.debug("REF1:",A),await(0,a.XX)(A,g);const y=A.config.flowchart?.diagramPadding??8;c._K.insertTitle(g,"flowchartTitleText",u?.titleTopMargin||0,n.db.getDiagramTitle()),(0,i.P)(g,y,"flowchart",u?.useMaxWidth||!1);for(const i of A.nodes){const t=(0,h.Ltv)(`#${e} [id="${i.id}"]`);if(!t||!i.link)continue;const s=p.createElementNS("http://www.w3.org/2000/svg","a");s.setAttributeNS("http://www.w3.org/2000/svg","class",i.cssClasses),s.setAttributeNS("http://www.w3.org/2000/svg","rel","noopener"),"sandbox"===r?s.setAttributeNS("http://www.w3.org/2000/svg","target","_top"):i.linkTarget&&s.setAttributeNS("http://www.w3.org/2000/svg","target",i.linkTarget);const n=t.insert((function(){return s}),":first-child"),u=t.select(".label-container");u&&n.append((function(){return u.node()}));const a=t.select(".label");a&&n.append((function(){return a.node()}))}}),"draw")},bt=function(){var t=(0,l.K2)((function(t,e,s,n){for(s=s||{},n=t.length;n--;s[t[n]]=e);return s}),"o"),e=[1,4],s=[1,3],n=[1,5],r=[1,8,9,10,11,27,34,36,38,44,60,83,84,85,86,87,88,101,104,105,108,110,113,114,115,120,121,122,123],i=[2,2],u=[1,13],a=[1,14],o=[1,15],c=[1,16],h=[1,23],d=[1,25],p=[1,26],A=[1,27],g=[1,49],f=[1,48],y=[1,29],k=[1,30],b=[1,31],E=[1,32],m=[1,33],D=[1,44],x=[1,46],C=[1,42],T=[1,47],S=[1,43],F=[1,50],_=[1,45],B=[1,51],v=[1,52],w=[1,34],$=[1,35],L=[1,36],R=[1,37],I=[1,57],K=[1,8,9,10,11,27,32,34,36,38,44,60,83,84,85,86,87,88,101,104,105,108,110,113,114,115,120,121,122,123],N=[1,61],P=[1,60],O=[1,62],M=[8,9,11,75,77],V=[1,77],U=[1,90],G=[1,95],W=[1,94],Y=[1,91],j=[1,87],X=[1,93],z=[1,89],H=[1,96],q=[1,92],Q=[1,97],Z=[1,88],J=[8,9,10,11,40,75,77],tt=[8,9,10,11,40,46,75,77],et=[8,9,10,11,29,40,44,46,48,50,52,54,56,58,60,63,65,67,68,70,75,77,88,101,104,105,108,110,113,114,115],st=[8,9,11,44,60,75,77,88,101,104,105,108,110,113,114,115],nt=[44,60,88,101,104,105,108,110,113,114,115],rt=[1,123],it=[1,122],ut=[1,130],at=[1,144],ot=[1,145],ct=[1,146],lt=[1,147],ht=[1,132],dt=[1,134],pt=[1,138],At=[1,139],gt=[1,140],ft=[1,141],yt=[1,142],kt=[1,143],bt=[1,148],Et=[1,149],mt=[1,128],Dt=[1,129],xt=[1,136],Ct=[1,131],Tt=[1,135],St=[1,133],Ft=[8,9,10,11,27,32,34,36,38,44,60,83,84,85,86,87,88,101,104,105,108,110,113,114,115,120,121,122,123],_t=[1,151],Bt=[1,153],vt=[8,9,11],wt=[8,9,10,11,14,44,60,88,104,105,108,110,113,114,115],$t=[1,173],Lt=[1,169],Rt=[1,170],It=[1,174],Kt=[1,171],Nt=[1,172],Pt=[77,115,118],Ot=[8,9,10,11,12,14,27,29,32,44,60,75,83,84,85,86,87,88,89,104,108,110,113,114,115],Mt=[10,105],Vt=[31,49,51,53,55,57,62,64,66,67,69,71,115,116,117],Ut=[1,242],Gt=[1,240],Wt=[1,244],Yt=[1,238],jt=[1,239],Xt=[1,241],zt=[1,243],Ht=[1,245],qt=[1,263],Qt=[8,9,11,105],Zt=[8,9,10,11,60,83,104,105,108,109,110,111],Jt={trace:(0,l.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,graphConfig:4,document:5,line:6,statement:7,SEMI:8,NEWLINE:9,SPACE:10,EOF:11,GRAPH:12,NODIR:13,DIR:14,FirstStmtSeparator:15,ending:16,endToken:17,spaceList:18,spaceListNewline:19,vertexStatement:20,separator:21,styleStatement:22,linkStyleStatement:23,classDefStatement:24,classStatement:25,clickStatement:26,subgraph:27,textNoTags:28,SQS:29,text:30,SQE:31,end:32,direction:33,acc_title:34,acc_title_value:35,acc_descr:36,acc_descr_value:37,acc_descr_multiline_value:38,shapeData:39,SHAPE_DATA:40,link:41,node:42,styledVertex:43,AMP:44,vertex:45,STYLE_SEPARATOR:46,idString:47,DOUBLECIRCLESTART:48,DOUBLECIRCLEEND:49,PS:50,PE:51,"(-":52,"-)":53,STADIUMSTART:54,STADIUMEND:55,SUBROUTINESTART:56,SUBROUTINEEND:57,VERTEX_WITH_PROPS_START:58,"NODE_STRING[field]":59,COLON:60,"NODE_STRING[value]":61,PIPE:62,CYLINDERSTART:63,CYLINDEREND:64,DIAMOND_START:65,DIAMOND_STOP:66,TAGEND:67,TRAPSTART:68,TRAPEND:69,INVTRAPSTART:70,INVTRAPEND:71,linkStatement:72,arrowText:73,TESTSTR:74,START_LINK:75,edgeText:76,LINK:77,edgeTextToken:78,STR:79,MD_STR:80,textToken:81,keywords:82,STYLE:83,LINKSTYLE:84,CLASSDEF:85,CLASS:86,CLICK:87,DOWN:88,UP:89,textNoTagsToken:90,stylesOpt:91,"idString[vertex]":92,"idString[class]":93,CALLBACKNAME:94,CALLBACKARGS:95,HREF:96,LINK_TARGET:97,"STR[link]":98,"STR[tooltip]":99,alphaNum:100,DEFAULT:101,numList:102,INTERPOLATE:103,NUM:104,COMMA:105,style:106,styleComponent:107,NODE_STRING:108,UNIT:109,BRKT:110,PCT:111,idStringToken:112,MINUS:113,MULT:114,UNICODE_TEXT:115,TEXT:116,TAGSTART:117,EDGE_TEXT:118,alphaNumToken:119,direction_tb:120,direction_bt:121,direction_rl:122,direction_lr:123,$accept:0,$end:1},terminals_:{2:"error",8:"SEMI",9:"NEWLINE",10:"SPACE",11:"EOF",12:"GRAPH",13:"NODIR",14:"DIR",27:"subgraph",29:"SQS",31:"SQE",32:"end",34:"acc_title",35:"acc_title_value",36:"acc_descr",37:"acc_descr_value",38:"acc_descr_multiline_value",40:"SHAPE_DATA",44:"AMP",46:"STYLE_SEPARATOR",48:"DOUBLECIRCLESTART",49:"DOUBLECIRCLEEND",50:"PS",51:"PE",52:"(-",53:"-)",54:"STADIUMSTART",55:"STADIUMEND",56:"SUBROUTINESTART",57:"SUBROUTINEEND",58:"VERTEX_WITH_PROPS_START",59:"NODE_STRING[field]",60:"COLON",61:"NODE_STRING[value]",62:"PIPE",63:"CYLINDERSTART",64:"CYLINDEREND",65:"DIAMOND_START",66:"DIAMOND_STOP",67:"TAGEND",68:"TRAPSTART",69:"TRAPEND",70:"INVTRAPSTART",71:"INVTRAPEND",74:"TESTSTR",75:"START_LINK",77:"LINK",79:"STR",80:"MD_STR",83:"STYLE",84:"LINKSTYLE",85:"CLASSDEF",86:"CLASS",87:"CLICK",88:"DOWN",89:"UP",92:"idString[vertex]",93:"idString[class]",94:"CALLBACKNAME",95:"CALLBACKARGS",96:"HREF",97:"LINK_TARGET",98:"STR[link]",99:"STR[tooltip]",101:"DEFAULT",103:"INTERPOLATE",104:"NUM",105:"COMMA",108:"NODE_STRING",109:"UNIT",110:"BRKT",111:"PCT",113:"MINUS",114:"MULT",115:"UNICODE_TEXT",116:"TEXT",117:"TAGSTART",118:"EDGE_TEXT",120:"direction_tb",121:"direction_bt",122:"direction_rl",123:"direction_lr"},productions_:[0,[3,2],[5,0],[5,2],[6,1],[6,1],[6,1],[6,1],[6,1],[4,2],[4,2],[4,2],[4,3],[16,2],[16,1],[17,1],[17,1],[17,1],[15,1],[15,1],[15,2],[19,2],[19,2],[19,1],[19,1],[18,2],[18,1],[7,2],[7,2],[7,2],[7,2],[7,2],[7,2],[7,9],[7,6],[7,4],[7,1],[7,2],[7,2],[7,1],[21,1],[21,1],[21,1],[39,2],[39,1],[20,4],[20,3],[20,4],[20,2],[20,2],[20,1],[42,1],[42,6],[42,5],[43,1],[43,3],[45,4],[45,4],[45,6],[45,4],[45,4],[45,4],[45,8],[45,4],[45,4],[45,4],[45,6],[45,4],[45,4],[45,4],[45,4],[45,4],[45,1],[41,2],[41,3],[41,3],[41,1],[41,3],[76,1],[76,2],[76,1],[76,1],[72,1],[73,3],[30,1],[30,2],[30,1],[30,1],[82,1],[82,1],[82,1],[82,1],[82,1],[82,1],[82,1],[82,1],[82,1],[82,1],[82,1],[28,1],[28,2],[28,1],[28,1],[24,5],[25,5],[26,2],[26,4],[26,3],[26,5],[26,3],[26,5],[26,5],[26,7],[26,2],[26,4],[26,2],[26,4],[26,4],[26,6],[22,5],[23,5],[23,5],[23,9],[23,9],[23,7],[23,7],[102,1],[102,3],[91,1],[91,3],[106,1],[106,2],[107,1],[107,1],[107,1],[107,1],[107,1],[107,1],[107,1],[107,1],[112,1],[112,1],[112,1],[112,1],[112,1],[112,1],[112,1],[112,1],[112,1],[112,1],[112,1],[81,1],[81,1],[81,1],[81,1],[90,1],[90,1],[90,1],[90,1],[90,1],[90,1],[90,1],[90,1],[90,1],[90,1],[90,1],[78,1],[78,1],[119,1],[119,1],[119,1],[119,1],[119,1],[119,1],[119,1],[119,1],[119,1],[119,1],[119,1],[47,1],[47,2],[100,1],[100,2],[33,1],[33,1],[33,1],[33,1]],performAction:(0,l.K2)((function(t,e,s,n,r,i,u){var a=i.length-1;switch(r){case 2:case 28:case 29:case 30:case 31:case 32:this.$=[];break;case 3:(!Array.isArray(i[a])||i[a].length>0)&&i[a-1].push(i[a]),this.$=i[a-1];break;case 4:case 181:case 44:case 54:case 76:case 179:this.$=i[a];break;case 11:n.setDirection("TB"),this.$="TB";break;case 12:n.setDirection(i[a-1]),this.$=i[a-1];break;case 27:this.$=i[a-1].nodes;break;case 33:this.$=n.addSubGraph(i[a-6],i[a-1],i[a-4]);break;case 34:this.$=n.addSubGraph(i[a-3],i[a-1],i[a-3]);break;case 35:this.$=n.addSubGraph(void 0,i[a-1],void 0);break;case 37:this.$=i[a].trim(),n.setAccTitle(this.$);break;case 38:case 39:this.$=i[a].trim(),n.setAccDescription(this.$);break;case 43:case 131:this.$=i[a-1]+i[a];break;case 45:n.addVertex(i[a-1][0],void 0,void 0,void 0,void 0,void 0,void 0,i[a]),n.addLink(i[a-3].stmt,i[a-1],i[a-2]),this.$={stmt:i[a-1],nodes:i[a-1].concat(i[a-3].nodes)};break;case 46:n.addLink(i[a-2].stmt,i[a],i[a-1]),this.$={stmt:i[a],nodes:i[a].concat(i[a-2].nodes)};break;case 47:n.addLink(i[a-3].stmt,i[a-1],i[a-2]),this.$={stmt:i[a-1],nodes:i[a-1].concat(i[a-3].nodes)};break;case 48:this.$={stmt:i[a-1],nodes:i[a-1]};break;case 49:n.addVertex(i[a-1][0],void 0,void 0,void 0,void 0,void 0,void 0,i[a]),this.$={stmt:i[a-1],nodes:i[a-1],shapeData:i[a]};break;case 50:this.$={stmt:i[a],nodes:i[a]};break;case 51:case 126:case 128:this.$=[i[a]];break;case 52:n.addVertex(i[a-5][0],void 0,void 0,void 0,void 0,void 0,void 0,i[a-4]),this.$=i[a-5].concat(i[a]);break;case 53:this.$=i[a-4].concat(i[a]);break;case 55:this.$=i[a-2],n.setClass(i[a-2],i[a]);break;case 56:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"square");break;case 57:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"doublecircle");break;case 58:this.$=i[a-5],n.addVertex(i[a-5],i[a-2],"circle");break;case 59:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"ellipse");break;case 60:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"stadium");break;case 61:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"subroutine");break;case 62:this.$=i[a-7],n.addVertex(i[a-7],i[a-1],"rect",void 0,void 0,void 0,Object.fromEntries([[i[a-5],i[a-3]]]));break;case 63:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"cylinder");break;case 64:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"round");break;case 65:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"diamond");break;case 66:this.$=i[a-5],n.addVertex(i[a-5],i[a-2],"hexagon");break;case 67:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"odd");break;case 68:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"trapezoid");break;case 69:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"inv_trapezoid");break;case 70:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"lean_right");break;case 71:this.$=i[a-3],n.addVertex(i[a-3],i[a-1],"lean_left");break;case 72:this.$=i[a],n.addVertex(i[a]);break;case 73:i[a-1].text=i[a],this.$=i[a-1];break;case 74:case 75:i[a-2].text=i[a-1],this.$=i[a-2];break;case 77:var o=n.destructLink(i[a],i[a-2]);this.$={type:o.type,stroke:o.stroke,length:o.length,text:i[a-1]};break;case 78:case 84:case 99:case 101:this.$={text:i[a],type:"text"};break;case 79:case 85:case 100:this.$={text:i[a-1].text+""+i[a],type:i[a-1].type};break;case 80:case 86:this.$={text:i[a],type:"string"};break;case 81:case 87:case 102:this.$={text:i[a],type:"markdown"};break;case 82:o=n.destructLink(i[a]);this.$={type:o.type,stroke:o.stroke,length:o.length};break;case 83:this.$=i[a-1];break;case 103:this.$=i[a-4],n.addClass(i[a-2],i[a]);break;case 104:this.$=i[a-4],n.setClass(i[a-2],i[a]);break;case 105:case 113:this.$=i[a-1],n.setClickEvent(i[a-1],i[a]);break;case 106:case 114:this.$=i[a-3],n.setClickEvent(i[a-3],i[a-2]),n.setTooltip(i[a-3],i[a]);break;case 107:this.$=i[a-2],n.setClickEvent(i[a-2],i[a-1],i[a]);break;case 108:this.$=i[a-4],n.setClickEvent(i[a-4],i[a-3],i[a-2]),n.setTooltip(i[a-4],i[a]);break;case 109:this.$=i[a-2],n.setLink(i[a-2],i[a]);break;case 110:this.$=i[a-4],n.setLink(i[a-4],i[a-2]),n.setTooltip(i[a-4],i[a]);break;case 111:this.$=i[a-4],n.setLink(i[a-4],i[a-2],i[a]);break;case 112:this.$=i[a-6],n.setLink(i[a-6],i[a-4],i[a]),n.setTooltip(i[a-6],i[a-2]);break;case 115:this.$=i[a-1],n.setLink(i[a-1],i[a]);break;case 116:this.$=i[a-3],n.setLink(i[a-3],i[a-2]),n.setTooltip(i[a-3],i[a]);break;case 117:this.$=i[a-3],n.setLink(i[a-3],i[a-2],i[a]);break;case 118:this.$=i[a-5],n.setLink(i[a-5],i[a-4],i[a]),n.setTooltip(i[a-5],i[a-2]);break;case 119:this.$=i[a-4],n.addVertex(i[a-2],void 0,void 0,i[a]);break;case 120:this.$=i[a-4],n.updateLink([i[a-2]],i[a]);break;case 121:this.$=i[a-4],n.updateLink(i[a-2],i[a]);break;case 122:this.$=i[a-8],n.updateLinkInterpolate([i[a-6]],i[a-2]),n.updateLink([i[a-6]],i[a]);break;case 123:this.$=i[a-8],n.updateLinkInterpolate(i[a-6],i[a-2]),n.updateLink(i[a-6],i[a]);break;case 124:this.$=i[a-6],n.updateLinkInterpolate([i[a-4]],i[a]);break;case 125:this.$=i[a-6],n.updateLinkInterpolate(i[a-4],i[a]);break;case 127:case 129:i[a-2].push(i[a]),this.$=i[a-2];break;case 180:case 182:this.$=i[a-1]+""+i[a];break;case 183:this.$={stmt:"dir",value:"TB"};break;case 184:this.$={stmt:"dir",value:"BT"};break;case 185:this.$={stmt:"dir",value:"RL"};break;case 186:this.$={stmt:"dir",value:"LR"}}}),"anonymous"),table:[{3:1,4:2,9:e,10:s,12:n},{1:[3]},t(r,i,{5:6}),{4:7,9:e,10:s,12:n},{4:8,9:e,10:s,12:n},{13:[1,9],14:[1,10]},{1:[2,1],6:11,7:12,8:u,9:a,10:o,11:c,20:17,22:18,23:19,24:20,25:21,26:22,27:h,33:24,34:d,36:p,38:A,42:28,43:38,44:g,45:39,47:40,60:f,83:y,84:k,85:b,86:E,87:m,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v,120:w,121:$,122:L,123:R},t(r,[2,9]),t(r,[2,10]),t(r,[2,11]),{8:[1,54],9:[1,55],10:I,15:53,18:56},t(K,[2,3]),t(K,[2,4]),t(K,[2,5]),t(K,[2,6]),t(K,[2,7]),t(K,[2,8]),{8:N,9:P,11:O,21:58,41:59,72:63,75:[1,64],77:[1,65]},{8:N,9:P,11:O,21:66},{8:N,9:P,11:O,21:67},{8:N,9:P,11:O,21:68},{8:N,9:P,11:O,21:69},{8:N,9:P,11:O,21:70},{8:N,9:P,10:[1,71],11:O,21:72},t(K,[2,36]),{35:[1,73]},{37:[1,74]},t(K,[2,39]),t(M,[2,50],{18:75,39:76,10:I,40:V}),{10:[1,78]},{10:[1,79]},{10:[1,80]},{10:[1,81]},{14:U,44:G,60:W,79:[1,85],88:Y,94:[1,82],96:[1,83],100:84,104:j,105:X,108:z,110:H,113:q,114:Q,115:Z,119:86},t(K,[2,183]),t(K,[2,184]),t(K,[2,185]),t(K,[2,186]),t(J,[2,51]),t(J,[2,54],{46:[1,98]}),t(tt,[2,72],{112:111,29:[1,99],44:g,48:[1,100],50:[1,101],52:[1,102],54:[1,103],56:[1,104],58:[1,105],60:f,63:[1,106],65:[1,107],67:[1,108],68:[1,109],70:[1,110],88:D,101:x,104:C,105:T,108:S,110:F,113:_,114:B,115:v}),t(et,[2,179]),t(et,[2,140]),t(et,[2,141]),t(et,[2,142]),t(et,[2,143]),t(et,[2,144]),t(et,[2,145]),t(et,[2,146]),t(et,[2,147]),t(et,[2,148]),t(et,[2,149]),t(et,[2,150]),t(r,[2,12]),t(r,[2,18]),t(r,[2,19]),{9:[1,112]},t(st,[2,26],{18:113,10:I}),t(K,[2,27]),{42:114,43:38,44:g,45:39,47:40,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},t(K,[2,40]),t(K,[2,41]),t(K,[2,42]),t(nt,[2,76],{73:115,62:[1,117],74:[1,116]}),{76:118,78:119,79:[1,120],80:[1,121],115:rt,118:it},t([44,60,62,74,88,101,104,105,108,110,113,114,115],[2,82]),t(K,[2,28]),t(K,[2,29]),t(K,[2,30]),t(K,[2,31]),t(K,[2,32]),{10:ut,12:at,14:ot,27:ct,28:124,32:lt,44:ht,60:dt,75:pt,79:[1,126],80:[1,127],82:137,83:At,84:gt,85:ft,86:yt,87:kt,88:bt,89:Et,90:125,104:mt,108:Dt,110:xt,113:Ct,114:Tt,115:St},t(Ft,i,{5:150}),t(K,[2,37]),t(K,[2,38]),t(M,[2,48],{44:_t}),t(M,[2,49],{18:152,10:I,40:Bt}),t(J,[2,44]),{44:g,47:154,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},{101:[1,155],102:156,104:[1,157]},{44:g,47:158,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},{44:g,47:159,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},t(vt,[2,105],{10:[1,160],95:[1,161]}),{79:[1,162]},t(vt,[2,113],{119:164,10:[1,163],14:U,44:G,60:W,88:Y,104:j,105:X,108:z,110:H,113:q,114:Q,115:Z}),t(vt,[2,115],{10:[1,165]}),t(wt,[2,181]),t(wt,[2,168]),t(wt,[2,169]),t(wt,[2,170]),t(wt,[2,171]),t(wt,[2,172]),t(wt,[2,173]),t(wt,[2,174]),t(wt,[2,175]),t(wt,[2,176]),t(wt,[2,177]),t(wt,[2,178]),{44:g,47:166,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},{30:167,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:175,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:177,50:[1,176],67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:178,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:179,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:180,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{108:[1,181]},{30:182,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:183,65:[1,184],67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:185,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:186,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{30:187,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},t(et,[2,180]),t(r,[2,20]),t(st,[2,25]),t(M,[2,46],{39:188,18:189,10:I,40:V}),t(nt,[2,73],{10:[1,190]}),{10:[1,191]},{30:192,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{77:[1,193],78:194,115:rt,118:it},t(Pt,[2,78]),t(Pt,[2,80]),t(Pt,[2,81]),t(Pt,[2,166]),t(Pt,[2,167]),{8:N,9:P,10:ut,11:O,12:at,14:ot,21:196,27:ct,29:[1,195],32:lt,44:ht,60:dt,75:pt,82:137,83:At,84:gt,85:ft,86:yt,87:kt,88:bt,89:Et,90:197,104:mt,108:Dt,110:xt,113:Ct,114:Tt,115:St},t(Ot,[2,99]),t(Ot,[2,101]),t(Ot,[2,102]),t(Ot,[2,155]),t(Ot,[2,156]),t(Ot,[2,157]),t(Ot,[2,158]),t(Ot,[2,159]),t(Ot,[2,160]),t(Ot,[2,161]),t(Ot,[2,162]),t(Ot,[2,163]),t(Ot,[2,164]),t(Ot,[2,165]),t(Ot,[2,88]),t(Ot,[2,89]),t(Ot,[2,90]),t(Ot,[2,91]),t(Ot,[2,92]),t(Ot,[2,93]),t(Ot,[2,94]),t(Ot,[2,95]),t(Ot,[2,96]),t(Ot,[2,97]),t(Ot,[2,98]),{6:11,7:12,8:u,9:a,10:o,11:c,20:17,22:18,23:19,24:20,25:21,26:22,27:h,32:[1,198],33:24,34:d,36:p,38:A,42:28,43:38,44:g,45:39,47:40,60:f,83:y,84:k,85:b,86:E,87:m,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v,120:w,121:$,122:L,123:R},{10:I,18:199},{44:[1,200]},t(J,[2,43]),{10:[1,201],44:g,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:111,113:_,114:B,115:v},{10:[1,202]},{10:[1,203],105:[1,204]},t(Mt,[2,126]),{10:[1,205],44:g,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:111,113:_,114:B,115:v},{10:[1,206],44:g,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:111,113:_,114:B,115:v},{79:[1,207]},t(vt,[2,107],{10:[1,208]}),t(vt,[2,109],{10:[1,209]}),{79:[1,210]},t(wt,[2,182]),{79:[1,211],97:[1,212]},t(J,[2,55],{112:111,44:g,60:f,88:D,101:x,104:C,105:T,108:S,110:F,113:_,114:B,115:v}),{31:[1,213],67:$t,81:214,115:It,116:Kt,117:Nt},t(Vt,[2,84]),t(Vt,[2,86]),t(Vt,[2,87]),t(Vt,[2,151]),t(Vt,[2,152]),t(Vt,[2,153]),t(Vt,[2,154]),{49:[1,215],67:$t,81:214,115:It,116:Kt,117:Nt},{30:216,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{51:[1,217],67:$t,81:214,115:It,116:Kt,117:Nt},{53:[1,218],67:$t,81:214,115:It,116:Kt,117:Nt},{55:[1,219],67:$t,81:214,115:It,116:Kt,117:Nt},{57:[1,220],67:$t,81:214,115:It,116:Kt,117:Nt},{60:[1,221]},{64:[1,222],67:$t,81:214,115:It,116:Kt,117:Nt},{66:[1,223],67:$t,81:214,115:It,116:Kt,117:Nt},{30:224,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},{31:[1,225],67:$t,81:214,115:It,116:Kt,117:Nt},{67:$t,69:[1,226],71:[1,227],81:214,115:It,116:Kt,117:Nt},{67:$t,69:[1,229],71:[1,228],81:214,115:It,116:Kt,117:Nt},t(M,[2,45],{18:152,10:I,40:Bt}),t(M,[2,47],{44:_t}),t(nt,[2,75]),t(nt,[2,74]),{62:[1,230],67:$t,81:214,115:It,116:Kt,117:Nt},t(nt,[2,77]),t(Pt,[2,79]),{30:231,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},t(Ft,i,{5:232}),t(Ot,[2,100]),t(K,[2,35]),{43:233,44:g,45:39,47:40,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},{10:I,18:234},{10:Ut,60:Gt,83:Wt,91:235,104:Yt,106:236,107:237,108:jt,109:Xt,110:zt,111:Ht},{10:Ut,60:Gt,83:Wt,91:246,103:[1,247],104:Yt,106:236,107:237,108:jt,109:Xt,110:zt,111:Ht},{10:Ut,60:Gt,83:Wt,91:248,103:[1,249],104:Yt,106:236,107:237,108:jt,109:Xt,110:zt,111:Ht},{104:[1,250]},{10:Ut,60:Gt,83:Wt,91:251,104:Yt,106:236,107:237,108:jt,109:Xt,110:zt,111:Ht},{44:g,47:252,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},t(vt,[2,106]),{79:[1,253]},{79:[1,254],97:[1,255]},t(vt,[2,114]),t(vt,[2,116],{10:[1,256]}),t(vt,[2,117]),t(tt,[2,56]),t(Vt,[2,85]),t(tt,[2,57]),{51:[1,257],67:$t,81:214,115:It,116:Kt,117:Nt},t(tt,[2,64]),t(tt,[2,59]),t(tt,[2,60]),t(tt,[2,61]),{108:[1,258]},t(tt,[2,63]),t(tt,[2,65]),{66:[1,259],67:$t,81:214,115:It,116:Kt,117:Nt},t(tt,[2,67]),t(tt,[2,68]),t(tt,[2,70]),t(tt,[2,69]),t(tt,[2,71]),t([10,44,60,88,101,104,105,108,110,113,114,115],[2,83]),{31:[1,260],67:$t,81:214,115:It,116:Kt,117:Nt},{6:11,7:12,8:u,9:a,10:o,11:c,20:17,22:18,23:19,24:20,25:21,26:22,27:h,32:[1,261],33:24,34:d,36:p,38:A,42:28,43:38,44:g,45:39,47:40,60:f,83:y,84:k,85:b,86:E,87:m,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v,120:w,121:$,122:L,123:R},t(J,[2,53]),{43:262,44:g,45:39,47:40,60:f,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v},t(vt,[2,119],{105:qt}),t(Qt,[2,128],{107:264,10:Ut,60:Gt,83:Wt,104:Yt,108:jt,109:Xt,110:zt,111:Ht}),t(Zt,[2,130]),t(Zt,[2,132]),t(Zt,[2,133]),t(Zt,[2,134]),t(Zt,[2,135]),t(Zt,[2,136]),t(Zt,[2,137]),t(Zt,[2,138]),t(Zt,[2,139]),t(vt,[2,120],{105:qt}),{10:[1,265]},t(vt,[2,121],{105:qt}),{10:[1,266]},t(Mt,[2,127]),t(vt,[2,103],{105:qt}),t(vt,[2,104],{112:111,44:g,60:f,88:D,101:x,104:C,105:T,108:S,110:F,113:_,114:B,115:v}),t(vt,[2,108]),t(vt,[2,110],{10:[1,267]}),t(vt,[2,111]),{97:[1,268]},{51:[1,269]},{62:[1,270]},{66:[1,271]},{8:N,9:P,11:O,21:272},t(K,[2,34]),t(J,[2,52]),{10:Ut,60:Gt,83:Wt,104:Yt,106:273,107:237,108:jt,109:Xt,110:zt,111:Ht},t(Zt,[2,131]),{14:U,44:G,60:W,88:Y,100:274,104:j,105:X,108:z,110:H,113:q,114:Q,115:Z,119:86},{14:U,44:G,60:W,88:Y,100:275,104:j,105:X,108:z,110:H,113:q,114:Q,115:Z,119:86},{97:[1,276]},t(vt,[2,118]),t(tt,[2,58]),{30:277,67:$t,79:Lt,80:Rt,81:168,115:It,116:Kt,117:Nt},t(tt,[2,66]),t(Ft,i,{5:278}),t(Qt,[2,129],{107:264,10:Ut,60:Gt,83:Wt,104:Yt,108:jt,109:Xt,110:zt,111:Ht}),t(vt,[2,124],{119:164,10:[1,279],14:U,44:G,60:W,88:Y,104:j,105:X,108:z,110:H,113:q,114:Q,115:Z}),t(vt,[2,125],{119:164,10:[1,280],14:U,44:G,60:W,88:Y,104:j,105:X,108:z,110:H,113:q,114:Q,115:Z}),t(vt,[2,112]),{31:[1,281],67:$t,81:214,115:It,116:Kt,117:Nt},{6:11,7:12,8:u,9:a,10:o,11:c,20:17,22:18,23:19,24:20,25:21,26:22,27:h,32:[1,282],33:24,34:d,36:p,38:A,42:28,43:38,44:g,45:39,47:40,60:f,83:y,84:k,85:b,86:E,87:m,88:D,101:x,104:C,105:T,108:S,110:F,112:41,113:_,114:B,115:v,120:w,121:$,122:L,123:R},{10:Ut,60:Gt,83:Wt,91:283,104:Yt,106:236,107:237,108:jt,109:Xt,110:zt,111:Ht},{10:Ut,60:Gt,83:Wt,91:284,104:Yt,106:236,107:237,108:jt,109:Xt,110:zt,111:Ht},t(tt,[2,62]),t(K,[2,33]),t(vt,[2,122],{105:qt}),t(vt,[2,123],{105:qt})],defaultActions:{},parseError:(0,l.K2)((function(t,e){if(!e.recoverable){var s=new Error(t);throw s.hash=e,s}this.trace(t)}),"parseError"),parse:(0,l.K2)((function(t){var e=this,s=[0],n=[],r=[null],i=[],u=this.table,a="",o=0,c=0,h=0,d=i.slice.call(arguments,1),p=Object.create(this.lexer),A={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(A.yy[g]=this.yy[g]);p.setInput(t,A.yy),A.yy.lexer=p,A.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var f=p.yylloc;i.push(f);var y=p.options&&p.options.ranges;function k(){var t;return"number"!=typeof(t=n.pop()||p.lex()||1)&&(t instanceof Array&&(t=(n=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof A.yy.parseError?this.parseError=A.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,l.K2)((function(t){s.length=s.length-2*t,r.length=r.length-t,i.length=i.length-t}),"popStack"),(0,l.K2)(k,"lex");for(var b,E,m,D,x,C,T,S,F,_={};;){if(m=s[s.length-1],this.defaultActions[m]?D=this.defaultActions[m]:(null==b&&(b=k()),D=u[m]&&u[m][b]),void 0===D||!D.length||!D[0]){var B="";for(C in F=[],u[m])this.terminals_[C]&&C>2&&F.push("'"+this.terminals_[C]+"'");B=p.showPosition?"Parse error on line "+(o+1)+":\n"+p.showPosition()+"\nExpecting "+F.join(", ")+", got '"+(this.terminals_[b]||b)+"'":"Parse error on line "+(o+1)+": Unexpected "+(1==b?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(B,{text:p.match,token:this.terminals_[b]||b,line:p.yylineno,loc:f,expected:F})}if(D[0]instanceof Array&&D.length>1)throw new Error("Parse Error: multiple actions possible at state: "+m+", token: "+b);switch(D[0]){case 1:s.push(b),r.push(p.yytext),i.push(p.yylloc),s.push(D[1]),b=null,E?(b=E,E=null):(c=p.yyleng,a=p.yytext,o=p.yylineno,f=p.yylloc,h>0&&h--);break;case 2:if(T=this.productions_[D[1]][1],_.$=r[r.length-T],_._$={first_line:i[i.length-(T||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(T||1)].first_column,last_column:i[i.length-1].last_column},y&&(_._$.range=[i[i.length-(T||1)].range[0],i[i.length-1].range[1]]),void 0!==(x=this.performAction.apply(_,[a,c,o,A.yy,D[1],r,i].concat(d))))return x;T&&(s=s.slice(0,-1*T*2),r=r.slice(0,-1*T),i=i.slice(0,-1*T)),s.push(this.productions_[D[1]][0]),r.push(_.$),i.push(_._$),S=u[s[s.length-2]][s[s.length-1]],s.push(S);break;case 3:return!0}}return!0}),"parse")},te=function(){return{EOF:1,parseError:(0,l.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,l.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,l.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,l.K2)((function(t){var e=t.length,s=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),s.length-1&&(this.yylineno-=s.length-1);var r=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:s?(s.length===n.length?this.yylloc.first_column:0)+n[n.length-s.length].length-s[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[r[0],r[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,l.K2)((function(){return this._more=!0,this}),"more"),reject:(0,l.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,l.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,l.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,l.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,l.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,l.K2)((function(t,e){var s,n,r;if(this.options.backtrack_lexer&&(r={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(r.yylloc.range=this.yylloc.range.slice(0))),(n=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=n.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-n[n.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],s=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),s)return s;if(this._backtrack){for(var i in r)this[i]=r[i];return!1}return!1}),"test_match"),next:(0,l.K2)((function(){if(this.done)return this.EOF;var t,e,s,n;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var r=this._currentRules(),i=0;i<r.length;i++)if((s=this._input.match(this.rules[r[i]]))&&(!e||s[0].length>e[0].length)){if(e=s,n=i,this.options.backtrack_lexer){if(!1!==(t=this.test_match(s,r[i])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,r[n]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,l.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,l.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,l.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,l.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,l.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,l.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,l.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{},performAction:(0,l.K2)((function(t,e,s,n){switch(s){case 0:return this.begin("acc_title"),34;case 1:return this.popState(),"acc_title_value";case 2:return this.begin("acc_descr"),36;case 3:return this.popState(),"acc_descr_value";case 4:this.begin("acc_descr_multiline");break;case 5:case 12:case 14:case 17:case 20:case 23:case 33:this.popState();break;case 6:return"acc_descr_multiline_value";case 7:return this.pushState("shapeData"),e.yytext="",40;case 8:return this.pushState("shapeDataStr"),40;case 9:return this.popState(),40;case 10:const s=/\n\s*/g;return e.yytext=e.yytext.replace(s,"<br/>"),40;case 11:return 40;case 13:this.begin("callbackname");break;case 15:this.popState(),this.begin("callbackargs");break;case 16:return 94;case 18:return 95;case 19:return"MD_STR";case 21:this.begin("md_string");break;case 22:return"STR";case 24:this.pushState("string");break;case 25:return 83;case 26:return 101;case 27:return 84;case 28:return 103;case 29:return 85;case 30:return 86;case 31:return 96;case 32:this.begin("click");break;case 34:return 87;case 35:case 36:case 37:return t.lex.firstGraph()&&this.begin("dir"),12;case 38:return 27;case 39:return 32;case 40:case 41:case 42:case 43:return 97;case 44:return this.popState(),13;case 45:case 46:case 47:case 48:case 49:case 50:case 51:case 52:case 53:case 54:return this.popState(),14;case 55:return 120;case 56:return 121;case 57:return 122;case 58:return 123;case 59:return 104;case 60:case 101:return 110;case 61:return 46;case 62:return 60;case 63:case 102:return 44;case 64:return 8;case 65:return 105;case 66:case 100:return 114;case 67:case 70:case 73:return this.popState(),77;case 68:return this.pushState("edgeText"),75;case 69:case 72:case 75:return 118;case 71:return this.pushState("thickEdgeText"),75;case 74:return this.pushState("dottedEdgeText"),75;case 76:return 77;case 77:return this.popState(),53;case 78:case 114:return"TEXT";case 79:return this.pushState("ellipseText"),52;case 80:return this.popState(),55;case 81:return this.pushState("text"),54;case 82:return this.popState(),57;case 83:return this.pushState("text"),56;case 84:return 58;case 85:return this.pushState("text"),67;case 86:return this.popState(),64;case 87:return this.pushState("text"),63;case 88:return this.popState(),49;case 89:return this.pushState("text"),48;case 90:return this.popState(),69;case 91:return this.popState(),71;case 92:return 116;case 93:return this.pushState("trapText"),68;case 94:return this.pushState("trapText"),70;case 95:return 117;case 96:return 67;case 97:return 89;case 98:return"SEP";case 99:return 88;case 103:return 108;case 104:return 113;case 105:return 115;case 106:return this.popState(),62;case 107:return this.pushState("text"),62;case 108:return this.popState(),51;case 109:return this.pushState("text"),50;case 110:return this.popState(),31;case 111:return this.pushState("text"),29;case 112:return this.popState(),66;case 113:return this.pushState("text"),65;case 115:return"QUOTE";case 116:return 9;case 117:return 10;case 118:return 11}}),"anonymous"),rules:[/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:@\{)/,/^(?:["])/,/^(?:["])/,/^(?:[^\"]+)/,/^(?:[^}^"]+)/,/^(?:\})/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:[^`"]+)/,/^(?:[`]["])/,/^(?:["][`])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:["])/,/^(?:style\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\b)/,/^(?:class\b)/,/^(?:href[\s])/,/^(?:click[\s]+)/,/^(?:[\s\n])/,/^(?:[^\s\n]*)/,/^(?:flowchart-elk\b)/,/^(?:graph\b)/,/^(?:flowchart\b)/,/^(?:subgraph\b)/,/^(?:end\b\s*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:(\r?\n)*\s*\n)/,/^(?:\s*LR\b)/,/^(?:\s*RL\b)/,/^(?:\s*TB\b)/,/^(?:\s*BT\b)/,/^(?:\s*TD\b)/,/^(?:\s*BR\b)/,/^(?:\s*<)/,/^(?:\s*>)/,/^(?:\s*\^)/,/^(?:\s*v\b)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:[0-9]+)/,/^(?:#)/,/^(?::::)/,/^(?::)/,/^(?:&)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:[^-]|-(?!-)+)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:[^=]|=(?!))/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:[^\.]|\.(?!))/,/^(?:\s*~~[\~]+\s*)/,/^(?:[-/\)][\)])/,/^(?:[^\(\)\[\]\{\}]|!\)+)/,/^(?:\(-)/,/^(?:\]\))/,/^(?:\(\[)/,/^(?:\]\])/,/^(?:\[\[)/,/^(?:\[\|)/,/^(?:>)/,/^(?:\)\])/,/^(?:\[\()/,/^(?:\)\)\))/,/^(?:\(\(\()/,/^(?:[\\(?=\])][\]])/,/^(?:\/(?=\])\])/,/^(?:\/(?!\])|\\(?!\])|[^\\\[\]\(\)\{\}\/]+)/,/^(?:\[\/)/,/^(?:\[\\)/,/^(?:<)/,/^(?:>)/,/^(?:\^)/,/^(?:\\\|)/,/^(?:v\b)/,/^(?:\*)/,/^(?:#)/,/^(?:&)/,/^(?:([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|-(?=[^\>\-\.])|(?!))+)/,/^(?:-)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\|)/,/^(?:\|)/,/^(?:\))/,/^(?:\()/,/^(?:\])/,/^(?:\[)/,/^(?:(\}))/,/^(?:\{)/,/^(?:[^\[\]\(\)\{\}\|\"]+)/,/^(?:")/,/^(?:(\r?\n)+)/,/^(?:\s)/,/^(?:$)/],conditions:{shapeDataEndBracket:{rules:[21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},shapeDataStr:{rules:[9,10,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},shapeData:{rules:[8,11,12,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},callbackargs:{rules:[17,18,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},callbackname:{rules:[14,15,16,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},href:{rules:[21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},click:{rules:[21,24,33,34,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},dottedEdgeText:{rules:[21,24,73,75,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},thickEdgeText:{rules:[21,24,70,72,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},edgeText:{rules:[21,24,67,69,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},trapText:{rules:[21,24,76,79,81,83,87,89,90,91,92,93,94,107,109,111,113],inclusive:!1},ellipseText:{rules:[21,24,76,77,78,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},text:{rules:[21,24,76,79,80,81,82,83,86,87,88,89,93,94,106,107,108,109,110,111,112,113,114],inclusive:!1},vertex:{rules:[21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},dir:{rules:[21,24,44,45,46,47,48,49,50,51,52,53,54,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},acc_descr_multiline:{rules:[5,6,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},acc_descr:{rules:[3,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},acc_title:{rules:[1,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},md_string:{rules:[19,20,21,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},string:{rules:[21,22,23,24,76,79,81,83,87,89,93,94,107,109,111,113],inclusive:!1},INITIAL:{rules:[0,2,4,7,13,21,24,25,26,27,28,29,30,31,32,35,36,37,38,39,40,41,42,43,55,56,57,58,59,60,61,62,63,64,65,66,67,68,70,71,73,74,76,79,81,83,84,85,87,89,93,94,95,96,97,98,99,100,101,102,103,104,105,107,109,111,113,115,116,117,118],inclusive:!0}}}}();function ee(){this.yy={}}return Jt.lexer=te,(0,l.K2)(ee,"Parser"),ee.prototype=Jt,Jt.Parser=ee,new ee}();bt.parser=bt;var Et=bt,mt=(0,l.K2)(((t,e)=>{const s=d.A,n=s(t,"r"),r=s(t,"g"),i=s(t,"b");return p.A(n,r,i,e)}),"fade"),Dt={parser:Et,db:yt,renderer:kt,styles:(0,l.K2)((t=>`.label {\n font-family: ${t.fontFamily};\n color: ${t.nodeTextColor||t.textColor};\n }\n .cluster-label text {\n fill: ${t.titleColor};\n }\n .cluster-label span {\n color: ${t.titleColor};\n }\n .cluster-label span p {\n background-color: transparent;\n }\n\n .label text,span {\n fill: ${t.nodeTextColor||t.textColor};\n color: ${t.nodeTextColor||t.textColor};\n }\n\n .node rect,\n .node circle,\n .node ellipse,\n .node polygon,\n .node path {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n stroke-width: 1px;\n }\n .rough-node .label text , .node .label text, .image-shape .label, .icon-shape .label {\n text-anchor: middle;\n }\n // .flowchart-label .text-outer-tspan {\n // text-anchor: middle;\n // }\n // .flowchart-label .text-inner-tspan {\n // text-anchor: start;\n // }\n\n .node .katex path {\n fill: #000;\n stroke: #000;\n stroke-width: 1px;\n }\n\n .rough-node .label,.node .label, .image-shape .label, .icon-shape .label {\n text-align: center;\n }\n .node.clickable {\n cursor: pointer;\n }\n\n\n .root .anchor path {\n fill: ${t.lineColor} !important;\n stroke-width: 0;\n stroke: ${t.lineColor};\n }\n\n .arrowheadPath {\n fill: ${t.arrowheadColor};\n }\n\n .edgePath .path {\n stroke: ${t.lineColor};\n stroke-width: 2.0px;\n }\n\n .flowchart-link {\n stroke: ${t.lineColor};\n fill: none;\n }\n\n .edgeLabel {\n background-color: ${t.edgeLabelBackground};\n p {\n background-color: ${t.edgeLabelBackground};\n }\n rect {\n opacity: 0.5;\n background-color: ${t.edgeLabelBackground};\n fill: ${t.edgeLabelBackground};\n }\n text-align: center;\n }\n\n /* For html labels only */\n .labelBkg {\n background-color: ${mt(t.edgeLabelBackground,.5)};\n // background-color:\n }\n\n .cluster rect {\n fill: ${t.clusterBkg};\n stroke: ${t.clusterBorder};\n stroke-width: 1px;\n }\n\n .cluster text {\n fill: ${t.titleColor};\n }\n\n .cluster span {\n color: ${t.titleColor};\n }\n /* .cluster div {\n color: ${t.titleColor};\n } */\n\n div.mermaidTooltip {\n position: absolute;\n text-align: center;\n max-width: 200px;\n padding: 2px;\n font-family: ${t.fontFamily};\n font-size: 12px;\n background: ${t.tertiaryColor};\n border: 1px solid ${t.border2};\n border-radius: 2px;\n pointer-events: none;\n z-index: 100;\n }\n\n .flowchartTitleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.textColor};\n }\n\n rect.text {\n fill: none;\n stroke-width: 0;\n }\n\n .icon-shape, .image-shape {\n background-color: ${t.edgeLabelBackground};\n p {\n background-color: ${t.edgeLabelBackground};\n padding: 2px;\n }\n rect {\n opacity: 0.5;\n background-color: ${t.edgeLabelBackground};\n fill: ${t.edgeLabelBackground};\n }\n text-align: center;\n }\n`),"getStyles"),init:(0,l.K2)((t=>{t.flowchart||(t.flowchart={}),t.layout&&(0,l.XV)({layout:t.layout}),t.flowchart.arrowMarkerAbsolute=t.arrowMarkerAbsolute,(0,l.XV)({flowchart:{arrowMarkerAbsolute:t.arrowMarkerAbsolute}}),yt.clear(),yt.setGen("gen-2")}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4492.d9cafff9.js b/pr-preview/pr-1071/assets/js/4492.d9cafff9.js deleted file mode 100644 index 56412fe0f0..0000000000 --- a/pr-preview/pr-1071/assets/js/4492.d9cafff9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4492],{50053:(e,n,t)=>{t.d(n,{A:()=>i});var r=t(68675);const i=function(e){return(0,r.A)(e,4)}},84492:(e,n,t)=>{t.r(n),t.d(n,{render:()=>O});var r=t(37938),i=t(1282),a=(t(64532),t(47588),t(33115)),o=(t(10483),t(8159),t(10009)),d=t(62334),s=t(69592),c=t(50053),g=t(74722);t(37981);function l(e){var n={options:{directed:e.isDirected(),multigraph:e.isMultigraph(),compound:e.isCompound()},nodes:f(e),edges:h(e)};return s.A(e.graph())||(n.value=c.A(e.graph())),n}function f(e){return g.A(e.nodes(),(function(n){var t=e.node(n),r=e.parent(n),i={v:n};return s.A(t)||(i.value=t),s.A(r)||(i.parent=r),i}))}function h(e){return g.A(e.edges(),(function(n){var t=e.edge(n),r={v:n.v,w:n.w};return s.A(n.name)||(r.name=n.name),s.A(t)||(r.value=t),r}))}var u=t(697),p=new Map,m=new Map,w=new Map,R=(0,o.K2)((()=>{m.clear(),w.clear(),p.clear()}),"clear"),v=(0,o.K2)(((e,n)=>{const t=m.get(n)||[];return o.Rm.trace("In isDescendant",n," ",e," = ",t.includes(e)),t.includes(e)}),"isDescendant"),y=(0,o.K2)(((e,n)=>{const t=m.get(n)||[];return o.Rm.info("Descendants of ",n," is ",t),o.Rm.info("Edge is ",e),e.v!==n&&e.w!==n&&(t?t.includes(e.v)||v(e.v,n)||v(e.w,n)||t.includes(e.w):(o.Rm.debug("Tilt, ",n,",not in descendants"),!1))}),"edgeInCluster"),X=(0,o.K2)(((e,n,t,r)=>{o.Rm.warn("Copying children of ",e,"root",r,"data",n.node(e),r);const i=n.children(e)||[];e!==r&&i.push(e),o.Rm.warn("Copying (nodes) clusterId",e,"nodes",i),i.forEach((i=>{if(n.children(i).length>0)X(i,n,t,r);else{const a=n.node(i);o.Rm.info("cp ",i," to ",r," with parent ",e),t.setNode(i,a),r!==n.parent(i)&&(o.Rm.warn("Setting parent",i,n.parent(i)),t.setParent(i,n.parent(i))),e!==r&&i!==e?(o.Rm.debug("Setting parent",i,e),t.setParent(i,e)):(o.Rm.info("In copy ",e,"root",r,"data",n.node(e),r),o.Rm.debug("Not Setting parent for node=",i,"cluster!==rootId",e!==r,"node!==clusterId",i!==e));const d=n.edges(i);o.Rm.debug("Copying Edges",d),d.forEach((i=>{o.Rm.info("Edge",i);const a=n.edge(i.v,i.w,i.name);o.Rm.info("Edge data",a,r);try{y(i,r)?(o.Rm.info("Copying as ",i.v,i.w,a,i.name),t.setEdge(i.v,i.w,a,i.name),o.Rm.info("newGraph edges ",t.edges(),t.edge(t.edges()[0]))):o.Rm.info("Skipping copy of edge ",i.v,"--\x3e",i.w," rootId: ",r," clusterId:",e)}catch(d){o.Rm.error(d)}}))}o.Rm.debug("Removing node",i),n.removeNode(i)}))}),"copy"),b=(0,o.K2)(((e,n)=>{const t=n.children(e);let r=[...t];for(const i of t)w.set(i,e),r=[...r,...b(i,n)];return r}),"extractDescendants"),E=(0,o.K2)(((e,n,t)=>{const r=e.edges().filter((e=>e.v===n||e.w===n)),i=e.edges().filter((e=>e.v===t||e.w===t)),a=r.map((e=>({v:e.v===n?t:e.v,w:e.w===n?n:e.w}))),o=i.map((e=>({v:e.v,w:e.w})));return a.filter((e=>o.some((n=>e.v===n.v&&e.w===n.w))))}),"findCommonEdges"),N=(0,o.K2)(((e,n,t)=>{const r=n.children(e);if(o.Rm.trace("Searching children of id ",e,r),r.length<1)return e;let i;for(const a of r){const e=N(a,n,t),r=E(n,t,e);if(e){if(!(r.length>0))return e;i=e}}return i}),"findNonClusterChild"),C=(0,o.K2)((e=>p.has(e)&&p.get(e).externalConnections&&p.has(e)?p.get(e).id:e),"getAnchorId"),x=(0,o.K2)(((e,n)=>{if(!e||n>10)o.Rm.debug("Opting out, no graph ");else{o.Rm.debug("Opting in, graph "),e.nodes().forEach((function(n){e.children(n).length>0&&(o.Rm.warn("Cluster identified",n," Replacement id in edges: ",N(n,e,n)),m.set(n,b(n,e)),p.set(n,{id:N(n,e,n),clusterData:e.node(n)}))})),e.nodes().forEach((function(n){const t=e.children(n),r=e.edges();t.length>0?(o.Rm.debug("Cluster identified",n,m),r.forEach((e=>{v(e.v,n)^v(e.w,n)&&(o.Rm.warn("Edge: ",e," leaves cluster ",n),o.Rm.warn("Descendants of XXX ",n,": ",m.get(n)),p.get(n).externalConnections=!0)}))):o.Rm.debug("Not a cluster ",n,m)}));for(let n of p.keys()){const t=p.get(n).id,r=e.parent(t);r!==n&&p.has(r)&&!p.get(r).externalConnections&&(p.get(n).id=r)}e.edges().forEach((function(n){const t=e.edge(n);o.Rm.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(n)),o.Rm.warn("Edge "+n.v+" -> "+n.w+": "+JSON.stringify(e.edge(n)));let r=n.v,i=n.w;if(o.Rm.warn("Fix XXX",p,"ids:",n.v,n.w,"Translating: ",p.get(n.v)," --- ",p.get(n.w)),p.get(n.v)||p.get(n.w)){if(o.Rm.warn("Fixing and trying - removing XXX",n.v,n.w,n.name),r=C(n.v),i=C(n.w),e.removeEdge(n.v,n.w,n.name),r!==n.v){const i=e.parent(r);p.get(i).externalConnections=!0,t.fromCluster=n.v}if(i!==n.w){const r=e.parent(i);p.get(r).externalConnections=!0,t.toCluster=n.w}o.Rm.warn("Fix Replacing with XXX",r,i,n.name),e.setEdge(r,i,t,n.name)}})),o.Rm.warn("Adjusted Graph",l(e)),I(e,0),o.Rm.trace(p)}}),"adjustClustersAndEdges"),I=(0,o.K2)(((e,n)=>{if(o.Rm.warn("extractor - ",n,l(e),e.children("D")),n>10)return void o.Rm.error("Bailing out");let t=e.nodes(),r=!1;for(const i of t){const n=e.children(i);r=r||n.length>0}if(r){o.Rm.debug("Nodes = ",t,n);for(const r of t)if(o.Rm.debug("Extracting node",r,p,p.has(r)&&!p.get(r).externalConnections,!e.parent(r),e.node(r),e.children("D")," Depth ",n),p.has(r))if(!p.get(r).externalConnections&&e.children(r)&&e.children(r).length>0){o.Rm.warn("Cluster without external connections, without a parent and with children",r,n);let t="TB"===e.graph().rankdir?"LR":"TB";p.get(r)?.clusterData?.dir&&(t=p.get(r).clusterData.dir,o.Rm.warn("Fixing dir",p.get(r).clusterData.dir,t));const i=new u.T({multigraph:!0,compound:!0}).setGraph({rankdir:t,nodesep:50,ranksep:50,marginx:8,marginy:8}).setDefaultEdgeLabel((function(){return{}}));o.Rm.warn("Old graph before copy",l(e)),X(r,e,i,r),e.setNode(r,{clusterNode:!0,id:r,clusterData:p.get(r).clusterData,label:p.get(r).label,graph:i}),o.Rm.warn("New graph after copy node: (",r,")",l(i)),o.Rm.debug("Old graph after copy",l(e))}else o.Rm.warn("Cluster ** ",r," **not meeting the criteria !externalConnections:",!p.get(r).externalConnections," no parent: ",!e.parent(r)," children ",e.children(r)&&e.children(r).length>0,e.children("D"),n),o.Rm.debug(p);else o.Rm.debug("Not a cluster",r,n);t=e.nodes(),o.Rm.warn("New list of nodes",t);for(const r of t){const t=e.node(r);o.Rm.warn(" Now next level",r,t),t?.clusterNode&&I(t.graph,n+1)}}else o.Rm.debug("Done, no node has children",e.nodes())}),"extractor"),S=(0,o.K2)(((e,n)=>{if(0===n.length)return[];let t=Object.assign([],n);return n.forEach((n=>{const r=e.children(n),i=S(e,r);t=[...t,...i]})),t}),"sorter"),D=(0,o.K2)((e=>S(e,e.children())),"sortNodesByHierarchy"),A=(0,o.K2)((async(e,n,t,s,c,g)=>{o.Rm.warn("Graph in recursive render:XAX",l(n),c);const f=n.graph().rankdir;o.Rm.trace("Dir in recursive render - dir:",f);const h=e.insert("g").attr("class","root");n.nodes()?o.Rm.info("Recursive render XXX",n.nodes()):o.Rm.info("No nodes found for",n),n.edges().length>0&&o.Rm.info("Recursive edges",n.edge(n.edges()[0]));const u=h.insert("g").attr("class","clusters"),m=h.insert("g").attr("class","edgePaths"),w=h.insert("g").attr("class","edgeLabels"),R=h.insert("g").attr("class","nodes");await Promise.all(n.nodes().map((async function(e){const r=n.node(e);if(void 0!==c){const t=JSON.parse(JSON.stringify(c.clusterData));o.Rm.trace("Setting data for parent cluster XXX\n Node.id = ",e,"\n data=",t.height,"\nParent cluster",c.height),n.setNode(c.id,t),n.parent(e)||(o.Rm.trace("Setting parent",e,c.id),n.setParent(e,c.id,t))}if(o.Rm.info("(Insert) Node XXX"+e+": "+JSON.stringify(n.node(e))),r?.clusterNode){o.Rm.info("Cluster identified XBX",e,r.width,n.node(e));const{ranksep:a,nodesep:d}=n.graph();r.graph.setGraph({...r.graph.graph(),ranksep:a+25,nodesep:d});const c=await A(R,r.graph,t,s,n.node(e),g),l=c.elem;(0,i.lC)(r,l),r.diff=c.diff||0,o.Rm.info("New compound node after recursive render XAX",e,"width",r.width,"height",r.height),(0,i.U7)(l,r)}else n.children(e).length>0?(o.Rm.trace("Cluster - the non recursive path XBX",e,r.id,r,r.width,"Graph:",n),o.Rm.trace(N(r.id,n)),p.set(r.id,{id:N(r.id,n),node:r})):(o.Rm.trace("Node - the non recursive path XAX",e,R,n.node(e),f),await(0,i.on)(R,n.node(e),{config:g,dir:f}))})));const v=(0,o.K2)((async()=>{const e=n.edges().map((async function(e){const t=n.edge(e.v,e.w,e.name);o.Rm.info("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(e)),o.Rm.info("Edge "+e.v+" -> "+e.w+": ",e," ",JSON.stringify(n.edge(e))),o.Rm.info("Fix",p,"ids:",e.v,e.w,"Translating: ",p.get(e.v),p.get(e.w)),await(0,r.jP)(w,t)}));await Promise.all(e)}),"processEdges");await v(),o.Rm.info("Graph before layout:",JSON.stringify(l(n))),o.Rm.info("############################################# XXX"),o.Rm.info("### Layout ### XXX"),o.Rm.info("############################################# XXX"),(0,d.Zp)(n),o.Rm.info("Graph after layout:",JSON.stringify(l(n)));let y=0,{subGraphTitleTotalMargin:X}=(0,a.O)(g);return await Promise.all(D(n).map((async function(e){const t=n.node(e);if(o.Rm.info("Position XBX => "+e+": ("+t.x,","+t.y,") width: ",t.width," height: ",t.height),t?.clusterNode)t.y+=X,o.Rm.info("A tainted cluster node XBX1",e,t.id,t.width,t.height,t.x,t.y,n.parent(e)),p.get(t.id).node=t,(0,i.U_)(t);else if(n.children(e).length>0){o.Rm.info("A pure cluster node XBX1",e,t.id,t.x,t.y,t.width,t.height,n.parent(e)),t.height+=X,n.node(t.parentId);const r=t?.padding/2||0,a=t?.labelBBox?.height||0,d=a-r||0;o.Rm.debug("OffsetY",d,"labelHeight",a,"halfPadding",r),await(0,i.U)(u,t),p.get(t.id).node=t}else{const e=n.node(t.parentId);t.y+=X/2,o.Rm.info("A regular node XBX1 - using the padding",t.id,"parent",t.parentId,t.width,t.height,t.x,t.y,"offsetY",t.offsetY,"parent",e,e?.offsetY,t),(0,i.U_)(t)}}))),n.edges().forEach((function(e){const i=n.edge(e);o.Rm.info("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(i),i),i.points.forEach((e=>e.y+=X/2));const a=n.node(e.v);var d=n.node(e.w);const c=(0,r.Jo)(m,i,p,t,a,d,s);(0,r.T_)(i,c)})),n.nodes().forEach((function(e){const t=n.node(e);o.Rm.info(e,t.type,t.diff),t.isGroup&&(y=t.diff)})),o.Rm.warn("Returning from recursive render XAX",h,y),{elem:h,diff:y}}),"recursiveRender"),O=(0,o.K2)((async(e,n)=>{const t=new u.T({multigraph:!0,compound:!0}).setGraph({rankdir:e.direction,nodesep:e.config?.nodeSpacing||e.config?.flowchart?.nodeSpacing||e.nodeSpacing,ranksep:e.config?.rankSpacing||e.config?.flowchart?.rankSpacing||e.rankSpacing,marginx:8,marginy:8}).setDefaultEdgeLabel((function(){return{}})),a=n.select("g");(0,r.g0)(a,e.markers,e.type,e.diagramId),(0,i.gh)(),(0,r.IU)(),(0,i.IU)(),R(),e.nodes.forEach((e=>{t.setNode(e.id,{...e}),e.parentId&&t.setParent(e.id,e.parentId)})),o.Rm.debug("Edges:",e.edges),e.edges.forEach((e=>{if(e.start===e.end){const n=e.start,r=n+"---"+n+"---1",i=n+"---"+n+"---2",a=t.node(n);t.setNode(r,{domId:r,id:r,parentId:a.parentId,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),t.setParent(r,a.parentId),t.setNode(i,{domId:i,id:i,parentId:a.parentId,labelStyle:"",padding:0,shape:"labelRect",label:"",style:"",width:10,height:10}),t.setParent(i,a.parentId);const o=structuredClone(e),d=structuredClone(e),s=structuredClone(e);o.label="",o.arrowTypeEnd="none",o.id=n+"-cyclic-special-1",d.arrowTypeEnd="none",d.id=n+"-cyclic-special-mid",s.label="",a.isGroup&&(o.fromCluster=n,s.toCluster=n),s.id=n+"-cyclic-special-2",t.setEdge(n,r,o,n+"-cyclic-special-0"),t.setEdge(r,i,d,n+"-cyclic-special-1"),t.setEdge(i,n,s,n+"-cyc<lic-special-2")}else t.setEdge(e.start,e.end,{...e},e.id)})),o.Rm.warn("Graph at first:",JSON.stringify(l(t))),x(t),o.Rm.warn("Graph after XAX:",JSON.stringify(l(t)));const d=(0,o.D7)();await A(a,t,e.type,e.diagramId,void 0,d)}),"render")}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/44b49990.bb5c3680.js b/pr-preview/pr-1071/assets/js/44b49990.bb5c3680.js deleted file mode 100644 index 7ced358f69..0000000000 --- a/pr-preview/pr-1071/assets/js/44b49990.bb5c3680.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9652],{40820:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-0.9/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/0.9/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/intro.md","tags":[],"version":"0.9","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/getting-started/install",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/44f8de13.64a0e6ff.js b/pr-preview/pr-1071/assets/js/44f8de13.64a0e6ff.js deleted file mode 100644 index 5908486d9f..0000000000 --- a/pr-preview/pr-1071/assets/js/44f8de13.64a0e6ff.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8976],{65878:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-1.2/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/examples/emojivoto.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Bare metal setup","permalink":"/contrast/pr-preview/pr-1071/getting-started/bare-metal"},"next":{"title":"Encrypted volume mount","permalink":"/contrast/pr-preview/pr-1071/examples/mysql"}}');var o=n(74848),s=n(28453);const a={},r="Confidential emoji voting",l={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Download the deployment files",id:"download-the-deployment-files",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Verifying the deployment as a user",id:"verifying-the-deployment-as-a-user",level:2},{value:"Verifying the Coordinator",id:"verifying-the-coordinator",level:3},{value:"Auditing the manifest history and artifacts",id:"auditing-the-manifest-history-and-artifacts",level:3},{value:"Connecting securely to the application",id:"connecting-securely-to-the-application",level:3},{value:"Updating the certificate SAN and the manifest (optional)",id:"updating-the-certificate-san-and-the-manifest-optional",level:2},{value:"Configuring the service SAN in the manifest",id:"configuring-the-service-san-in-the-manifest",level:3},{value:"Updating the manifest",id:"updating-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components},{TabItem:i,Tabs:a}=t;return i||p("TabItem",!0),a||p("Tabs",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(90861).A+"",width:"1503",height:"732"})}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,o.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voter's perspective."]})}),"\n",(0,o.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,o.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,o.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,o.jsx)(t.code,{children:"voting"}),"). The ",(0,o.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,o.jsx)(t.p,{children:"Emojivoto can be seen as a lighthearted example of an app dealing with sensitive data.\nContrast protects emojivoto in two ways. First, it shields emojivoto as a whole from the infrastructure, for example, Azure.\nSecond, it can be configured to also prevent data access even from the administrator of the app. In the case of emojivoto, this gives assurance to users that their votes remain secret."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,o.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installed Contrast CLI"}),"\n",(0,o.jsxs)(t.li,{children:["A running Kubernetes cluster with support for confidential containers, either on ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/getting-started/cluster-setup",children:"AKS"})," or on ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/getting-started/bare-metal",children:"bare metal"}),"."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,o.jsx)(t.h3,{id:"download-the-deployment-files",children:"Download the deployment files"}),"\n",(0,o.jsx)(t.p,{children:"The emojivoto deployment files are part of the Contrast release. You can download them by running:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.2.0/emojivoto-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,o.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"custom Kubernetes RuntimeClass"}),",\nwhich needs to be installed to the cluster initially.\nThis consists of a ",(0,o.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,o.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-aks-clh-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-k3s-qemu-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,o.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,o.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-aks-clh-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-k3s-qemu-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,o.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,o.jsxs)(t.p,{children:["Run the ",(0,o.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,o.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})})}),(0,o.jsxs)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp deployment/\n"})}),(0,o.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,o.jsxs)(t.p,{children:["On bare-metal SEV-SNP, ",(0,o.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,o.jsx)(t.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,o.jsx)(t.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,o.jsxs)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx deployment/\n"})}),(0,o.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,o.jsxs)(t.p,{children:["On bare-metal TDX, ",(0,o.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,o.jsx)(t.code,{children:"MinimumTeeTcbSvn"})," and ",(0,o.jsx)(t.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,o.jsx)(t.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,o.jsx)(t.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,o.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,o.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,o.jsx)(t.a,{href:"../components/runtime",children:"runtime class"})," ",(0,o.jsx)(t.code,{children:"contrast-cc"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,o.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,o.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,o.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,o.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,o.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,o.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,o.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,o.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,o.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,o.jsx)(t.h2,{id:"verifying-the-deployment-as-a-user",children:"Verifying the deployment as a user"}),"\n",(0,o.jsx)(t.p,{children:"In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before casting a vote.\nWith Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment.\nContrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future.\nSuccessful verification of the Coordinator means that the user can be sure that the given manifest will be enforced."}),"\n",(0,o.jsx)(t.h3,{id:"verifying-the-coordinator",children:"Verifying the Coordinator"}),"\n",(0,o.jsx)(t.p,{children:"A user can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,o.jsxs)(t.p,{children:["The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,o.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,o.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,o.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"auditing-the-manifest-history-and-artifacts",children:"Auditing the manifest history and artifacts"}),"\n",(0,o.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,o.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,o.jsx)(t.h3,{id:"connecting-securely-to-the-application",children:"Connecting securely to the application"}),"\n",(0,o.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, the user can securely connect\nto the application using the Coordinator's ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,o.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,o.jsxs)(t.p,{children:["Using ",(0,o.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,o.jsx)(t.h2,{id:"updating-the-certificate-san-and-the-manifest-optional",children:"Updating the certificate SAN and the manifest (optional)"}),"\n",(0,o.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,o.jsx)(t.h3,{id:"configuring-the-service-san-in-the-manifest",children:"Configuring the service SAN in the manifest"}),"\n",(0,o.jsxs)(t.p,{children:["The ",(0,o.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,o.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,o.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {\n "SANs": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n "WorkloadSecretID": "web"\n },\n'})}),"\n",(0,o.jsx)(t.h3,{id:"updating-the-manifest",children:"Updating the manifest"}),"\n",(0,o.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,o.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,o.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,o.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}function p(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},90861:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var i=n(96540);const o={},s=i.createContext(o);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/45c98560.84e9a5be.js b/pr-preview/pr-1071/assets/js/45c98560.84e9a5be.js deleted file mode 100644 index 1f2a87a634..0000000000 --- a/pr-preview/pr-1071/assets/js/45c98560.84e9a5be.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9361],{70687:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"components/index","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-0.6/components/index.md","sourceDirName":"components","slug":"/components/","permalink":"/contrast/pr-preview/pr-1071/0.6/components/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/components/index.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.6/deployment"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.6/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},d=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(80013).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},80013:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-dd64f006e7d6b6facb9eb16f1af59d39.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/46157656.b50ca5fc.js b/pr-preview/pr-1071/assets/js/46157656.b50ca5fc.js deleted file mode 100644 index 3a55994ab6..0000000000 --- a/pr-preview/pr-1071/assets/js/46157656.b50ca5fc.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2857],{35749:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"1.0","label":"1.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-1.0","isLast":false,"docsSidebars":{"docs":[{"type":"link","label":"What is Contrast?","href":"/contrast/pr-preview/pr-1071/1.0/","docId":"intro","unlisted":false},{"type":"category","label":"Basics","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/1.0/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/1.0/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false}],"collapsible":true},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/1.0/deployment","docId":"deployment","unlisted":false},{"type":"link","label":"Troubleshooting","href":"/contrast/pr-preview/pr-1071/1.0/troubleshooting","docId":"troubleshooting","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Overview","href":"/contrast/pr-preview/pr-1071/1.0/components/overview","docId":"components/overview","unlisted":false},{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/1.0/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/1.0/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/1.0/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/1.0/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Secrets & recovery","href":"/contrast/pr-preview/pr-1071/1.0/architecture/secrets","docId":"architecture/secrets","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/1.0/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/1.0/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/1.0/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/1.0/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"architecture/secrets":{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/overview":{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"troubleshooting":{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4632.878c659d.js b/pr-preview/pr-1071/assets/js/4632.878c659d.js deleted file mode 100644 index c50aced2c6..0000000000 --- a/pr-preview/pr-1071/assets/js/4632.878c659d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4632],{14632:(t,e,i)=>{i.d(e,{diagram:()=>v});var a=i(10009),n=i(20007),s=function(){var t=(0,a.K2)((function(t,e,i,a){for(i=i||{},a=t.length;a--;i[t[a]]=e);return i}),"o"),e=[1,3],i=[1,4],n=[1,5],s=[1,6],r=[1,7],o=[1,4,5,10,12,13,14,18,25,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],l=[1,4,5,10,12,13,14,18,25,28,35,37,39,41,42,48,50,51,52,53,54,55,56,57,60,61,63,64,65,66,67],h=[55,56,57],c=[2,36],d=[1,37],u=[1,36],x=[1,38],g=[1,35],f=[1,43],p=[1,41],y=[1,14],T=[1,23],m=[1,18],q=[1,19],A=[1,20],_=[1,21],b=[1,22],S=[1,24],k=[1,25],F=[1,26],P=[1,27],C=[1,28],L=[1,29],v=[1,32],I=[1,33],E=[1,34],D=[1,39],z=[1,40],w=[1,42],K=[1,44],U=[1,62],N=[1,61],R=[4,5,8,10,12,13,14,18,44,47,49,55,56,57,63,64,65,66,67],B=[1,65],W=[1,66],$=[1,67],Q=[1,68],O=[1,69],X=[1,70],H=[1,71],M=[1,72],Y=[1,73],j=[1,74],G=[1,75],V=[1,76],Z=[4,5,6,7,8,9,10,11,12,13,14,15,18],J=[1,90],tt=[1,91],et=[1,92],it=[1,99],at=[1,93],nt=[1,96],st=[1,94],rt=[1,95],ot=[1,97],lt=[1,98],ht=[1,102],ct=[10,55,56,57],dt=[4,5,6,8,10,11,13,17,18,19,20,55,56,57],ut={trace:(0,a.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,idStringToken:3,ALPHA:4,NUM:5,NODE_STRING:6,DOWN:7,MINUS:8,DEFAULT:9,COMMA:10,COLON:11,AMP:12,BRKT:13,MULT:14,UNICODE_TEXT:15,styleComponent:16,UNIT:17,SPACE:18,STYLE:19,PCT:20,idString:21,style:22,stylesOpt:23,classDefStatement:24,CLASSDEF:25,start:26,eol:27,QUADRANT:28,document:29,line:30,statement:31,axisDetails:32,quadrantDetails:33,points:34,title:35,title_value:36,acc_title:37,acc_title_value:38,acc_descr:39,acc_descr_value:40,acc_descr_multiline_value:41,section:42,text:43,point_start:44,point_x:45,point_y:46,class_name:47,"X-AXIS":48,"AXIS-TEXT-DELIMITER":49,"Y-AXIS":50,QUADRANT_1:51,QUADRANT_2:52,QUADRANT_3:53,QUADRANT_4:54,NEWLINE:55,SEMI:56,EOF:57,alphaNumToken:58,textNoTagsToken:59,STR:60,MD_STR:61,alphaNum:62,PUNCTUATION:63,PLUS:64,EQUALS:65,DOT:66,UNDERSCORE:67,$accept:0,$end:1},terminals_:{2:"error",4:"ALPHA",5:"NUM",6:"NODE_STRING",7:"DOWN",8:"MINUS",9:"DEFAULT",10:"COMMA",11:"COLON",12:"AMP",13:"BRKT",14:"MULT",15:"UNICODE_TEXT",17:"UNIT",18:"SPACE",19:"STYLE",20:"PCT",25:"CLASSDEF",28:"QUADRANT",35:"title",36:"title_value",37:"acc_title",38:"acc_title_value",39:"acc_descr",40:"acc_descr_value",41:"acc_descr_multiline_value",42:"section",44:"point_start",45:"point_x",46:"point_y",47:"class_name",48:"X-AXIS",49:"AXIS-TEXT-DELIMITER",50:"Y-AXIS",51:"QUADRANT_1",52:"QUADRANT_2",53:"QUADRANT_3",54:"QUADRANT_4",55:"NEWLINE",56:"SEMI",57:"EOF",60:"STR",61:"MD_STR",63:"PUNCTUATION",64:"PLUS",65:"EQUALS",66:"DOT",67:"UNDERSCORE"},productions_:[0,[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[3,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[16,1],[21,1],[21,2],[22,1],[22,2],[23,1],[23,3],[24,5],[26,2],[26,2],[26,2],[29,0],[29,2],[30,2],[31,0],[31,1],[31,2],[31,1],[31,1],[31,1],[31,2],[31,2],[31,2],[31,1],[31,1],[34,4],[34,5],[34,5],[34,6],[32,4],[32,3],[32,2],[32,4],[32,3],[32,2],[33,2],[33,2],[33,2],[33,2],[27,1],[27,1],[27,1],[43,1],[43,2],[43,1],[43,1],[62,1],[62,2],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[58,1],[59,1],[59,1],[59,1]],performAction:(0,a.K2)((function(t,e,i,a,n,s,r){var o=s.length-1;switch(n){case 23:case 68:this.$=s[o];break;case 24:case 69:this.$=s[o-1]+""+s[o];break;case 26:this.$=s[o-1]+s[o];break;case 27:this.$=[s[o].trim()];break;case 28:s[o-2].push(s[o].trim()),this.$=s[o-2];break;case 29:this.$=s[o-4],a.addClass(s[o-2],s[o]);break;case 37:this.$=[];break;case 42:this.$=s[o].trim(),a.setDiagramTitle(this.$);break;case 43:this.$=s[o].trim(),a.setAccTitle(this.$);break;case 44:case 45:this.$=s[o].trim(),a.setAccDescription(this.$);break;case 46:a.addSection(s[o].substr(8)),this.$=s[o].substr(8);break;case 47:a.addPoint(s[o-3],"",s[o-1],s[o],[]);break;case 48:a.addPoint(s[o-4],s[o-3],s[o-1],s[o],[]);break;case 49:a.addPoint(s[o-4],"",s[o-2],s[o-1],s[o]);break;case 50:a.addPoint(s[o-5],s[o-4],s[o-2],s[o-1],s[o]);break;case 51:a.setXAxisLeftText(s[o-2]),a.setXAxisRightText(s[o]);break;case 52:s[o-1].text+=" \u27f6 ",a.setXAxisLeftText(s[o-1]);break;case 53:a.setXAxisLeftText(s[o]);break;case 54:a.setYAxisBottomText(s[o-2]),a.setYAxisTopText(s[o]);break;case 55:s[o-1].text+=" \u27f6 ",a.setYAxisBottomText(s[o-1]);break;case 56:a.setYAxisBottomText(s[o]);break;case 57:a.setQuadrant1Text(s[o]);break;case 58:a.setQuadrant2Text(s[o]);break;case 59:a.setQuadrant3Text(s[o]);break;case 60:a.setQuadrant4Text(s[o]);break;case 64:case 66:this.$={text:s[o],type:"text"};break;case 65:this.$={text:s[o-1].text+""+s[o],type:s[o-1].type};break;case 67:this.$={text:s[o],type:"markdown"}}}),"anonymous"),table:[{18:e,26:1,27:2,28:i,55:n,56:s,57:r},{1:[3]},{18:e,26:8,27:2,28:i,55:n,56:s,57:r},{18:e,26:9,27:2,28:i,55:n,56:s,57:r},t(o,[2,33],{29:10}),t(l,[2,61]),t(l,[2,62]),t(l,[2,63]),{1:[2,30]},{1:[2,31]},t(h,c,{30:11,31:12,24:13,32:15,33:16,34:17,43:30,58:31,1:[2,32],4:d,5:u,10:x,12:g,13:f,14:p,18:y,25:T,35:m,37:q,39:A,41:_,42:b,48:S,50:k,51:F,52:P,53:C,54:L,60:v,61:I,63:E,64:D,65:z,66:w,67:K}),t(o,[2,34]),{27:45,55:n,56:s,57:r},t(h,[2,37]),t(h,c,{24:13,32:15,33:16,34:17,43:30,58:31,31:46,4:d,5:u,10:x,12:g,13:f,14:p,18:y,25:T,35:m,37:q,39:A,41:_,42:b,48:S,50:k,51:F,52:P,53:C,54:L,60:v,61:I,63:E,64:D,65:z,66:w,67:K}),t(h,[2,39]),t(h,[2,40]),t(h,[2,41]),{36:[1,47]},{38:[1,48]},{40:[1,49]},t(h,[2,45]),t(h,[2,46]),{18:[1,50]},{4:d,5:u,10:x,12:g,13:f,14:p,43:51,58:31,60:v,61:I,63:E,64:D,65:z,66:w,67:K},{4:d,5:u,10:x,12:g,13:f,14:p,43:52,58:31,60:v,61:I,63:E,64:D,65:z,66:w,67:K},{4:d,5:u,10:x,12:g,13:f,14:p,43:53,58:31,60:v,61:I,63:E,64:D,65:z,66:w,67:K},{4:d,5:u,10:x,12:g,13:f,14:p,43:54,58:31,60:v,61:I,63:E,64:D,65:z,66:w,67:K},{4:d,5:u,10:x,12:g,13:f,14:p,43:55,58:31,60:v,61:I,63:E,64:D,65:z,66:w,67:K},{4:d,5:u,10:x,12:g,13:f,14:p,43:56,58:31,60:v,61:I,63:E,64:D,65:z,66:w,67:K},{4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,44:[1,57],47:[1,58],58:60,59:59,63:E,64:D,65:z,66:w,67:K},t(R,[2,64]),t(R,[2,66]),t(R,[2,67]),t(R,[2,70]),t(R,[2,71]),t(R,[2,72]),t(R,[2,73]),t(R,[2,74]),t(R,[2,75]),t(R,[2,76]),t(R,[2,77]),t(R,[2,78]),t(R,[2,79]),t(R,[2,80]),t(o,[2,35]),t(h,[2,38]),t(h,[2,42]),t(h,[2,43]),t(h,[2,44]),{3:64,4:B,5:W,6:$,7:Q,8:O,9:X,10:H,11:M,12:Y,13:j,14:G,15:V,21:63},t(h,[2,53],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,49:[1,77],63:E,64:D,65:z,66:w,67:K}),t(h,[2,56],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,49:[1,78],63:E,64:D,65:z,66:w,67:K}),t(h,[2,57],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,63:E,64:D,65:z,66:w,67:K}),t(h,[2,58],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,63:E,64:D,65:z,66:w,67:K}),t(h,[2,59],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,63:E,64:D,65:z,66:w,67:K}),t(h,[2,60],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,63:E,64:D,65:z,66:w,67:K}),{45:[1,79]},{44:[1,80]},t(R,[2,65]),t(R,[2,81]),t(R,[2,82]),t(R,[2,83]),{3:82,4:B,5:W,6:$,7:Q,8:O,9:X,10:H,11:M,12:Y,13:j,14:G,15:V,18:[1,81]},t(Z,[2,23]),t(Z,[2,1]),t(Z,[2,2]),t(Z,[2,3]),t(Z,[2,4]),t(Z,[2,5]),t(Z,[2,6]),t(Z,[2,7]),t(Z,[2,8]),t(Z,[2,9]),t(Z,[2,10]),t(Z,[2,11]),t(Z,[2,12]),t(h,[2,52],{58:31,43:83,4:d,5:u,10:x,12:g,13:f,14:p,60:v,61:I,63:E,64:D,65:z,66:w,67:K}),t(h,[2,55],{58:31,43:84,4:d,5:u,10:x,12:g,13:f,14:p,60:v,61:I,63:E,64:D,65:z,66:w,67:K}),{46:[1,85]},{45:[1,86]},{4:J,5:tt,6:et,8:it,11:at,13:nt,16:89,17:st,18:rt,19:ot,20:lt,22:88,23:87},t(Z,[2,24]),t(h,[2,51],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,63:E,64:D,65:z,66:w,67:K}),t(h,[2,54],{59:59,58:60,4:d,5:u,8:U,10:x,12:g,13:f,14:p,18:N,63:E,64:D,65:z,66:w,67:K}),t(h,[2,47],{22:88,16:89,23:100,4:J,5:tt,6:et,8:it,11:at,13:nt,17:st,18:rt,19:ot,20:lt}),{46:[1,101]},t(h,[2,29],{10:ht}),t(ct,[2,27],{16:103,4:J,5:tt,6:et,8:it,11:at,13:nt,17:st,18:rt,19:ot,20:lt}),t(dt,[2,25]),t(dt,[2,13]),t(dt,[2,14]),t(dt,[2,15]),t(dt,[2,16]),t(dt,[2,17]),t(dt,[2,18]),t(dt,[2,19]),t(dt,[2,20]),t(dt,[2,21]),t(dt,[2,22]),t(h,[2,49],{10:ht}),t(h,[2,48],{22:88,16:89,23:104,4:J,5:tt,6:et,8:it,11:at,13:nt,17:st,18:rt,19:ot,20:lt}),{4:J,5:tt,6:et,8:it,11:at,13:nt,16:89,17:st,18:rt,19:ot,20:lt,22:105},t(dt,[2,26]),t(h,[2,50],{10:ht}),t(ct,[2,28],{16:103,4:J,5:tt,6:et,8:it,11:at,13:nt,17:st,18:rt,19:ot,20:lt})],defaultActions:{8:[2,30],9:[2,31]},parseError:(0,a.K2)((function(t,e){if(!e.recoverable){var i=new Error(t);throw i.hash=e,i}this.trace(t)}),"parseError"),parse:(0,a.K2)((function(t){var e=this,i=[0],n=[],s=[null],r=[],o=this.table,l="",h=0,c=0,d=0,u=r.slice.call(arguments,1),x=Object.create(this.lexer),g={yy:{}};for(var f in this.yy)Object.prototype.hasOwnProperty.call(this.yy,f)&&(g.yy[f]=this.yy[f]);x.setInput(t,g.yy),g.yy.lexer=x,g.yy.parser=this,void 0===x.yylloc&&(x.yylloc={});var p=x.yylloc;r.push(p);var y=x.options&&x.options.ranges;function T(){var t;return"number"!=typeof(t=n.pop()||x.lex()||1)&&(t instanceof Array&&(t=(n=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,a.K2)((function(t){i.length=i.length-2*t,s.length=s.length-t,r.length=r.length-t}),"popStack"),(0,a.K2)(T,"lex");for(var m,q,A,_,b,S,k,F,P,C={};;){if(A=i[i.length-1],this.defaultActions[A]?_=this.defaultActions[A]:(null==m&&(m=T()),_=o[A]&&o[A][m]),void 0===_||!_.length||!_[0]){var L="";for(S in P=[],o[A])this.terminals_[S]&&S>2&&P.push("'"+this.terminals_[S]+"'");L=x.showPosition?"Parse error on line "+(h+1)+":\n"+x.showPosition()+"\nExpecting "+P.join(", ")+", got '"+(this.terminals_[m]||m)+"'":"Parse error on line "+(h+1)+": Unexpected "+(1==m?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(L,{text:x.match,token:this.terminals_[m]||m,line:x.yylineno,loc:p,expected:P})}if(_[0]instanceof Array&&_.length>1)throw new Error("Parse Error: multiple actions possible at state: "+A+", token: "+m);switch(_[0]){case 1:i.push(m),s.push(x.yytext),r.push(x.yylloc),i.push(_[1]),m=null,q?(m=q,q=null):(c=x.yyleng,l=x.yytext,h=x.yylineno,p=x.yylloc,d>0&&d--);break;case 2:if(k=this.productions_[_[1]][1],C.$=s[s.length-k],C._$={first_line:r[r.length-(k||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(k||1)].first_column,last_column:r[r.length-1].last_column},y&&(C._$.range=[r[r.length-(k||1)].range[0],r[r.length-1].range[1]]),void 0!==(b=this.performAction.apply(C,[l,c,h,g.yy,_[1],s,r].concat(u))))return b;k&&(i=i.slice(0,-1*k*2),s=s.slice(0,-1*k),r=r.slice(0,-1*k)),i.push(this.productions_[_[1]][0]),s.push(C.$),r.push(C._$),F=o[i[i.length-2]][i[i.length-1]],i.push(F);break;case 3:return!0}}return!0}),"parse")},xt=function(){return{EOF:1,parseError:(0,a.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,a.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,a.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,a.K2)((function(t){var e=t.length,i=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var a=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),i.length-1&&(this.yylineno-=i.length-1);var n=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:i?(i.length===a.length?this.yylloc.first_column:0)+a[a.length-i.length].length-i[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[n[0],n[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,a.K2)((function(){return this._more=!0,this}),"more"),reject:(0,a.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,a.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,a.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,a.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,a.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,a.K2)((function(t,e){var i,a,n;if(this.options.backtrack_lexer&&(n={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(n.yylloc.range=this.yylloc.range.slice(0))),(a=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=a.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:a?a[a.length-1].length-a[a.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],i=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var s in n)this[s]=n[s];return!1}return!1}),"test_match"),next:(0,a.K2)((function(){if(this.done)return this.EOF;var t,e,i,a;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var n=this._currentRules(),s=0;s<n.length;s++)if((i=this._input.match(this.rules[n[s]]))&&(!e||i[0].length>e[0].length)){if(e=i,a=s,this.options.backtrack_lexer){if(!1!==(t=this.test_match(i,n[s])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,n[a]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,a.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,a.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,a.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,a.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,a.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,a.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,a.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,a.K2)((function(t,e,i,a){switch(i){case 0:case 1:case 3:break;case 2:return 55;case 4:return this.begin("title"),35;case 5:return this.popState(),"title_value";case 6:return this.begin("acc_title"),37;case 7:return this.popState(),"acc_title_value";case 8:return this.begin("acc_descr"),39;case 9:return this.popState(),"acc_descr_value";case 10:this.begin("acc_descr_multiline");break;case 11:case 23:case 25:case 31:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:return 48;case 14:return 50;case 15:return 49;case 16:return 51;case 17:return 52;case 18:return 53;case 19:return 54;case 20:return 25;case 21:this.begin("md_string");break;case 22:return"MD_STR";case 24:this.begin("string");break;case 26:return"STR";case 27:this.begin("class_name");break;case 28:return this.popState(),47;case 29:return this.begin("point_start"),44;case 30:return this.begin("point_x"),45;case 32:this.popState(),this.begin("point_y");break;case 33:return this.popState(),46;case 34:return 28;case 35:return 4;case 36:return 11;case 37:return 64;case 38:return 10;case 39:case 40:return 65;case 41:return 14;case 42:return 13;case 43:return 67;case 44:return 66;case 45:return 12;case 46:return 8;case 47:return 5;case 48:return 18;case 49:return 56;case 50:return 63;case 51:return 57}}),"anonymous"),rules:[/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:title\b)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?: *x-axis *)/i,/^(?: *y-axis *)/i,/^(?: *--+> *)/i,/^(?: *quadrant-1 *)/i,/^(?: *quadrant-2 *)/i,/^(?: *quadrant-3 *)/i,/^(?: *quadrant-4 *)/i,/^(?:classDef\b)/i,/^(?:["][`])/i,/^(?:[^`"]+)/i,/^(?:[`]["])/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?::::)/i,/^(?:^\w+)/i,/^(?:\s*:\s*\[\s*)/i,/^(?:(1)|(0(.\d+)?))/i,/^(?:\s*\] *)/i,/^(?:\s*,\s*)/i,/^(?:(1)|(0(.\d+)?))/i,/^(?: *quadrantChart *)/i,/^(?:[A-Za-z]+)/i,/^(?::)/i,/^(?:\+)/i,/^(?:,)/i,/^(?:=)/i,/^(?:=)/i,/^(?:\*)/i,/^(?:#)/i,/^(?:[\_])/i,/^(?:\.)/i,/^(?:&)/i,/^(?:-)/i,/^(?:[0-9]+)/i,/^(?:\s)/i,/^(?:;)/i,/^(?:[!"#$%&'*+,-.`?\\_/])/i,/^(?:$)/i],conditions:{class_name:{rules:[28],inclusive:!1},point_y:{rules:[33],inclusive:!1},point_x:{rules:[32],inclusive:!1},point_start:{rules:[30,31],inclusive:!1},acc_descr_multiline:{rules:[11,12],inclusive:!1},acc_descr:{rules:[9],inclusive:!1},acc_title:{rules:[7],inclusive:!1},title:{rules:[5],inclusive:!1},md_string:{rules:[22,23],inclusive:!1},string:{rules:[25,26],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,6,8,10,13,14,15,16,17,18,19,20,21,24,27,29,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],inclusive:!0}}}}();function gt(){this.yy={}}return ut.lexer=xt,(0,a.K2)(gt,"Parser"),gt.prototype=ut,ut.Parser=gt,new gt}();s.parser=s;var r=s,o=(0,a.P$)(),l=class{constructor(){this.classes=new Map,this.config=this.getDefaultConfig(),this.themeConfig=this.getDefaultThemeConfig(),this.data=this.getDefaultData()}static{(0,a.K2)(this,"QuadrantBuilder")}getDefaultData(){return{titleText:"",quadrant1Text:"",quadrant2Text:"",quadrant3Text:"",quadrant4Text:"",xAxisLeftText:"",xAxisRightText:"",yAxisBottomText:"",yAxisTopText:"",points:[]}}getDefaultConfig(){return{showXAxis:!0,showYAxis:!0,showTitle:!0,chartHeight:a.UI.quadrantChart?.chartWidth||500,chartWidth:a.UI.quadrantChart?.chartHeight||500,titlePadding:a.UI.quadrantChart?.titlePadding||10,titleFontSize:a.UI.quadrantChart?.titleFontSize||20,quadrantPadding:a.UI.quadrantChart?.quadrantPadding||5,xAxisLabelPadding:a.UI.quadrantChart?.xAxisLabelPadding||5,yAxisLabelPadding:a.UI.quadrantChart?.yAxisLabelPadding||5,xAxisLabelFontSize:a.UI.quadrantChart?.xAxisLabelFontSize||16,yAxisLabelFontSize:a.UI.quadrantChart?.yAxisLabelFontSize||16,quadrantLabelFontSize:a.UI.quadrantChart?.quadrantLabelFontSize||16,quadrantTextTopPadding:a.UI.quadrantChart?.quadrantTextTopPadding||5,pointTextPadding:a.UI.quadrantChart?.pointTextPadding||5,pointLabelFontSize:a.UI.quadrantChart?.pointLabelFontSize||12,pointRadius:a.UI.quadrantChart?.pointRadius||5,xAxisPosition:a.UI.quadrantChart?.xAxisPosition||"top",yAxisPosition:a.UI.quadrantChart?.yAxisPosition||"left",quadrantInternalBorderStrokeWidth:a.UI.quadrantChart?.quadrantInternalBorderStrokeWidth||1,quadrantExternalBorderStrokeWidth:a.UI.quadrantChart?.quadrantExternalBorderStrokeWidth||2}}getDefaultThemeConfig(){return{quadrant1Fill:o.quadrant1Fill,quadrant2Fill:o.quadrant2Fill,quadrant3Fill:o.quadrant3Fill,quadrant4Fill:o.quadrant4Fill,quadrant1TextFill:o.quadrant1TextFill,quadrant2TextFill:o.quadrant2TextFill,quadrant3TextFill:o.quadrant3TextFill,quadrant4TextFill:o.quadrant4TextFill,quadrantPointFill:o.quadrantPointFill,quadrantPointTextFill:o.quadrantPointTextFill,quadrantXAxisTextFill:o.quadrantXAxisTextFill,quadrantYAxisTextFill:o.quadrantYAxisTextFill,quadrantTitleFill:o.quadrantTitleFill,quadrantInternalBorderStrokeFill:o.quadrantInternalBorderStrokeFill,quadrantExternalBorderStrokeFill:o.quadrantExternalBorderStrokeFill}}clear(){this.config=this.getDefaultConfig(),this.themeConfig=this.getDefaultThemeConfig(),this.data=this.getDefaultData(),this.classes=new Map,a.Rm.info("clear called")}setData(t){this.data={...this.data,...t}}addPoints(t){this.data.points=[...t,...this.data.points]}addClass(t,e){this.classes.set(t,e)}setConfig(t){a.Rm.trace("setConfig called with: ",t),this.config={...this.config,...t}}setThemeConfig(t){a.Rm.trace("setThemeConfig called with: ",t),this.themeConfig={...this.themeConfig,...t}}calculateSpace(t,e,i,a){const n=2*this.config.xAxisLabelPadding+this.config.xAxisLabelFontSize,s={top:"top"===t&&e?n:0,bottom:"bottom"===t&&e?n:0},r=2*this.config.yAxisLabelPadding+this.config.yAxisLabelFontSize,o={left:"left"===this.config.yAxisPosition&&i?r:0,right:"right"===this.config.yAxisPosition&&i?r:0},l=this.config.titleFontSize+2*this.config.titlePadding,h={top:a?l:0},c=this.config.quadrantPadding+o.left,d=this.config.quadrantPadding+s.top+h.top,u=this.config.chartWidth-2*this.config.quadrantPadding-o.left-o.right,x=this.config.chartHeight-2*this.config.quadrantPadding-s.top-s.bottom-h.top;return{xAxisSpace:s,yAxisSpace:o,titleSpace:h,quadrantSpace:{quadrantLeft:c,quadrantTop:d,quadrantWidth:u,quadrantHalfWidth:u/2,quadrantHeight:x,quadrantHalfHeight:x/2}}}getAxisLabels(t,e,i,a){const{quadrantSpace:n,titleSpace:s}=a,{quadrantHalfHeight:r,quadrantHeight:o,quadrantLeft:l,quadrantHalfWidth:h,quadrantTop:c,quadrantWidth:d}=n,u=Boolean(this.data.xAxisRightText),x=Boolean(this.data.yAxisTopText),g=[];return this.data.xAxisLeftText&&e&&g.push({text:this.data.xAxisLeftText,fill:this.themeConfig.quadrantXAxisTextFill,x:l+(u?h/2:0),y:"top"===t?this.config.xAxisLabelPadding+s.top:this.config.xAxisLabelPadding+c+o+this.config.quadrantPadding,fontSize:this.config.xAxisLabelFontSize,verticalPos:u?"center":"left",horizontalPos:"top",rotation:0}),this.data.xAxisRightText&&e&&g.push({text:this.data.xAxisRightText,fill:this.themeConfig.quadrantXAxisTextFill,x:l+h+(u?h/2:0),y:"top"===t?this.config.xAxisLabelPadding+s.top:this.config.xAxisLabelPadding+c+o+this.config.quadrantPadding,fontSize:this.config.xAxisLabelFontSize,verticalPos:u?"center":"left",horizontalPos:"top",rotation:0}),this.data.yAxisBottomText&&i&&g.push({text:this.data.yAxisBottomText,fill:this.themeConfig.quadrantYAxisTextFill,x:"left"===this.config.yAxisPosition?this.config.yAxisLabelPadding:this.config.yAxisLabelPadding+l+d+this.config.quadrantPadding,y:c+o-(x?r/2:0),fontSize:this.config.yAxisLabelFontSize,verticalPos:x?"center":"left",horizontalPos:"top",rotation:-90}),this.data.yAxisTopText&&i&&g.push({text:this.data.yAxisTopText,fill:this.themeConfig.quadrantYAxisTextFill,x:"left"===this.config.yAxisPosition?this.config.yAxisLabelPadding:this.config.yAxisLabelPadding+l+d+this.config.quadrantPadding,y:c+r-(x?r/2:0),fontSize:this.config.yAxisLabelFontSize,verticalPos:x?"center":"left",horizontalPos:"top",rotation:-90}),g}getQuadrants(t){const{quadrantSpace:e}=t,{quadrantHalfHeight:i,quadrantLeft:a,quadrantHalfWidth:n,quadrantTop:s}=e,r=[{text:{text:this.data.quadrant1Text,fill:this.themeConfig.quadrant1TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:a+n,y:s,width:n,height:i,fill:this.themeConfig.quadrant1Fill},{text:{text:this.data.quadrant2Text,fill:this.themeConfig.quadrant2TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:a,y:s,width:n,height:i,fill:this.themeConfig.quadrant2Fill},{text:{text:this.data.quadrant3Text,fill:this.themeConfig.quadrant3TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:a,y:s+i,width:n,height:i,fill:this.themeConfig.quadrant3Fill},{text:{text:this.data.quadrant4Text,fill:this.themeConfig.quadrant4TextFill,x:0,y:0,fontSize:this.config.quadrantLabelFontSize,verticalPos:"center",horizontalPos:"middle",rotation:0},x:a+n,y:s+i,width:n,height:i,fill:this.themeConfig.quadrant4Fill}];for(const o of r)o.text.x=o.x+o.width/2,0===this.data.points.length?(o.text.y=o.y+o.height/2,o.text.horizontalPos="middle"):(o.text.y=o.y+this.config.quadrantTextTopPadding,o.text.horizontalPos="top");return r}getQuadrantPoints(t){const{quadrantSpace:e}=t,{quadrantHeight:i,quadrantLeft:a,quadrantTop:s,quadrantWidth:r}=e,o=(0,n.m4Y)().domain([0,1]).range([a,r+a]),l=(0,n.m4Y)().domain([0,1]).range([i+s,s]);return this.data.points.map((t=>{const e=this.classes.get(t.className);e&&(t={...e,...t});return{x:o(t.x),y:l(t.y),fill:t.color??this.themeConfig.quadrantPointFill,radius:t.radius??this.config.pointRadius,text:{text:t.text,fill:this.themeConfig.quadrantPointTextFill,x:o(t.x),y:l(t.y)+this.config.pointTextPadding,verticalPos:"center",horizontalPos:"top",fontSize:this.config.pointLabelFontSize,rotation:0},strokeColor:t.strokeColor??this.themeConfig.quadrantPointFill,strokeWidth:t.strokeWidth??"0px"}}))}getBorders(t){const e=this.config.quadrantExternalBorderStrokeWidth/2,{quadrantSpace:i}=t,{quadrantHalfHeight:a,quadrantHeight:n,quadrantLeft:s,quadrantHalfWidth:r,quadrantTop:o,quadrantWidth:l}=i;return[{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s-e,y1:o,x2:s+l+e,y2:o},{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s+l,y1:o+e,x2:s+l,y2:o+n-e},{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s-e,y1:o+n,x2:s+l+e,y2:o+n},{strokeFill:this.themeConfig.quadrantExternalBorderStrokeFill,strokeWidth:this.config.quadrantExternalBorderStrokeWidth,x1:s,y1:o+e,x2:s,y2:o+n-e},{strokeFill:this.themeConfig.quadrantInternalBorderStrokeFill,strokeWidth:this.config.quadrantInternalBorderStrokeWidth,x1:s+r,y1:o+e,x2:s+r,y2:o+n-e},{strokeFill:this.themeConfig.quadrantInternalBorderStrokeFill,strokeWidth:this.config.quadrantInternalBorderStrokeWidth,x1:s+e,y1:o+a,x2:s+l-e,y2:o+a}]}getTitle(t){if(t)return{text:this.data.titleText,fill:this.themeConfig.quadrantTitleFill,fontSize:this.config.titleFontSize,horizontalPos:"top",verticalPos:"center",rotation:0,y:this.config.titlePadding,x:this.config.chartWidth/2}}build(){const t=this.config.showXAxis&&!(!this.data.xAxisLeftText&&!this.data.xAxisRightText),e=this.config.showYAxis&&!(!this.data.yAxisTopText&&!this.data.yAxisBottomText),i=this.config.showTitle&&!!this.data.titleText,a=this.data.points.length>0?"bottom":this.config.xAxisPosition,n=this.calculateSpace(a,t,e,i);return{points:this.getQuadrantPoints(n),quadrants:this.getQuadrants(n),axisLabels:this.getAxisLabels(a,t,e,n),borderLines:this.getBorders(n),title:this.getTitle(i)}}},h=class extends Error{static{(0,a.K2)(this,"InvalidStyleError")}constructor(t,e,i){super(`value for ${t} ${e} is invalid, please use a valid ${i}`),this.name="InvalidStyleError"}};function c(t){return!/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(t)}function d(t){return!/^\d+$/.test(t)}function u(t){return!/^\d+px$/.test(t)}(0,a.K2)(c,"validateHexCode"),(0,a.K2)(d,"validateNumber"),(0,a.K2)(u,"validateSizeInPixels");var x=(0,a.D7)();function g(t){return(0,a.jZ)(t.trim(),x)}(0,a.K2)(g,"textSanitizer");var f=new l;function p(t){f.setData({quadrant1Text:g(t.text)})}function y(t){f.setData({quadrant2Text:g(t.text)})}function T(t){f.setData({quadrant3Text:g(t.text)})}function m(t){f.setData({quadrant4Text:g(t.text)})}function q(t){f.setData({xAxisLeftText:g(t.text)})}function A(t){f.setData({xAxisRightText:g(t.text)})}function _(t){f.setData({yAxisTopText:g(t.text)})}function b(t){f.setData({yAxisBottomText:g(t.text)})}function S(t){const e={};for(const i of t){const[t,a]=i.trim().split(/\s*:\s*/);if("radius"===t){if(d(a))throw new h(t,a,"number");e.radius=parseInt(a)}else if("color"===t){if(c(a))throw new h(t,a,"hex code");e.color=a}else if("stroke-color"===t){if(c(a))throw new h(t,a,"hex code");e.strokeColor=a}else{if("stroke-width"!==t)throw new Error(`style named ${t} is not supported.`);if(u(a))throw new h(t,a,"number of pixels (eg. 10px)");e.strokeWidth=a}}return e}function k(t,e,i,a,n){const s=S(n);f.addPoints([{x:i,y:a,text:g(t.text),className:e,...s}])}function F(t,e){f.addClass(t,S(e))}function P(t){f.setConfig({chartWidth:t})}function C(t){f.setConfig({chartHeight:t})}function L(){const t=(0,a.D7)(),{themeVariables:e,quadrantChart:i}=t;return i&&f.setConfig(i),f.setThemeConfig({quadrant1Fill:e.quadrant1Fill,quadrant2Fill:e.quadrant2Fill,quadrant3Fill:e.quadrant3Fill,quadrant4Fill:e.quadrant4Fill,quadrant1TextFill:e.quadrant1TextFill,quadrant2TextFill:e.quadrant2TextFill,quadrant3TextFill:e.quadrant3TextFill,quadrant4TextFill:e.quadrant4TextFill,quadrantPointFill:e.quadrantPointFill,quadrantPointTextFill:e.quadrantPointTextFill,quadrantXAxisTextFill:e.quadrantXAxisTextFill,quadrantYAxisTextFill:e.quadrantYAxisTextFill,quadrantExternalBorderStrokeFill:e.quadrantExternalBorderStrokeFill,quadrantInternalBorderStrokeFill:e.quadrantInternalBorderStrokeFill,quadrantTitleFill:e.quadrantTitleFill}),f.setData({titleText:(0,a.ab)()}),f.build()}(0,a.K2)(p,"setQuadrant1Text"),(0,a.K2)(y,"setQuadrant2Text"),(0,a.K2)(T,"setQuadrant3Text"),(0,a.K2)(m,"setQuadrant4Text"),(0,a.K2)(q,"setXAxisLeftText"),(0,a.K2)(A,"setXAxisRightText"),(0,a.K2)(_,"setYAxisTopText"),(0,a.K2)(b,"setYAxisBottomText"),(0,a.K2)(S,"parseStyles"),(0,a.K2)(k,"addPoint"),(0,a.K2)(F,"addClass"),(0,a.K2)(P,"setWidth"),(0,a.K2)(C,"setHeight"),(0,a.K2)(L,"getQuadrantData");var v={parser:r,db:{setWidth:P,setHeight:C,setQuadrant1Text:p,setQuadrant2Text:y,setQuadrant3Text:T,setQuadrant4Text:m,setXAxisLeftText:q,setXAxisRightText:A,setYAxisTopText:_,setYAxisBottomText:b,parseStyles:S,addPoint:k,addClass:F,getQuadrantData:L,clear:(0,a.K2)((function(){f.clear(),(0,a.IU)()}),"clear"),setAccTitle:a.SV,getAccTitle:a.iN,setDiagramTitle:a.ke,getDiagramTitle:a.ab,getAccDescription:a.m7,setAccDescription:a.EI},renderer:{draw:(0,a.K2)(((t,e,i,s)=>{function r(t){return"top"===t?"hanging":"middle"}function o(t){return"left"===t?"start":"middle"}function l(t){return`translate(${t.x}, ${t.y}) rotate(${t.rotation||0})`}(0,a.K2)(r,"getDominantBaseLine"),(0,a.K2)(o,"getTextAnchor"),(0,a.K2)(l,"getTransformation");const h=(0,a.D7)();a.Rm.debug("Rendering quadrant chart\n"+t);const c=h.securityLevel;let d;"sandbox"===c&&(d=(0,n.Ltv)("#i"+e));const u=("sandbox"===c?(0,n.Ltv)(d.nodes()[0].contentDocument.body):(0,n.Ltv)("body")).select(`[id="${e}"]`),x=u.append("g").attr("class","main"),g=h.quadrantChart?.chartWidth??500,f=h.quadrantChart?.chartHeight??500;(0,a.a$)(u,f,g,h.quadrantChart?.useMaxWidth??!0),u.attr("viewBox","0 0 "+g+" "+f),s.db.setHeight(f),s.db.setWidth(g);const p=s.db.getQuadrantData(),y=x.append("g").attr("class","quadrants"),T=x.append("g").attr("class","border"),m=x.append("g").attr("class","data-points"),q=x.append("g").attr("class","labels"),A=x.append("g").attr("class","title");p.title&&A.append("text").attr("x",0).attr("y",0).attr("fill",p.title.fill).attr("font-size",p.title.fontSize).attr("dominant-baseline",r(p.title.horizontalPos)).attr("text-anchor",o(p.title.verticalPos)).attr("transform",l(p.title)).text(p.title.text),p.borderLines&&T.selectAll("line").data(p.borderLines).enter().append("line").attr("x1",(t=>t.x1)).attr("y1",(t=>t.y1)).attr("x2",(t=>t.x2)).attr("y2",(t=>t.y2)).style("stroke",(t=>t.strokeFill)).style("stroke-width",(t=>t.strokeWidth));const _=y.selectAll("g.quadrant").data(p.quadrants).enter().append("g").attr("class","quadrant");_.append("rect").attr("x",(t=>t.x)).attr("y",(t=>t.y)).attr("width",(t=>t.width)).attr("height",(t=>t.height)).attr("fill",(t=>t.fill)),_.append("text").attr("x",0).attr("y",0).attr("fill",(t=>t.text.fill)).attr("font-size",(t=>t.text.fontSize)).attr("dominant-baseline",(t=>r(t.text.horizontalPos))).attr("text-anchor",(t=>o(t.text.verticalPos))).attr("transform",(t=>l(t.text))).text((t=>t.text.text));q.selectAll("g.label").data(p.axisLabels).enter().append("g").attr("class","label").append("text").attr("x",0).attr("y",0).text((t=>t.text)).attr("fill",(t=>t.fill)).attr("font-size",(t=>t.fontSize)).attr("dominant-baseline",(t=>r(t.horizontalPos))).attr("text-anchor",(t=>o(t.verticalPos))).attr("transform",(t=>l(t)));const b=m.selectAll("g.data-point").data(p.points).enter().append("g").attr("class","data-point");b.append("circle").attr("cx",(t=>t.x)).attr("cy",(t=>t.y)).attr("r",(t=>t.radius)).attr("fill",(t=>t.fill)).attr("stroke",(t=>t.strokeColor)).attr("stroke-width",(t=>t.strokeWidth)),b.append("text").attr("x",0).attr("y",0).text((t=>t.text.text)).attr("fill",(t=>t.text.fill)).attr("font-size",(t=>t.text.fontSize)).attr("dominant-baseline",(t=>r(t.text.horizontalPos))).attr("text-anchor",(t=>o(t.text.verticalPos))).attr("transform",(t=>l(t.text)))}),"draw")},styles:(0,a.K2)((()=>""),"styles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4697.c7062f31.js b/pr-preview/pr-1071/assets/js/4697.c7062f31.js deleted file mode 100644 index ce2ea48b82..0000000000 --- a/pr-preview/pr-1071/assets/js/4697.c7062f31.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4697],{34697:(t,n,e)=>{e.d(n,{diagram:()=>rt});var i=e(10009),s=e(20007);function r(t,n){let e;if(void 0===n)for(const i of t)null!=i&&(e>i||void 0===e&&i>=i)&&(e=i);else{let i=-1;for(let s of t)null!=(s=n(s,++i,t))&&(e>s||void 0===e&&s>=s)&&(e=s)}return e}function o(t){return t.target.depth}function c(t,n){return t.sourceLinks.length?t.depth:n-1}function a(t,n){let e=0;if(void 0===n)for(let i of t)(i=+i)&&(e+=i);else{let i=-1;for(let s of t)(s=+n(s,++i,t))&&(e+=s)}return e}function l(t,n){let e;if(void 0===n)for(const i of t)null!=i&&(e<i||void 0===e&&i>=i)&&(e=i);else{let i=-1;for(let s of t)null!=(s=n(s,++i,t))&&(e<s||void 0===e&&s>=s)&&(e=s)}return e}function h(t){return function(){return t}}function u(t,n){return y(t.source,n.source)||t.index-n.index}function f(t,n){return y(t.target,n.target)||t.index-n.index}function y(t,n){return t.y0-n.y0}function d(t){return t.value}function p(t){return t.index}function g(t){return t.nodes}function _(t){return t.links}function k(t,n){const e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function x({nodes:t}){for(const n of t){let t=n.y0,e=t;for(const i of n.sourceLinks)i.y0=t+i.width/2,t+=i.width;for(const i of n.targetLinks)i.y1=e+i.width/2,e+=i.width}}function m(){let t,n,e,i=0,s=0,o=1,m=1,v=24,b=8,w=p,L=c,S=g,E=_,A=6;function K(){const c={nodes:S.apply(null,arguments),links:E.apply(null,arguments)};return function({nodes:t,links:n}){for(const[e,s]of t.entries())s.index=e,s.sourceLinks=[],s.targetLinks=[];const i=new Map(t.map(((n,e)=>[w(n,e,t),n])));for(const[e,s]of n.entries()){s.index=e;let{source:t,target:n}=s;"object"!=typeof t&&(t=s.source=k(i,t)),"object"!=typeof n&&(n=s.target=k(i,n)),t.sourceLinks.push(s),n.targetLinks.push(s)}if(null!=e)for(const{sourceLinks:s,targetLinks:r}of t)s.sort(e),r.sort(e)}(c),function({nodes:t}){for(const n of t)n.value=void 0===n.fixedValue?Math.max(a(n.sourceLinks,d),a(n.targetLinks,d)):n.fixedValue}(c),function({nodes:t}){const n=t.length;let e=new Set(t),i=new Set,s=0;for(;e.size;){for(const t of e){t.depth=s;for(const{target:n}of t.sourceLinks)i.add(n)}if(++s>n)throw new Error("circular link");e=i,i=new Set}}(c),function({nodes:t}){const n=t.length;let e=new Set(t),i=new Set,s=0;for(;e.size;){for(const t of e){t.height=s;for(const{source:n}of t.targetLinks)i.add(n)}if(++s>n)throw new Error("circular link");e=i,i=new Set}}(c),function(e){const c=function({nodes:t}){const e=l(t,(t=>t.depth))+1,s=(o-i-v)/(e-1),r=new Array(e);for(const n of t){const t=Math.max(0,Math.min(e-1,Math.floor(L.call(null,n,e))));n.layer=t,n.x0=i+t*s,n.x1=n.x0+v,r[t]?r[t].push(n):r[t]=[n]}if(n)for(const i of r)i.sort(n);return r}(e);t=Math.min(b,(m-s)/(l(c,(t=>t.length))-1)),function(n){const e=r(n,(n=>(m-s-(n.length-1)*t)/a(n,d)));for(const i of n){let n=s;for(const s of i){s.y0=n,s.y1=n+s.value*e,n=s.y1+t;for(const t of s.sourceLinks)t.width=t.value*e}n=(m-n+t)/(i.length+1);for(let t=0;t<i.length;++t){const e=i[t];e.y0+=n*(t+1),e.y1+=n*(t+1)}C(i)}}(c);for(let t=0;t<A;++t){const n=Math.pow(.99,t),e=Math.max(1-n,(t+1)/A);I(c,n,e),M(c,n,e)}}(c),x(c),c}function M(t,e,i){for(let s=1,r=t.length;s<r;++s){const r=t[s];for(const t of r){let n=0,i=0;for(const{source:e,value:r}of t.targetLinks){let s=r*(t.layer-e.layer);n+=O(e,t)*s,i+=s}if(!(i>0))continue;let s=(n/i-t.y0)*e;t.y0+=s,t.y1+=s,P(t)}void 0===n&&r.sort(y),T(r,i)}}function I(t,e,i){for(let s=t.length-2;s>=0;--s){const r=t[s];for(const t of r){let n=0,i=0;for(const{target:e,value:r}of t.sourceLinks){let s=r*(e.layer-t.layer);n+=$(t,e)*s,i+=s}if(!(i>0))continue;let s=(n/i-t.y0)*e;t.y0+=s,t.y1+=s,P(t)}void 0===n&&r.sort(y),T(r,i)}}function T(n,e){const i=n.length>>1,r=n[i];N(n,r.y0-t,i-1,e),D(n,r.y1+t,i+1,e),N(n,m,n.length-1,e),D(n,s,0,e)}function D(n,e,i,s){for(;i<n.length;++i){const r=n[i],o=(e-r.y0)*s;o>1e-6&&(r.y0+=o,r.y1+=o),e=r.y1+t}}function N(n,e,i,s){for(;i>=0;--i){const r=n[i],o=(r.y1-e)*s;o>1e-6&&(r.y0-=o,r.y1-=o),e=r.y0-t}}function P({sourceLinks:t,targetLinks:n}){if(void 0===e){for(const{source:{sourceLinks:t}}of n)t.sort(f);for(const{target:{targetLinks:n}}of t)n.sort(u)}}function C(t){if(void 0===e)for(const{sourceLinks:n,targetLinks:e}of t)n.sort(f),e.sort(u)}function O(n,e){let i=n.y0-(n.sourceLinks.length-1)*t/2;for(const{target:s,width:r}of n.sourceLinks){if(s===e)break;i+=r+t}for(const{source:t,width:s}of e.targetLinks){if(t===n)break;i-=s}return i}function $(n,e){let i=e.y0-(e.targetLinks.length-1)*t/2;for(const{source:s,width:r}of e.targetLinks){if(s===n)break;i+=r+t}for(const{target:t,width:s}of n.sourceLinks){if(t===e)break;i-=s}return i}return K.update=function(t){return x(t),t},K.nodeId=function(t){return arguments.length?(w="function"==typeof t?t:h(t),K):w},K.nodeAlign=function(t){return arguments.length?(L="function"==typeof t?t:h(t),K):L},K.nodeSort=function(t){return arguments.length?(n=t,K):n},K.nodeWidth=function(t){return arguments.length?(v=+t,K):v},K.nodePadding=function(n){return arguments.length?(b=t=+n,K):b},K.nodes=function(t){return arguments.length?(S="function"==typeof t?t:h(t),K):S},K.links=function(t){return arguments.length?(E="function"==typeof t?t:h(t),K):E},K.linkSort=function(t){return arguments.length?(e=t,K):e},K.size=function(t){return arguments.length?(i=s=0,o=+t[0],m=+t[1],K):[o-i,m-s]},K.extent=function(t){return arguments.length?(i=+t[0][0],o=+t[1][0],s=+t[0][1],m=+t[1][1],K):[[i,s],[o,m]]},K.iterations=function(t){return arguments.length?(A=+t,K):A},K}var v=Math.PI,b=2*v,w=1e-6,L=b-w;function S(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function E(){return new S}S.prototype=E.prototype={constructor:S,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,i){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+i)},bezierCurveTo:function(t,n,e,i,s,r){this._+="C"+ +t+","+ +n+","+ +e+","+ +i+","+(this._x1=+s)+","+(this._y1=+r)},arcTo:function(t,n,e,i,s){t=+t,n=+n,e=+e,i=+i,s=+s;var r=this._x1,o=this._y1,c=e-t,a=i-n,l=r-t,h=o-n,u=l*l+h*h;if(s<0)throw new Error("negative radius: "+s);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(u>w)if(Math.abs(h*c-a*l)>w&&s){var f=e-r,y=i-o,d=c*c+a*a,p=f*f+y*y,g=Math.sqrt(d),_=Math.sqrt(u),k=s*Math.tan((v-Math.acos((d+u-p)/(2*g*_)))/2),x=k/_,m=k/g;Math.abs(x-1)>w&&(this._+="L"+(t+x*l)+","+(n+x*h)),this._+="A"+s+","+s+",0,0,"+ +(h*f>l*y)+","+(this._x1=t+m*c)+","+(this._y1=n+m*a)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,i,s,r){t=+t,n=+n,r=!!r;var o=(e=+e)*Math.cos(i),c=e*Math.sin(i),a=t+o,l=n+c,h=1^r,u=r?i-s:s-i;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+a+","+l:(Math.abs(this._x1-a)>w||Math.abs(this._y1-l)>w)&&(this._+="L"+a+","+l),e&&(u<0&&(u=u%b+b),u>L?this._+="A"+e+","+e+",0,1,"+h+","+(t-o)+","+(n-c)+"A"+e+","+e+",0,1,"+h+","+(this._x1=a)+","+(this._y1=l):u>w&&(this._+="A"+e+","+e+",0,"+ +(u>=v)+","+h+","+(this._x1=t+e*Math.cos(s))+","+(this._y1=n+e*Math.sin(s))))},rect:function(t,n,e,i){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +i+"h"+-e+"Z"},toString:function(){return this._}};const A=E;var K=Array.prototype.slice;function M(t){return function(){return t}}function I(t){return t[0]}function T(t){return t[1]}function D(t){return t.source}function N(t){return t.target}function P(t){var n=D,e=N,i=I,s=T,r=null;function o(){var o,c=K.call(arguments),a=n.apply(this,c),l=e.apply(this,c);if(r||(r=o=A()),t(r,+i.apply(this,(c[0]=a,c)),+s.apply(this,c),+i.apply(this,(c[0]=l,c)),+s.apply(this,c)),o)return r=null,o+""||null}return o.source=function(t){return arguments.length?(n=t,o):n},o.target=function(t){return arguments.length?(e=t,o):e},o.x=function(t){return arguments.length?(i="function"==typeof t?t:M(+t),o):i},o.y=function(t){return arguments.length?(s="function"==typeof t?t:M(+t),o):s},o.context=function(t){return arguments.length?(r=null==t?null:t,o):r},o}function C(t,n,e,i,s){t.moveTo(n,e),t.bezierCurveTo(n=(n+i)/2,e,n,s,i,s)}function O(t){return[t.source.x1,t.y0]}function $(t){return[t.target.x0,t.y1]}function j(){return P(C).source(O).target($)}var z=function(){var t=(0,i.K2)((function(t,n,e,i){for(e=e||{},i=t.length;i--;e[t[i]]=n);return e}),"o"),n=[1,9],e=[1,10],s=[1,5,10,12],r={trace:(0,i.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,SANKEY:4,NEWLINE:5,csv:6,opt_eof:7,record:8,csv_tail:9,EOF:10,"field[source]":11,COMMA:12,"field[target]":13,"field[value]":14,field:15,escaped:16,non_escaped:17,DQUOTE:18,ESCAPED_TEXT:19,NON_ESCAPED_TEXT:20,$accept:0,$end:1},terminals_:{2:"error",4:"SANKEY",5:"NEWLINE",10:"EOF",11:"field[source]",12:"COMMA",13:"field[target]",14:"field[value]",18:"DQUOTE",19:"ESCAPED_TEXT",20:"NON_ESCAPED_TEXT"},productions_:[0,[3,4],[6,2],[9,2],[9,0],[7,1],[7,0],[8,5],[15,1],[15,1],[16,3],[17,1]],performAction:(0,i.K2)((function(t,n,e,i,s,r,o){var c=r.length-1;switch(s){case 7:const t=i.findOrCreateNode(r[c-4].trim().replaceAll('""','"')),n=i.findOrCreateNode(r[c-2].trim().replaceAll('""','"')),e=parseFloat(r[c].trim());i.addLink(t,n,e);break;case 8:case 9:case 11:this.$=r[c];break;case 10:this.$=r[c-1]}}),"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3]},{6:4,8:5,15:6,16:7,17:8,18:n,20:e},{1:[2,6],7:11,10:[1,12]},t(e,[2,4],{9:13,5:[1,14]}),{12:[1,15]},t(s,[2,8]),t(s,[2,9]),{19:[1,16]},t(s,[2,11]),{1:[2,1]},{1:[2,5]},t(e,[2,2]),{6:17,8:5,15:6,16:7,17:8,18:n,20:e},{15:18,16:7,17:8,18:n,20:e},{18:[1,19]},t(e,[2,3]),{12:[1,20]},t(s,[2,10]),{15:21,16:7,17:8,18:n,20:e},t([1,5,10],[2,7])],defaultActions:{11:[2,1],12:[2,5]},parseError:(0,i.K2)((function(t,n){if(!n.recoverable){var e=new Error(t);throw e.hash=n,e}this.trace(t)}),"parseError"),parse:(0,i.K2)((function(t){var n=this,e=[0],s=[],r=[null],o=[],c=this.table,a="",l=0,h=0,u=0,f=o.slice.call(arguments,1),y=Object.create(this.lexer),d={yy:{}};for(var p in this.yy)Object.prototype.hasOwnProperty.call(this.yy,p)&&(d.yy[p]=this.yy[p]);y.setInput(t,d.yy),d.yy.lexer=y,d.yy.parser=this,void 0===y.yylloc&&(y.yylloc={});var g=y.yylloc;o.push(g);var _=y.options&&y.options.ranges;function k(){var t;return"number"!=typeof(t=s.pop()||y.lex()||1)&&(t instanceof Array&&(t=(s=t).pop()),t=n.symbols_[t]||t),t}"function"==typeof d.yy.parseError?this.parseError=d.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,i.K2)((function(t){e.length=e.length-2*t,r.length=r.length-t,o.length=o.length-t}),"popStack"),(0,i.K2)(k,"lex");for(var x,m,v,b,w,L,S,E,A,K={};;){if(v=e[e.length-1],this.defaultActions[v]?b=this.defaultActions[v]:(null==x&&(x=k()),b=c[v]&&c[v][x]),void 0===b||!b.length||!b[0]){var M="";for(L in A=[],c[v])this.terminals_[L]&&L>2&&A.push("'"+this.terminals_[L]+"'");M=y.showPosition?"Parse error on line "+(l+1)+":\n"+y.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[x]||x)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==x?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(M,{text:y.match,token:this.terminals_[x]||x,line:y.yylineno,loc:g,expected:A})}if(b[0]instanceof Array&&b.length>1)throw new Error("Parse Error: multiple actions possible at state: "+v+", token: "+x);switch(b[0]){case 1:e.push(x),r.push(y.yytext),o.push(y.yylloc),e.push(b[1]),x=null,m?(x=m,m=null):(h=y.yyleng,a=y.yytext,l=y.yylineno,g=y.yylloc,u>0&&u--);break;case 2:if(S=this.productions_[b[1]][1],K.$=r[r.length-S],K._$={first_line:o[o.length-(S||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(S||1)].first_column,last_column:o[o.length-1].last_column},_&&(K._$.range=[o[o.length-(S||1)].range[0],o[o.length-1].range[1]]),void 0!==(w=this.performAction.apply(K,[a,h,l,d.yy,b[1],r,o].concat(f))))return w;S&&(e=e.slice(0,-1*S*2),r=r.slice(0,-1*S),o=o.slice(0,-1*S)),e.push(this.productions_[b[1]][0]),r.push(K.$),o.push(K._$),E=c[e[e.length-2]][e[e.length-1]],e.push(E);break;case 3:return!0}}return!0}),"parse")},o=function(){return{EOF:1,parseError:(0,i.K2)((function(t,n){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,n)}),"parseError"),setInput:(0,i.K2)((function(t,n){return this.yy=n||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,i.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,i.K2)((function(t){var n=t.length,e=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-n),this.offset-=n;var i=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),e.length-1&&(this.yylineno-=e.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:e?(e.length===i.length?this.yylloc.first_column:0)+i[i.length-e.length].length-e[0].length:this.yylloc.first_column-n},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-n]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,i.K2)((function(){return this._more=!0,this}),"more"),reject:(0,i.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,i.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,i.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,i.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,i.K2)((function(){var t=this.pastInput(),n=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+n+"^"}),"showPosition"),test_match:(0,i.K2)((function(t,n){var e,i,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),(i=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],e=this.performAction.call(this,this.yy,this,n,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),e)return e;if(this._backtrack){for(var r in s)this[r]=s[r];return!1}return!1}),"test_match"),next:(0,i.K2)((function(){if(this.done)return this.EOF;var t,n,e,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),r=0;r<s.length;r++)if((e=this._input.match(this.rules[s[r]]))&&(!n||e[0].length>n[0].length)){if(n=e,i=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(e,s[r])))return t;if(this._backtrack){n=!1;continue}return!1}if(!this.options.flex)break}return n?!1!==(t=this.test_match(n,s[i]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,i.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,i.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,i.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,i.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,i.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,i.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,i.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,i.K2)((function(t,n,e,i){switch(e){case 0:return this.pushState("csv"),4;case 1:return 10;case 2:return 5;case 3:return 12;case 4:return this.pushState("escaped_text"),18;case 5:return 20;case 6:return this.popState("escaped_text"),18;case 7:return 19}}),"anonymous"),rules:[/^(?:sankey-beta\b)/i,/^(?:$)/i,/^(?:((\u000D\u000A)|(\u000A)))/i,/^(?:(\u002C))/i,/^(?:(\u0022))/i,/^(?:([\u0020-\u0021\u0023-\u002B\u002D-\u007E])*)/i,/^(?:(\u0022)(?!(\u0022)))/i,/^(?:(([\u0020-\u0021\u0023-\u002B\u002D-\u007E])|(\u002C)|(\u000D)|(\u000A)|(\u0022)(\u0022))*)/i],conditions:{csv:{rules:[1,2,3,4,5,6,7],inclusive:!1},escaped_text:{rules:[6,7],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7],inclusive:!0}}}}();function c(){this.yy={}}return r.lexer=o,(0,i.K2)(c,"Parser"),c.prototype=r,r.Parser=c,new c}();z.parser=z;var U=z,F=[],W=[],G=new Map,V=(0,i.K2)((()=>{F=[],W=[],G=new Map,(0,i.IU)()}),"clear"),X=class{constructor(t,n,e=0){this.source=t,this.target=n,this.value=e}static{(0,i.K2)(this,"SankeyLink")}},Y=(0,i.K2)(((t,n,e)=>{F.push(new X(t,n,e))}),"addLink"),q=class{constructor(t){this.ID=t}static{(0,i.K2)(this,"SankeyNode")}},Q=(0,i.K2)((t=>{t=i.Y2.sanitizeText(t,(0,i.D7)());let n=G.get(t);return void 0===n&&(n=new q(t),G.set(t,n),W.push(n)),n}),"findOrCreateNode"),R=(0,i.K2)((()=>W),"getNodes"),B=(0,i.K2)((()=>F),"getLinks"),Z=(0,i.K2)((()=>({nodes:W.map((t=>({id:t.ID}))),links:F.map((t=>({source:t.source.ID,target:t.target.ID,value:t.value})))})),"getGraph"),H={nodesMap:G,getConfig:(0,i.K2)((()=>(0,i.D7)().sankey),"getConfig"),getNodes:R,getLinks:B,getGraph:Z,addLink:Y,findOrCreateNode:Q,getAccTitle:i.iN,setAccTitle:i.SV,getAccDescription:i.m7,setAccDescription:i.EI,getDiagramTitle:i.ab,setDiagramTitle:i.ke,clear:V},J=class t{static{(0,i.K2)(this,"Uid")}static{this.count=0}static next(n){return new t(n+ ++t.count)}constructor(t){this.id=t,this.href=`#${t}`}toString(){return"url("+this.href+")"}},tt={left:function(t){return t.depth},right:function(t,n){return n-1-t.height},center:function(t){return t.targetLinks.length?t.depth:t.sourceLinks.length?r(t.sourceLinks,o)-1:0},justify:c},nt=(0,i.K2)((function(t,n,e,r){const{securityLevel:o,sankey:c}=(0,i.D7)(),a=i.ME.sankey;let l;"sandbox"===o&&(l=(0,s.Ltv)("#i"+n));const h="sandbox"===o?(0,s.Ltv)(l.nodes()[0].contentDocument.body):(0,s.Ltv)("body"),u="sandbox"===o?h.select(`[id="${n}"]`):(0,s.Ltv)(`[id="${n}"]`),f=c?.width??a.width,y=c?.height??a.width,d=c?.useMaxWidth??a.useMaxWidth,p=c?.nodeAlignment??a.nodeAlignment,g=c?.prefix??a.prefix,_=c?.suffix??a.suffix,k=c?.showValues??a.showValues,x=r.db.getGraph(),v=tt[p];m().nodeId((t=>t.id)).nodeWidth(10).nodePadding(10+(k?15:0)).nodeAlign(v).extent([[0,0],[f,y]])(x);const b=(0,s.UMr)(s.zt);u.append("g").attr("class","nodes").selectAll(".node").data(x.nodes).join("g").attr("class","node").attr("id",(t=>(t.uid=J.next("node-")).id)).attr("transform",(function(t){return"translate("+t.x0+","+t.y0+")"})).attr("x",(t=>t.x0)).attr("y",(t=>t.y0)).append("rect").attr("height",(t=>t.y1-t.y0)).attr("width",(t=>t.x1-t.x0)).attr("fill",(t=>b(t.id)));const w=(0,i.K2)((({id:t,value:n})=>k?`${t}\n${g}${Math.round(100*n)/100}${_}`:t),"getText");u.append("g").attr("class","node-labels").attr("font-family","sans-serif").attr("font-size",14).selectAll("text").data(x.nodes).join("text").attr("x",(t=>t.x0<f/2?t.x1+6:t.x0-6)).attr("y",(t=>(t.y1+t.y0)/2)).attr("dy",(k?"0":"0.35")+"em").attr("text-anchor",(t=>t.x0<f/2?"start":"end")).text(w);const L=u.append("g").attr("class","links").attr("fill","none").attr("stroke-opacity",.5).selectAll(".link").data(x.links).join("g").attr("class","link").style("mix-blend-mode","multiply"),S=c?.linkColor??"gradient";if("gradient"===S){const t=L.append("linearGradient").attr("id",(t=>(t.uid=J.next("linearGradient-")).id)).attr("gradientUnits","userSpaceOnUse").attr("x1",(t=>t.source.x1)).attr("x2",(t=>t.target.x0));t.append("stop").attr("offset","0%").attr("stop-color",(t=>b(t.source.id))),t.append("stop").attr("offset","100%").attr("stop-color",(t=>b(t.target.id)))}let E;switch(S){case"gradient":E=(0,i.K2)((t=>t.uid),"coloring");break;case"source":E=(0,i.K2)((t=>b(t.source.id)),"coloring");break;case"target":E=(0,i.K2)((t=>b(t.target.id)),"coloring");break;default:E=S}L.append("path").attr("d",j()).attr("stroke",E).attr("stroke-width",(t=>Math.max(1,t.width))),(0,i.ot)(void 0,u,0,d)}),"draw"),et={draw:nt},it=(0,i.K2)((t=>t.replaceAll(/^[^\S\n\r]+|[^\S\n\r]+$/g,"").replaceAll(/([\n\r])+/g,"\n").trim()),"prepareTextForParsing"),st=U.parse.bind(U);U.parse=t=>st(it(t));var rt={parser:U,db:H,renderer:et}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/46d228a0.f0474804.js b/pr-preview/pr-1071/assets/js/46d228a0.f0474804.js deleted file mode 100644 index 2c9c87a15c..0000000000 --- a/pr-preview/pr-1071/assets/js/46d228a0.f0474804.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3246],{78137:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-1.2/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/components/service-mesh.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/components/policies"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/architecture/attestation"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"CONTRAST_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"CONTRAST_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"<name>#<port>#false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:"<name>"})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"<name>#<port>#true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: CONTRAST_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v1.2.0@sha256:756818aff3c61cc4852ef551a2fabfa90269d0b0a53d50c0e32fe448bac4d994"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-secrets\n mountPath: /contrast\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"<name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port>"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:"<name>"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/48f2f8ef.546ed612.js b/pr-preview/pr-1071/assets/js/48f2f8ef.546ed612.js deleted file mode 100644 index 1440c657c2..0000000000 --- a/pr-preview/pr-1071/assets/js/48f2f8ef.546ed612.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2020],{80401:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-1.1/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/architecture/attestation.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/1.1/components/service-mesh"},"next":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/secrets"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(69184).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(50981).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nThe hypervisor adds the hash of the policy to the attestation report via the HOSTDATA (on AMD SEV-SNP) or MRCONFIGID (Intel TDX) fields.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,r.jsx)(t.code,{children:"MRCONFIGID"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(26080).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP or Intel TDX to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},26080:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},50981:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},69184:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4ce6baab.ef6f63da.js b/pr-preview/pr-1071/assets/js/4ce6baab.ef6f63da.js deleted file mode 100644 index edea2c3c50..0000000000 --- a/pr-preview/pr-1071/assets/js/4ce6baab.ef6f63da.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[455],{57718:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-1.0/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/1.0/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/about/telemetry.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/1.0/features-limitations"}}');var r=n(74848),o=n(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4cf3063f.2196b4dd.js b/pr-preview/pr-1071/assets/js/4cf3063f.2196b4dd.js deleted file mode 100644 index 3a4a42da20..0000000000 --- a/pr-preview/pr-1071/assets/js/4cf3063f.2196b4dd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8364],{53881:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-1.0/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/basics/features.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/1.0/getting-started/install"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4eec459c.1d030701.js b/pr-preview/pr-1071/assets/js/4eec459c.1d030701.js deleted file mode 100644 index 951532880f..0000000000 --- a/pr-preview/pr-1071/assets/js/4eec459c.1d030701.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2639],{13204:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-1.1/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/1.1/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/components/runtime.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/1.1/components/overview"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/1.1/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"Virtual machine manager (VMM)",id:"virtual-machine-manager-vmm",level:3},{value:"Snapshotters",id:"snapshotters",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled/TDX-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(81553).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"virtual-machine-manager-vmm",children:"Virtual machine manager (VMM)"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses a virtual machine monitor to create a confidential virtual machine for every pod.\nOn AKS, Contrast uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})}),".\nOn bare metal, Contrast uses ",(0,i.jsx)(n.a,{href:"https://www.qemu.org/",children:(0,i.jsx)(n.code,{children:"QEMU"})}),".\nThe appropriate files are installed on every node by the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"snapshotters",children:"Snapshotters"}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotters"]})," to provide container images to the pod-VM.\nEach snapshotter consists of a host component that pulls container images and a guest component used to mount/pull container images."]}),"\n",(0,i.jsxs)(n.p,{children:["On AKS, Contrast uses the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})})," snapshotter to provide container images as block devices to the pod-VM.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsxs)(n.p,{children:["On bare metal, Contrast uses the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/nydus-snapshotter",children:(0,i.jsx)(n.code,{children:"nydus"})})," snapshotter to store metadata about the images. This metadata is communicated to the guest, so that it can pull the images itself."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," or ",(0,i.jsx)(n.code,{children:"QEMU"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file or separate firmware and kernel files for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},81553:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4f453872.54000c58.js b/pr-preview/pr-1071/assets/js/4f453872.54000c58.js deleted file mode 100644 index 5b7d932bf9..0000000000 --- a/pr-preview/pr-1071/assets/js/4f453872.54000c58.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8170],{80786:(t,e,r)=>{r.r(e),r.d(e,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>n,toc:()=>p});const n=JSON.parse('{"id":"architecture/attestation/pod-vm","title":"pod-vm","description":"","source":"@site/versioned_docs/version-0.5/architecture/attestation/pod-vm.md","sourceDirName":"architecture/attestation","slug":"/architecture/attestation/pod-vm","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/attestation/pod-vm.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Hardware","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware"},"next":{"title":"Runtime policies","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies"}}');var o=r(74848),s=r(28453);const a={},i=void 0,c={},p=[];function u(t){return(0,o.jsx)(o.Fragment,{})}function d(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,o.jsx)(e,{...t,children:(0,o.jsx)(u,{...t})}):u()}},28453:(t,e,r)=>{r.d(e,{R:()=>a,x:()=>i});var n=r(96540);const o={},s=n.createContext(o);function a(t){const e=n.useContext(s);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:a(t.components),n.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/4fb24623.b975bdd4.js b/pr-preview/pr-1071/assets/js/4fb24623.b975bdd4.js deleted file mode 100644 index 111fa01a8c..0000000000 --- a/pr-preview/pr-1071/assets/js/4fb24623.b975bdd4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2550],{17364:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/docs/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/next/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/architecture/certificates.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/next/architecture/secrets"},"next":{"title":"Security considerations","permalink":"/contrast/pr-preview/pr-1071/next/architecture/security-considerations"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(34102).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},34102:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/50474e10.3d570577.js b/pr-preview/pr-1071/assets/js/50474e10.3d570577.js deleted file mode 100644 index afcfe3dd9f..0000000000 --- a/pr-preview/pr-1071/assets/js/50474e10.3d570577.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7061],{63297:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-0.6/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/basics/confidential-containers.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Contrast","permalink":"/contrast/pr-preview/pr-1071/0.6/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5110.759384b2.js b/pr-preview/pr-1071/assets/js/5110.759384b2.js deleted file mode 100644 index 31fbe343b6..0000000000 --- a/pr-preview/pr-1071/assets/js/5110.759384b2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5110],{65110:(r,e,t)=>{t.d(e,{diagram:()=>c});var s=t(90758),a=(t(96474),t(87308),t(37938),t(1282),t(64532),t(47588),t(33115),t(10483),t(8159),t(10009)),c={parser:s.Zk,db:s.iP,renderer:s.q7,styles:s.tM,init:(0,a.K2)((r=>{r.state||(r.state={}),r.state.arrowMarkerAbsolute=r.arrowMarkerAbsolute,s.iP.clear()}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/51513a8d.5cbac465.js b/pr-preview/pr-1071/assets/js/51513a8d.5cbac465.js deleted file mode 100644 index e4be298db9..0000000000 --- a/pr-preview/pr-1071/assets/js/51513a8d.5cbac465.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3859],{12241:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/versioned_docs/version-1.0/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/architecture/observability.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/certificates"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/1.0/features-limitations"}}');var s=r(74848),i=r(28453);const o={},c="Observability",a={},d=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function h(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator exports gRPC metrics under the prefix ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_"}),".\nThese metrics are labeled with the gRPC service name and method name.\nMetrics of interest include ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handled_total"}),", which counts\nthe number of requests by return code, and\n",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handling_seconds_bucket"}),", which produces a histogram of",(0,s.jsx)(t.br,{}),"\n","request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["The gRPC service ",(0,s.jsx)(t.code,{children:"userapi.UserAPI"})," records metrics for the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"meshapi.MeshAPI"})," service records metrics for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"}),", which\ngets called by the ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures_total"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5410.e9c6eab1.js b/pr-preview/pr-1071/assets/js/5410.e9c6eab1.js deleted file mode 100644 index 4cd747b1b9..0000000000 --- a/pr-preview/pr-1071/assets/js/5410.e9c6eab1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5410],{37981:(t,e,r)=>{r.d(e,{T:()=>f});var s=r(39142),a=r(89610),i=r(27422),n=r(94092),o=r(66401),l=r(8058),c=r(69592),d=r(13588),h=r(24326),g=r(99902),u=r(53533);const p=(0,h.A)((function(t){return(0,g.A)((0,d.A)(t,1,u.A,!0))}));var y=r(38207),b=r(89463),x="\0";class f{constructor(t={}){this._isDirected=!Object.prototype.hasOwnProperty.call(t,"directed")||t.directed,this._isMultigraph=!!Object.prototype.hasOwnProperty.call(t,"multigraph")&&t.multigraph,this._isCompound=!!Object.prototype.hasOwnProperty.call(t,"compound")&&t.compound,this._label=void 0,this._defaultNodeLabelFn=s.A(void 0),this._defaultEdgeLabelFn=s.A(void 0),this._nodes={},this._isCompound&&(this._parent={},this._children={},this._children[x]={}),this._in={},this._preds={},this._out={},this._sucs={},this._edgeObjs={},this._edgeLabels={}}isDirected(){return this._isDirected}isMultigraph(){return this._isMultigraph}isCompound(){return this._isCompound}setGraph(t){return this._label=t,this}graph(){return this._label}setDefaultNodeLabel(t){return a.A(t)||(t=s.A(t)),this._defaultNodeLabelFn=t,this}nodeCount(){return this._nodeCount}nodes(){return i.A(this._nodes)}sources(){var t=this;return n.A(this.nodes(),(function(e){return o.A(t._in[e])}))}sinks(){var t=this;return n.A(this.nodes(),(function(e){return o.A(t._out[e])}))}setNodes(t,e){var r=arguments,s=this;return l.A(t,(function(t){r.length>1?s.setNode(t,e):s.setNode(t)})),this}setNode(t,e){return Object.prototype.hasOwnProperty.call(this._nodes,t)?(arguments.length>1&&(this._nodes[t]=e),this):(this._nodes[t]=arguments.length>1?e:this._defaultNodeLabelFn(t),this._isCompound&&(this._parent[t]=x,this._children[t]={},this._children[x][t]=!0),this._in[t]={},this._preds[t]={},this._out[t]={},this._sucs[t]={},++this._nodeCount,this)}node(t){return this._nodes[t]}hasNode(t){return Object.prototype.hasOwnProperty.call(this._nodes,t)}removeNode(t){if(Object.prototype.hasOwnProperty.call(this._nodes,t)){var e=t=>this.removeEdge(this._edgeObjs[t]);delete this._nodes[t],this._isCompound&&(this._removeFromParentsChildList(t),delete this._parent[t],l.A(this.children(t),(t=>{this.setParent(t)})),delete this._children[t]),l.A(i.A(this._in[t]),e),delete this._in[t],delete this._preds[t],l.A(i.A(this._out[t]),e),delete this._out[t],delete this._sucs[t],--this._nodeCount}return this}setParent(t,e){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(c.A(e))e=x;else{for(var r=e+="";!c.A(r);r=this.parent(r))if(r===t)throw new Error("Setting "+e+" as parent of "+t+" would create a cycle");this.setNode(e)}return this.setNode(t),this._removeFromParentsChildList(t),this._parent[t]=e,this._children[e][t]=!0,this}_removeFromParentsChildList(t){delete this._children[this._parent[t]][t]}parent(t){if(this._isCompound){var e=this._parent[t];if(e!==x)return e}}children(t){if(c.A(t)&&(t=x),this._isCompound){var e=this._children[t];if(e)return i.A(e)}else{if(t===x)return this.nodes();if(this.hasNode(t))return[]}}predecessors(t){var e=this._preds[t];if(e)return i.A(e)}successors(t){var e=this._sucs[t];if(e)return i.A(e)}neighbors(t){var e=this.predecessors(t);if(e)return p(e,this.successors(t))}isLeaf(t){return 0===(this.isDirected()?this.successors(t):this.neighbors(t)).length}filterNodes(t){var e=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});e.setGraph(this.graph());var r=this;l.A(this._nodes,(function(r,s){t(s)&&e.setNode(s,r)})),l.A(this._edgeObjs,(function(t){e.hasNode(t.v)&&e.hasNode(t.w)&&e.setEdge(t,r.edge(t))}));var s={};function a(t){var i=r.parent(t);return void 0===i||e.hasNode(i)?(s[t]=i,i):i in s?s[i]:a(i)}return this._isCompound&&l.A(e.nodes(),(function(t){e.setParent(t,a(t))})),e}setDefaultEdgeLabel(t){return a.A(t)||(t=s.A(t)),this._defaultEdgeLabelFn=t,this}edgeCount(){return this._edgeCount}edges(){return y.A(this._edgeObjs)}setPath(t,e){var r=this,s=arguments;return b.A(t,(function(t,a){return s.length>1?r.setEdge(t,a,e):r.setEdge(t,a),a})),this}setEdge(){var t,e,r,s,a=!1,i=arguments[0];"object"==typeof i&&null!==i&&"v"in i?(t=i.v,e=i.w,r=i.name,2===arguments.length&&(s=arguments[1],a=!0)):(t=i,e=arguments[1],r=arguments[3],arguments.length>2&&(s=arguments[2],a=!0)),t=""+t,e=""+e,c.A(r)||(r=""+r);var n=_(this._isDirected,t,e,r);if(Object.prototype.hasOwnProperty.call(this._edgeLabels,n))return a&&(this._edgeLabels[n]=s),this;if(!c.A(r)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(t),this.setNode(e),this._edgeLabels[n]=a?s:this._defaultEdgeLabelFn(t,e,r);var o=function(t,e,r,s){var a=""+e,i=""+r;if(!t&&a>i){var n=a;a=i,i=n}var o={v:a,w:i};s&&(o.name=s);return o}(this._isDirected,t,e,r);return t=o.v,e=o.w,Object.freeze(o),this._edgeObjs[n]=o,m(this._preds[e],t),m(this._sucs[t],e),this._in[e][n]=o,this._out[t][n]=o,this._edgeCount++,this}edge(t,e,r){var s=1===arguments.length?L(this._isDirected,arguments[0]):_(this._isDirected,t,e,r);return this._edgeLabels[s]}hasEdge(t,e,r){var s=1===arguments.length?L(this._isDirected,arguments[0]):_(this._isDirected,t,e,r);return Object.prototype.hasOwnProperty.call(this._edgeLabels,s)}removeEdge(t,e,r){var s=1===arguments.length?L(this._isDirected,arguments[0]):_(this._isDirected,t,e,r),a=this._edgeObjs[s];return a&&(t=a.v,e=a.w,delete this._edgeLabels[s],delete this._edgeObjs[s],w(this._preds[e],t),w(this._sucs[t],e),delete this._in[e][s],delete this._out[t][s],this._edgeCount--),this}inEdges(t,e){var r=this._in[t];if(r){var s=y.A(r);return e?n.A(s,(function(t){return t.v===e})):s}}outEdges(t,e){var r=this._out[t];if(r){var s=y.A(r);return e?n.A(s,(function(t){return t.w===e})):s}}nodeEdges(t,e){var r=this.inEdges(t,e);if(r)return r.concat(this.outEdges(t,e))}}function m(t,e){t[e]?t[e]++:t[e]=1}function w(t,e){--t[e]||delete t[e]}function _(t,e,r,s){var a=""+e,i=""+r;if(!t&&a>i){var n=a;a=i,i=n}return a+"\x01"+i+"\x01"+(c.A(s)?"\0":s)}function L(t,e){return _(t,e.v,e.w,e.name)}f.prototype._nodeCount=0,f.prototype._edgeCount=0},697:(t,e,r)=>{r.d(e,{T:()=>s.T});var s=r(37981)},75937:(t,e,r)=>{r.d(e,{A:()=>i});var s=r(72453),a=r(74886);const i=(t,e)=>s.A.lang.round(a.A.parse(t)[e])},50053:(t,e,r)=>{r.d(e,{A:()=>a});var s=r(68675);const a=function(t){return(0,s.A)(t,4)}},65410:(t,e,r)=>{r.d(e,{diagram:()=>fe});var s=r(47588),a=r(33115),i=r(10483),n=r(8159),o=r(10009),l=r(50053),c=r(75937),d=r(25582),h=r(20007),g=r(697),u=function(){var t=(0,o.K2)((function(t,e,r,s){for(r=r||{},s=t.length;s--;r[t[s]]=e);return r}),"o"),e=[1,7],r=[1,13],s=[1,14],a=[1,15],i=[1,19],n=[1,16],l=[1,17],c=[1,18],d=[8,30],h=[8,21,28,29,30,31,32,40,44,47],g=[1,23],u=[1,24],p=[8,15,16,21,28,29,30,31,32,40,44,47],y=[8,15,16,21,27,28,29,30,31,32,40,44,47],b=[1,49],x={trace:(0,o.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,spaceLines:3,SPACELINE:4,NL:5,separator:6,SPACE:7,EOF:8,start:9,BLOCK_DIAGRAM_KEY:10,document:11,stop:12,statement:13,link:14,LINK:15,START_LINK:16,LINK_LABEL:17,STR:18,nodeStatement:19,columnsStatement:20,SPACE_BLOCK:21,blockStatement:22,classDefStatement:23,cssClassStatement:24,styleStatement:25,node:26,SIZE:27,COLUMNS:28,"id-block":29,end:30,block:31,NODE_ID:32,nodeShapeNLabel:33,dirList:34,DIR:35,NODE_DSTART:36,NODE_DEND:37,BLOCK_ARROW_START:38,BLOCK_ARROW_END:39,classDef:40,CLASSDEF_ID:41,CLASSDEF_STYLEOPTS:42,DEFAULT:43,class:44,CLASSENTITY_IDS:45,STYLECLASS:46,style:47,STYLE_ENTITY_IDS:48,STYLE_DEFINITION_DATA:49,$accept:0,$end:1},terminals_:{2:"error",4:"SPACELINE",5:"NL",7:"SPACE",8:"EOF",10:"BLOCK_DIAGRAM_KEY",15:"LINK",16:"START_LINK",17:"LINK_LABEL",18:"STR",21:"SPACE_BLOCK",27:"SIZE",28:"COLUMNS",29:"id-block",30:"end",31:"block",32:"NODE_ID",35:"DIR",36:"NODE_DSTART",37:"NODE_DEND",38:"BLOCK_ARROW_START",39:"BLOCK_ARROW_END",40:"classDef",41:"CLASSDEF_ID",42:"CLASSDEF_STYLEOPTS",43:"DEFAULT",44:"class",45:"CLASSENTITY_IDS",46:"STYLECLASS",47:"style",48:"STYLE_ENTITY_IDS",49:"STYLE_DEFINITION_DATA"},productions_:[0,[3,1],[3,2],[3,2],[6,1],[6,1],[6,1],[9,3],[12,1],[12,1],[12,2],[12,2],[11,1],[11,2],[14,1],[14,4],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[19,3],[19,2],[19,1],[20,1],[22,4],[22,3],[26,1],[26,2],[34,1],[34,2],[33,3],[33,4],[23,3],[23,3],[24,3],[25,3]],performAction:(0,o.K2)((function(t,e,r,s,a,i,n){var o=i.length-1;switch(a){case 4:s.getLogger().debug("Rule: separator (NL) ");break;case 5:s.getLogger().debug("Rule: separator (Space) ");break;case 6:s.getLogger().debug("Rule: separator (EOF) ");break;case 7:s.getLogger().debug("Rule: hierarchy: ",i[o-1]),s.setHierarchy(i[o-1]);break;case 8:s.getLogger().debug("Stop NL ");break;case 9:s.getLogger().debug("Stop EOF ");break;case 10:s.getLogger().debug("Stop NL2 ");break;case 11:s.getLogger().debug("Stop EOF2 ");break;case 12:s.getLogger().debug("Rule: statement: ",i[o]),"number"==typeof i[o].length?this.$=i[o]:this.$=[i[o]];break;case 13:s.getLogger().debug("Rule: statement #2: ",i[o-1]),this.$=[i[o-1]].concat(i[o]);break;case 14:s.getLogger().debug("Rule: link: ",i[o],t),this.$={edgeTypeStr:i[o],label:""};break;case 15:s.getLogger().debug("Rule: LABEL link: ",i[o-3],i[o-1],i[o]),this.$={edgeTypeStr:i[o],label:i[o-1]};break;case 18:const e=parseInt(i[o]),r=s.generateId();this.$={id:r,type:"space",label:"",width:e,children:[]};break;case 23:s.getLogger().debug("Rule: (nodeStatement link node) ",i[o-2],i[o-1],i[o]," typestr: ",i[o-1].edgeTypeStr);const a=s.edgeStrToEdgeData(i[o-1].edgeTypeStr);this.$=[{id:i[o-2].id,label:i[o-2].label,type:i[o-2].type,directions:i[o-2].directions},{id:i[o-2].id+"-"+i[o].id,start:i[o-2].id,end:i[o].id,label:i[o-1].label,type:"edge",directions:i[o].directions,arrowTypeEnd:a,arrowTypeStart:"arrow_open"},{id:i[o].id,label:i[o].label,type:s.typeStr2Type(i[o].typeStr),directions:i[o].directions}];break;case 24:s.getLogger().debug("Rule: nodeStatement (abc88 node size) ",i[o-1],i[o]),this.$={id:i[o-1].id,label:i[o-1].label,type:s.typeStr2Type(i[o-1].typeStr),directions:i[o-1].directions,widthInColumns:parseInt(i[o],10)};break;case 25:s.getLogger().debug("Rule: nodeStatement (node) ",i[o]),this.$={id:i[o].id,label:i[o].label,type:s.typeStr2Type(i[o].typeStr),directions:i[o].directions,widthInColumns:1};break;case 26:s.getLogger().debug("APA123",this?this:"na"),s.getLogger().debug("COLUMNS: ",i[o]),this.$={type:"column-setting",columns:"auto"===i[o]?-1:parseInt(i[o])};break;case 27:s.getLogger().debug("Rule: id-block statement : ",i[o-2],i[o-1]);s.generateId();this.$={...i[o-2],type:"composite",children:i[o-1]};break;case 28:s.getLogger().debug("Rule: blockStatement : ",i[o-2],i[o-1],i[o]);const n=s.generateId();this.$={id:n,type:"composite",label:"",children:i[o-1]};break;case 29:s.getLogger().debug("Rule: node (NODE_ID separator): ",i[o]),this.$={id:i[o]};break;case 30:s.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel separator): ",i[o-1],i[o]),this.$={id:i[o-1],label:i[o].label,typeStr:i[o].typeStr,directions:i[o].directions};break;case 31:s.getLogger().debug("Rule: dirList: ",i[o]),this.$=[i[o]];break;case 32:s.getLogger().debug("Rule: dirList: ",i[o-1],i[o]),this.$=[i[o-1]].concat(i[o]);break;case 33:s.getLogger().debug("Rule: nodeShapeNLabel: ",i[o-2],i[o-1],i[o]),this.$={typeStr:i[o-2]+i[o],label:i[o-1]};break;case 34:s.getLogger().debug("Rule: BLOCK_ARROW nodeShapeNLabel: ",i[o-3],i[o-2]," #3:",i[o-1],i[o]),this.$={typeStr:i[o-3]+i[o],label:i[o-2],directions:i[o-1]};break;case 35:case 36:this.$={type:"classDef",id:i[o-1].trim(),css:i[o].trim()};break;case 37:this.$={type:"applyClass",id:i[o-1].trim(),styleClass:i[o].trim()};break;case 38:this.$={type:"applyStyles",id:i[o-1].trim(),stylesStr:i[o].trim()}}}),"anonymous"),table:[{9:1,10:[1,2]},{1:[3]},{11:3,13:4,19:5,20:6,21:e,22:8,23:9,24:10,25:11,26:12,28:r,29:s,31:a,32:i,40:n,44:l,47:c},{8:[1,20]},t(d,[2,12],{13:4,19:5,20:6,22:8,23:9,24:10,25:11,26:12,11:21,21:e,28:r,29:s,31:a,32:i,40:n,44:l,47:c}),t(h,[2,16],{14:22,15:g,16:u}),t(h,[2,17]),t(h,[2,18]),t(h,[2,19]),t(h,[2,20]),t(h,[2,21]),t(h,[2,22]),t(p,[2,25],{27:[1,25]}),t(h,[2,26]),{19:26,26:12,32:i},{11:27,13:4,19:5,20:6,21:e,22:8,23:9,24:10,25:11,26:12,28:r,29:s,31:a,32:i,40:n,44:l,47:c},{41:[1,28],43:[1,29]},{45:[1,30]},{48:[1,31]},t(y,[2,29],{33:32,36:[1,33],38:[1,34]}),{1:[2,7]},t(d,[2,13]),{26:35,32:i},{32:[2,14]},{17:[1,36]},t(p,[2,24]),{11:37,13:4,14:22,15:g,16:u,19:5,20:6,21:e,22:8,23:9,24:10,25:11,26:12,28:r,29:s,31:a,32:i,40:n,44:l,47:c},{30:[1,38]},{42:[1,39]},{42:[1,40]},{46:[1,41]},{49:[1,42]},t(y,[2,30]),{18:[1,43]},{18:[1,44]},t(p,[2,23]),{18:[1,45]},{30:[1,46]},t(h,[2,28]),t(h,[2,35]),t(h,[2,36]),t(h,[2,37]),t(h,[2,38]),{37:[1,47]},{34:48,35:b},{15:[1,50]},t(h,[2,27]),t(y,[2,33]),{39:[1,51]},{34:52,35:b,39:[2,31]},{32:[2,15]},t(y,[2,34]),{39:[2,32]}],defaultActions:{20:[2,7],23:[2,14],50:[2,15],52:[2,32]},parseError:(0,o.K2)((function(t,e){if(!e.recoverable){var r=new Error(t);throw r.hash=e,r}this.trace(t)}),"parseError"),parse:(0,o.K2)((function(t){var e=this,r=[0],s=[],a=[null],i=[],n=this.table,l="",c=0,d=0,h=0,g=i.slice.call(arguments,1),u=Object.create(this.lexer),p={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(p.yy[y]=this.yy[y]);u.setInput(t,p.yy),p.yy.lexer=u,p.yy.parser=this,void 0===u.yylloc&&(u.yylloc={});var b=u.yylloc;i.push(b);var x=u.options&&u.options.ranges;function f(){var t;return"number"!=typeof(t=s.pop()||u.lex()||1)&&(t instanceof Array&&(t=(s=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof p.yy.parseError?this.parseError=p.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,o.K2)((function(t){r.length=r.length-2*t,a.length=a.length-t,i.length=i.length-t}),"popStack"),(0,o.K2)(f,"lex");for(var m,w,_,L,k,S,v,E,D,C={};;){if(_=r[r.length-1],this.defaultActions[_]?L=this.defaultActions[_]:(null==m&&(m=f()),L=n[_]&&n[_][m]),void 0===L||!L.length||!L[0]){var R="";for(S in D=[],n[_])this.terminals_[S]&&S>2&&D.push("'"+this.terminals_[S]+"'");R=u.showPosition?"Parse error on line "+(c+1)+":\n"+u.showPosition()+"\nExpecting "+D.join(", ")+", got '"+(this.terminals_[m]||m)+"'":"Parse error on line "+(c+1)+": Unexpected "+(1==m?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(R,{text:u.match,token:this.terminals_[m]||m,line:u.yylineno,loc:b,expected:D})}if(L[0]instanceof Array&&L.length>1)throw new Error("Parse Error: multiple actions possible at state: "+_+", token: "+m);switch(L[0]){case 1:r.push(m),a.push(u.yytext),i.push(u.yylloc),r.push(L[1]),m=null,w?(m=w,w=null):(d=u.yyleng,l=u.yytext,c=u.yylineno,b=u.yylloc,h>0&&h--);break;case 2:if(v=this.productions_[L[1]][1],C.$=a[a.length-v],C._$={first_line:i[i.length-(v||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(v||1)].first_column,last_column:i[i.length-1].last_column},x&&(C._$.range=[i[i.length-(v||1)].range[0],i[i.length-1].range[1]]),void 0!==(k=this.performAction.apply(C,[l,d,c,p.yy,L[1],a,i].concat(g))))return k;v&&(r=r.slice(0,-1*v*2),a=a.slice(0,-1*v),i=i.slice(0,-1*v)),r.push(this.productions_[L[1]][0]),a.push(C.$),i.push(C._$),E=n[r[r.length-2]][r[r.length-1]],r.push(E);break;case 3:return!0}}return!0}),"parse")},f=function(){return{EOF:1,parseError:(0,o.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,o.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,o.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,o.K2)((function(t){var e=t.length,r=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var s=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),r.length-1&&(this.yylineno-=r.length-1);var a=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:r?(r.length===s.length?this.yylloc.first_column:0)+s[s.length-r.length].length-r[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[a[0],a[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,o.K2)((function(){return this._more=!0,this}),"more"),reject:(0,o.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,o.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,o.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,o.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,o.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,o.K2)((function(t,e){var r,s,a;if(this.options.backtrack_lexer&&(a={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(a.yylloc.range=this.yylloc.range.slice(0))),(s=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=s.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:s?s[s.length-1].length-s[s.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],r=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),r)return r;if(this._backtrack){for(var i in a)this[i]=a[i];return!1}return!1}),"test_match"),next:(0,o.K2)((function(){if(this.done)return this.EOF;var t,e,r,s;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var a=this._currentRules(),i=0;i<a.length;i++)if((r=this._input.match(this.rules[a[i]]))&&(!e||r[0].length>e[0].length)){if(e=r,s=i,this.options.backtrack_lexer){if(!1!==(t=this.test_match(r,a[i])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,a[s]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,o.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,o.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,o.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,o.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,o.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,o.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,o.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{},performAction:(0,o.K2)((function(t,e,r,s){switch(r){case 0:return 10;case 1:return t.getLogger().debug("Found space-block"),31;case 2:return t.getLogger().debug("Found nl-block"),31;case 3:return t.getLogger().debug("Found space-block"),29;case 4:t.getLogger().debug(".",e.yytext);break;case 5:t.getLogger().debug("_",e.yytext);break;case 6:return 5;case 7:return e.yytext=-1,28;case 8:return e.yytext=e.yytext.replace(/columns\s+/,""),t.getLogger().debug("COLUMNS (LEX)",e.yytext),28;case 9:case 77:case 78:case 100:this.pushState("md_string");break;case 10:return"MD_STR";case 11:case 35:case 80:this.popState();break;case 12:this.pushState("string");break;case 13:t.getLogger().debug("LEX: POPPING STR:",e.yytext),this.popState();break;case 14:return t.getLogger().debug("LEX: STR end:",e.yytext),"STR";case 15:return e.yytext=e.yytext.replace(/space\:/,""),t.getLogger().debug("SPACE NUM (LEX)",e.yytext),21;case 16:return e.yytext="1",t.getLogger().debug("COLUMNS (LEX)",e.yytext),21;case 17:return 43;case 18:return"LINKSTYLE";case 19:return"INTERPOLATE";case 20:return this.pushState("CLASSDEF"),40;case 21:return this.popState(),this.pushState("CLASSDEFID"),"DEFAULT_CLASSDEF_ID";case 22:return this.popState(),this.pushState("CLASSDEFID"),41;case 23:return this.popState(),42;case 24:return this.pushState("CLASS"),44;case 25:return this.popState(),this.pushState("CLASS_STYLE"),45;case 26:return this.popState(),46;case 27:return this.pushState("STYLE_STMNT"),47;case 28:return this.popState(),this.pushState("STYLE_DEFINITION"),48;case 29:return this.popState(),49;case 30:return this.pushState("acc_title"),"acc_title";case 31:return this.popState(),"acc_title_value";case 32:return this.pushState("acc_descr"),"acc_descr";case 33:return this.popState(),"acc_descr_value";case 34:this.pushState("acc_descr_multiline");break;case 36:return"acc_descr_multiline_value";case 37:return 30;case 38:case 39:case 41:case 42:case 45:return this.popState(),t.getLogger().debug("Lex: (("),"NODE_DEND";case 40:return this.popState(),t.getLogger().debug("Lex: ))"),"NODE_DEND";case 43:return this.popState(),t.getLogger().debug("Lex: (-"),"NODE_DEND";case 44:return this.popState(),t.getLogger().debug("Lex: -)"),"NODE_DEND";case 46:return this.popState(),t.getLogger().debug("Lex: ]]"),"NODE_DEND";case 47:return this.popState(),t.getLogger().debug("Lex: ("),"NODE_DEND";case 48:return this.popState(),t.getLogger().debug("Lex: ])"),"NODE_DEND";case 49:case 50:return this.popState(),t.getLogger().debug("Lex: /]"),"NODE_DEND";case 51:return this.popState(),t.getLogger().debug("Lex: )]"),"NODE_DEND";case 52:return this.popState(),t.getLogger().debug("Lex: )"),"NODE_DEND";case 53:return this.popState(),t.getLogger().debug("Lex: ]>"),"NODE_DEND";case 54:return this.popState(),t.getLogger().debug("Lex: ]"),"NODE_DEND";case 55:return t.getLogger().debug("Lexa: -)"),this.pushState("NODE"),36;case 56:return t.getLogger().debug("Lexa: (-"),this.pushState("NODE"),36;case 57:return t.getLogger().debug("Lexa: ))"),this.pushState("NODE"),36;case 58:case 60:case 61:case 62:case 65:return t.getLogger().debug("Lexa: )"),this.pushState("NODE"),36;case 59:return t.getLogger().debug("Lex: ((("),this.pushState("NODE"),36;case 63:return t.getLogger().debug("Lexc: >"),this.pushState("NODE"),36;case 64:return t.getLogger().debug("Lexa: (["),this.pushState("NODE"),36;case 66:case 67:case 68:case 69:case 70:case 71:case 72:return this.pushState("NODE"),36;case 73:return t.getLogger().debug("Lexa: ["),this.pushState("NODE"),36;case 74:return this.pushState("BLOCK_ARROW"),t.getLogger().debug("LEX ARR START"),38;case 75:return t.getLogger().debug("Lex: NODE_ID",e.yytext),32;case 76:return t.getLogger().debug("Lex: EOF",e.yytext),8;case 79:return"NODE_DESCR";case 81:t.getLogger().debug("Lex: Starting string"),this.pushState("string");break;case 82:t.getLogger().debug("LEX ARR: Starting string"),this.pushState("string");break;case 83:return t.getLogger().debug("LEX: NODE_DESCR:",e.yytext),"NODE_DESCR";case 84:t.getLogger().debug("LEX POPPING"),this.popState();break;case 85:t.getLogger().debug("Lex: =>BAE"),this.pushState("ARROW_DIR");break;case 86:return e.yytext=e.yytext.replace(/^,\s*/,""),t.getLogger().debug("Lex (right): dir:",e.yytext),"DIR";case 87:return e.yytext=e.yytext.replace(/^,\s*/,""),t.getLogger().debug("Lex (left):",e.yytext),"DIR";case 88:return e.yytext=e.yytext.replace(/^,\s*/,""),t.getLogger().debug("Lex (x):",e.yytext),"DIR";case 89:return e.yytext=e.yytext.replace(/^,\s*/,""),t.getLogger().debug("Lex (y):",e.yytext),"DIR";case 90:return e.yytext=e.yytext.replace(/^,\s*/,""),t.getLogger().debug("Lex (up):",e.yytext),"DIR";case 91:return e.yytext=e.yytext.replace(/^,\s*/,""),t.getLogger().debug("Lex (down):",e.yytext),"DIR";case 92:return e.yytext="]>",t.getLogger().debug("Lex (ARROW_DIR end):",e.yytext),this.popState(),this.popState(),"BLOCK_ARROW_END";case 93:return t.getLogger().debug("Lex: LINK","#"+e.yytext+"#"),15;case 94:case 95:case 96:return t.getLogger().debug("Lex: LINK",e.yytext),15;case 97:case 98:case 99:return t.getLogger().debug("Lex: START_LINK",e.yytext),this.pushState("LLABEL"),16;case 101:return t.getLogger().debug("Lex: Starting string"),this.pushState("string"),"LINK_LABEL";case 102:return this.popState(),t.getLogger().debug("Lex: LINK","#"+e.yytext+"#"),15;case 103:case 104:return this.popState(),t.getLogger().debug("Lex: LINK",e.yytext),15;case 105:return t.getLogger().debug("Lex: COLON",e.yytext),e.yytext=e.yytext.slice(1),27}}),"anonymous"),rules:[/^(?:block-beta\b)/,/^(?:block\s+)/,/^(?:block\n+)/,/^(?:block:)/,/^(?:[\s]+)/,/^(?:[\n]+)/,/^(?:((\u000D\u000A)|(\u000A)))/,/^(?:columns\s+auto\b)/,/^(?:columns\s+[\d]+)/,/^(?:["][`])/,/^(?:[^`"]+)/,/^(?:[`]["])/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:space[:]\d+)/,/^(?:space\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\s+)/,/^(?:DEFAULT\s+)/,/^(?:\w+\s+)/,/^(?:[^\n]*)/,/^(?:class\s+)/,/^(?:(\w+)+((,\s*\w+)*))/,/^(?:[^\n]*)/,/^(?:style\s+)/,/^(?:(\w+)+((,\s*\w+)*))/,/^(?:[^\n]*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:end\b\s*)/,/^(?:\(\(\()/,/^(?:\)\)\))/,/^(?:[\)]\))/,/^(?:\}\})/,/^(?:\})/,/^(?:\(-)/,/^(?:-\))/,/^(?:\(\()/,/^(?:\]\])/,/^(?:\()/,/^(?:\]\))/,/^(?:\\\])/,/^(?:\/\])/,/^(?:\)\])/,/^(?:[\)])/,/^(?:\]>)/,/^(?:[\]])/,/^(?:-\))/,/^(?:\(-)/,/^(?:\)\))/,/^(?:\))/,/^(?:\(\(\()/,/^(?:\(\()/,/^(?:\{\{)/,/^(?:\{)/,/^(?:>)/,/^(?:\(\[)/,/^(?:\()/,/^(?:\[\[)/,/^(?:\[\|)/,/^(?:\[\()/,/^(?:\)\)\))/,/^(?:\[\\)/,/^(?:\[\/)/,/^(?:\[\\)/,/^(?:\[)/,/^(?:<\[)/,/^(?:[^\(\[\n\-\)\{\}\s\<\>:]+)/,/^(?:$)/,/^(?:["][`])/,/^(?:["][`])/,/^(?:[^`"]+)/,/^(?:[`]["])/,/^(?:["])/,/^(?:["])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:\]>\s*\()/,/^(?:,?\s*right\s*)/,/^(?:,?\s*left\s*)/,/^(?:,?\s*x\s*)/,/^(?:,?\s*y\s*)/,/^(?:,?\s*up\s*)/,/^(?:,?\s*down\s*)/,/^(?:\)\s*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*~~[\~]+\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:["][`])/,/^(?:["])/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?::\d+)/],conditions:{STYLE_DEFINITION:{rules:[29],inclusive:!1},STYLE_STMNT:{rules:[28],inclusive:!1},CLASSDEFID:{rules:[23],inclusive:!1},CLASSDEF:{rules:[21,22],inclusive:!1},CLASS_STYLE:{rules:[26],inclusive:!1},CLASS:{rules:[25],inclusive:!1},LLABEL:{rules:[100,101,102,103,104],inclusive:!1},ARROW_DIR:{rules:[86,87,88,89,90,91,92],inclusive:!1},BLOCK_ARROW:{rules:[77,82,85],inclusive:!1},NODE:{rules:[38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,78,81],inclusive:!1},md_string:{rules:[10,11,79,80],inclusive:!1},space:{rules:[],inclusive:!1},string:{rules:[13,14,83,84],inclusive:!1},acc_descr_multiline:{rules:[35,36],inclusive:!1},acc_descr:{rules:[33],inclusive:!1},acc_title:{rules:[31],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,12,15,16,17,18,19,20,24,27,30,32,34,37,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,93,94,95,96,97,98,99,105],inclusive:!0}}}}();function m(){this.yy={}}return x.lexer=f,(0,o.K2)(m,"Parser"),m.prototype=x,x.Parser=m,new m}();u.parser=u;var p=u,y=new Map,b=[],x=new Map,f="color",m="fill",w=(0,o.D7)(),_=new Map,L=(0,o.K2)((t=>o.Y2.sanitizeText(t,w)),"sanitizeText"),k=(0,o.K2)((function(t,e=""){let r=_.get(t);r||(r={id:t,styles:[],textStyles:[]},_.set(t,r)),null!=e&&e.split(",").forEach((t=>{const e=t.replace(/([^;]*);/,"$1").trim();if(RegExp(f).exec(t)){const t=e.replace(m,"bgFill").replace(f,m);r.textStyles.push(t)}r.styles.push(e)}))}),"addStyleClass"),S=(0,o.K2)((function(t,e=""){const r=y.get(t);null!=e&&(r.styles=e.split(","))}),"addStyle2Node"),v=(0,o.K2)((function(t,e){t.split(",").forEach((function(t){let r=y.get(t);if(void 0===r){const e=t.trim();r={id:e,type:"na",children:[]},y.set(e,r)}r.classes||(r.classes=[]),r.classes.push(e)}))}),"setCssClass"),E=(0,o.K2)(((t,e)=>{const r=t.flat(),s=[];for(const a of r)if(a.label&&(a.label=L(a.label)),"classDef"!==a.type)if("applyClass"!==a.type)if("applyStyles"!==a.type)if("column-setting"===a.type)e.columns=a.columns??-1;else if("edge"===a.type){const t=(x.get(a.id)??0)+1;x.set(a.id,t),a.id=t+"-"+a.id,b.push(a)}else{a.label||("composite"===a.type?a.label="":a.label=a.id);const t=y.get(a.id);if(void 0===t?y.set(a.id,a):("na"!==a.type&&(t.type=a.type),a.label!==a.id&&(t.label=a.label)),a.children&&E(a.children,a),"space"===a.type){const t=a.width??1;for(let e=0;e<t;e++){const t=(0,l.A)(a);t.id=t.id+"-"+e,y.set(t.id,t),s.push(t)}}else void 0===t&&s.push(a)}else a?.stylesStr&&S(a.id,a?.stylesStr);else v(a.id,a?.styleClass??"");else k(a.id,a.css);e.children=s}),"populateBlockDatabase"),D=[],C={id:"root",type:"composite",children:[],columns:-1},R=(0,o.K2)((()=>{o.Rm.debug("Clear called"),(0,o.IU)(),C={id:"root",type:"composite",children:[],columns:-1},y=new Map([["root",C]]),D=[],_=new Map,b=[],x=new Map}),"clear");function K(t){switch(o.Rm.debug("typeStr2Type",t),t){case"[]":return"square";case"()":return o.Rm.debug("we have a round"),"round";case"(())":return"circle";case">]":return"rect_left_inv_arrow";case"{}":return"diamond";case"{{}}":return"hexagon";case"([])":return"stadium";case"[[]]":return"subroutine";case"[()]":return"cylinder";case"((()))":return"doublecircle";case"[//]":return"lean_right";case"[\\\\]":return"lean_left";case"[/\\]":return"trapezoid";case"[\\/]":return"inv_trapezoid";case"<[]>":return"block_arrow";default:return"na"}}function N(t){return o.Rm.debug("typeStr2Type",t),"=="===t?"thick":"normal"}function T(t){switch(t.trim()){case"--x":return"arrow_cross";case"--o":return"arrow_circle";default:return"arrow_point"}}(0,o.K2)(K,"typeStr2Type"),(0,o.K2)(N,"edgeTypeStr2Type"),(0,o.K2)(T,"edgeStrToEdgeData");var $=0,A=(0,o.K2)((()=>($++,"id-"+Math.random().toString(36).substr(2,12)+"-"+$)),"generateId"),I=(0,o.K2)((t=>{C.children=t,E(t,C),D=C.children}),"setHierarchy"),O=(0,o.K2)((t=>{const e=y.get(t);return e?e.columns?e.columns:e.children?e.children.length:-1:-1}),"getColumns"),B=(0,o.K2)((()=>[...y.values()]),"getBlocksFlat"),z=(0,o.K2)((()=>D||[]),"getBlocks"),M=(0,o.K2)((()=>b),"getEdges"),P=(0,o.K2)((t=>y.get(t)),"getBlock"),Y=(0,o.K2)((t=>{y.set(t.id,t)}),"setBlock"),F=(0,o.K2)((()=>console),"getLogger"),j=(0,o.K2)((function(){return _}),"getClasses"),W={getConfig:(0,o.K2)((()=>(0,o.zj)().block),"getConfig"),typeStr2Type:K,edgeTypeStr2Type:N,edgeStrToEdgeData:T,getLogger:F,getBlocksFlat:B,getBlocks:z,getEdges:M,setHierarchy:I,getBlock:P,setBlock:Y,getColumns:O,getClasses:j,clear:R,generateId:A},X=(0,o.K2)(((t,e)=>{const r=c.A,s=r(t,"r"),a=r(t,"g"),i=r(t,"b");return d.A(s,a,i,e)}),"fade"),H=(0,o.K2)((t=>`.label {\n font-family: ${t.fontFamily};\n color: ${t.nodeTextColor||t.textColor};\n }\n .cluster-label text {\n fill: ${t.titleColor};\n }\n .cluster-label span,p {\n color: ${t.titleColor};\n }\n\n\n\n .label text,span,p {\n fill: ${t.nodeTextColor||t.textColor};\n color: ${t.nodeTextColor||t.textColor};\n }\n\n .node rect,\n .node circle,\n .node ellipse,\n .node polygon,\n .node path {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n stroke-width: 1px;\n }\n .flowchart-label text {\n text-anchor: middle;\n }\n // .flowchart-label .text-outer-tspan {\n // text-anchor: middle;\n // }\n // .flowchart-label .text-inner-tspan {\n // text-anchor: start;\n // }\n\n .node .label {\n text-align: center;\n }\n .node.clickable {\n cursor: pointer;\n }\n\n .arrowheadPath {\n fill: ${t.arrowheadColor};\n }\n\n .edgePath .path {\n stroke: ${t.lineColor};\n stroke-width: 2.0px;\n }\n\n .flowchart-link {\n stroke: ${t.lineColor};\n fill: none;\n }\n\n .edgeLabel {\n background-color: ${t.edgeLabelBackground};\n rect {\n opacity: 0.5;\n background-color: ${t.edgeLabelBackground};\n fill: ${t.edgeLabelBackground};\n }\n text-align: center;\n }\n\n /* For html labels only */\n .labelBkg {\n background-color: ${X(t.edgeLabelBackground,.5)};\n // background-color:\n }\n\n .node .cluster {\n // fill: ${X(t.mainBkg,.5)};\n fill: ${X(t.clusterBkg,.5)};\n stroke: ${X(t.clusterBorder,.2)};\n box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;\n stroke-width: 1px;\n }\n\n .cluster text {\n fill: ${t.titleColor};\n }\n\n .cluster span,p {\n color: ${t.titleColor};\n }\n /* .cluster div {\n color: ${t.titleColor};\n } */\n\n div.mermaidTooltip {\n position: absolute;\n text-align: center;\n max-width: 200px;\n padding: 2px;\n font-family: ${t.fontFamily};\n font-size: 12px;\n background: ${t.tertiaryColor};\n border: 1px solid ${t.border2};\n border-radius: 2px;\n pointer-events: none;\n z-index: 100;\n }\n\n .flowchartTitleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.textColor};\n }\n`),"getStyles"),U=(0,o.K2)(((t,e,r,s)=>{e.forEach((e=>{Z[e](t,r,s)}))}),"insertMarkers"),Z={extension:(0,o.K2)(((t,e,r)=>{o.Rm.trace("Making markers for ",r),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionStart").attr("class","marker extension "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 1,7 L18,13 V 1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-extensionEnd").attr("class","marker extension "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 1,1 V 13 L18,7 Z")}),"extension"),composition:(0,o.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionStart").attr("class","marker composition "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-compositionEnd").attr("class","marker composition "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")}),"composition"),aggregation:(0,o.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationStart").attr("class","marker aggregation "+e).attr("refX",18).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-aggregationEnd").attr("class","marker aggregation "+e).attr("refX",1).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z")}),"aggregation"),dependency:(0,o.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyStart").attr("class","marker dependency "+e).attr("refX",6).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 5,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",r+"_"+e+"-dependencyEnd").attr("class","marker dependency "+e).attr("refX",13).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")}),"dependency"),lollipop:(0,o.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopStart").attr("class","marker lollipop "+e).attr("refX",13).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6),t.append("defs").append("marker").attr("id",r+"_"+e+"-lollipopEnd").attr("class","marker lollipop "+e).attr("refX",1).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("circle").attr("stroke","black").attr("fill","transparent").attr("cx",7).attr("cy",7).attr("r",6)}),"lollipop"),point:(0,o.K2)(((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-pointEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",6).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-pointStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",4.5).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto").append("path").attr("d","M 0 5 L 10 10 L 10 0 z").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")}),"point"),circle:(0,o.K2)(((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-circleEnd").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",11).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-circleStart").attr("class","marker "+e).attr("viewBox","0 0 10 10").attr("refX",-1).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("circle").attr("cx","5").attr("cy","5").attr("r","5").attr("class","arrowMarkerPath").style("stroke-width",1).style("stroke-dasharray","1,0")}),"circle"),cross:(0,o.K2)(((t,e,r)=>{t.append("marker").attr("id",r+"_"+e+"-crossEnd").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",12).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0"),t.append("marker").attr("id",r+"_"+e+"-crossStart").attr("class","marker cross "+e).attr("viewBox","0 0 11 11").attr("refX",-1).attr("refY",5.2).attr("markerUnits","userSpaceOnUse").attr("markerWidth",11).attr("markerHeight",11).attr("orient","auto").append("path").attr("d","M 1,1 l 9,9 M 10,1 l -9,9").attr("class","arrowMarkerPath").style("stroke-width",2).style("stroke-dasharray","1,0")}),"cross"),barb:(0,o.K2)(((t,e,r)=>{t.append("defs").append("marker").attr("id",r+"_"+e+"-barbEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",14).attr("markerUnits","strokeWidth").attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")}),"barb")},q=U,G=(0,o.D7)()?.block?.padding??8;function J(t,e){if(0===t||!Number.isInteger(t))throw new Error("Columns must be an integer !== 0.");if(e<0||!Number.isInteger(e))throw new Error("Position must be a non-negative integer."+e);if(t<0)return{px:e,py:0};if(1===t)return{px:0,py:e};return{px:e%t,py:Math.floor(e/t)}}(0,o.K2)(J,"calculateBlockPosition");var V=(0,o.K2)((t=>{let e=0,r=0;for(const s of t.children){const{width:a,height:i,x:n,y:l}=s.size??{width:0,height:0,x:0,y:0};o.Rm.debug("getMaxChildSize abc95 child:",s.id,"width:",a,"height:",i,"x:",n,"y:",l,s.type),"space"!==s.type&&(a>e&&(e=a/(t.widthInColumns??1)),i>r&&(r=i))}return{width:e,height:r}}),"getMaxChildSize");function Q(t,e,r=0,s=0){o.Rm.debug("setBlockSizes abc95 (start)",t.id,t?.size?.x,"block width =",t?.size,"sieblingWidth",r),t?.size?.width||(t.size={width:r,height:s,x:0,y:0});let a=0,i=0;if(t.children?.length>0){for(const r of t.children)Q(r,e);const n=V(t);a=n.width,i=n.height,o.Rm.debug("setBlockSizes abc95 maxWidth of",t.id,":s children is ",a,i);for(const e of t.children)e.size&&(o.Rm.debug(`abc95 Setting size of children of ${t.id} id=${e.id} ${a} ${i} ${JSON.stringify(e.size)}`),e.size.width=a*(e.widthInColumns??1)+G*((e.widthInColumns??1)-1),e.size.height=i,e.size.x=0,e.size.y=0,o.Rm.debug(`abc95 updating size of ${t.id} children child:${e.id} maxWidth:${a} maxHeight:${i}`));for(const r of t.children)Q(r,e,a,i);const l=t.columns??-1;let c=0;for(const e of t.children)c+=e.widthInColumns??1;let d=t.children.length;l>0&&l<c&&(d=l);const h=Math.ceil(c/d);let g=d*(a+G)+G,u=h*(i+G)+G;if(g<r){o.Rm.debug(`Detected to small siebling: abc95 ${t.id} sieblingWidth ${r} sieblingHeight ${s} width ${g}`),g=r,u=s;const e=(r-d*G-G)/d,n=(s-h*G-G)/h;o.Rm.debug("Size indata abc88",t.id,"childWidth",e,"maxWidth",a),o.Rm.debug("Size indata abc88",t.id,"childHeight",n,"maxHeight",i),o.Rm.debug("Size indata abc88 xSize",d,"padding",G);for(const r of t.children)r.size&&(r.size.width=e,r.size.height=n,r.size.x=0,r.size.y=0)}if(o.Rm.debug(`abc95 (finale calc) ${t.id} xSize ${d} ySize ${h} columns ${l}${t.children.length} width=${Math.max(g,t.size?.width||0)}`),g<(t?.size?.width||0)){g=t?.size?.width||0;const e=l>0?Math.min(t.children.length,l):t.children.length;if(e>0){const r=(g-e*G-G)/e;o.Rm.debug("abc95 (growing to fit) width",t.id,g,t.size?.width,r);for(const e of t.children)e.size&&(e.size.width=r)}}t.size={width:g,height:u,x:0,y:0}}o.Rm.debug("setBlockSizes abc94 (done)",t.id,t?.size?.x,t?.size?.width,t?.size?.y,t?.size?.height)}function tt(t,e){o.Rm.debug(`abc85 layout blocks (=>layoutBlocks) ${t.id} x: ${t?.size?.x} y: ${t?.size?.y} width: ${t?.size?.width}`);const r=t.columns??-1;if(o.Rm.debug("layoutBlocks columns abc95",t.id,"=>",r,t),t.children&&t.children.length>0){const s=t?.children[0]?.size?.width??0,a=t.children.length*s+(t.children.length-1)*G;o.Rm.debug("widthOfChildren 88",a,"posX");let i=0;o.Rm.debug("abc91 block?.size?.x",t.id,t?.size?.x);let n=t?.size?.x?t?.size?.x+(-t?.size?.width/2||0):-G,l=0;for(const c of t.children){const s=t;if(!c.size)continue;const{width:a,height:d}=c.size,{px:h,py:g}=J(r,i);if(g!=l&&(l=g,n=t?.size?.x?t?.size?.x+(-t?.size?.width/2||0):-G,o.Rm.debug("New row in layout for block",t.id," and child ",c.id,l)),o.Rm.debug(`abc89 layout blocks (child) id: ${c.id} Pos: ${i} (px, py) ${h},${g} (${s?.size?.x},${s?.size?.y}) parent: ${s.id} width: ${a}${G}`),s.size){const t=a/2;c.size.x=n+G+t,o.Rm.debug(`abc91 layout blocks (calc) px, pyid:${c.id} startingPos=X${n} new startingPosX${c.size.x} ${t} padding=${G} width=${a} halfWidth=${t} => x:${c.size.x} y:${c.size.y} ${c.widthInColumns} (width * (child?.w || 1)) / 2 ${a*(c?.widthInColumns??1)/2}`),n=c.size.x+t,c.size.y=s.size.y-s.size.height/2+g*(d+G)+d/2+G,o.Rm.debug(`abc88 layout blocks (calc) px, pyid:${c.id}startingPosX${n}${G}${t}=>x:${c.size.x}y:${c.size.y}${c.widthInColumns}(width * (child?.w || 1)) / 2${a*(c?.widthInColumns??1)/2}`)}c.children&&tt(c,e),i+=c?.widthInColumns??1,o.Rm.debug("abc88 columnsPos",c,i)}}o.Rm.debug(`layout blocks (<==layoutBlocks) ${t.id} x: ${t?.size?.x} y: ${t?.size?.y} width: ${t?.size?.width}`)}function et(t,{minX:e,minY:r,maxX:s,maxY:a}={minX:0,minY:0,maxX:0,maxY:0}){if(t.size&&"root"!==t.id){const{x:i,y:n,width:o,height:l}=t.size;i-o/2<e&&(e=i-o/2),n-l/2<r&&(r=n-l/2),i+o/2>s&&(s=i+o/2),n+l/2>a&&(a=n+l/2)}if(t.children)for(const i of t.children)({minX:e,minY:r,maxX:s,maxY:a}=et(i,{minX:e,minY:r,maxX:s,maxY:a}));return{minX:e,minY:r,maxX:s,maxY:a}}function rt(t){const e=t.getBlock("root");if(!e)return;Q(e,t,0,0),tt(e,t),o.Rm.debug("getBlocks",JSON.stringify(e,null,2));const{minX:r,minY:s,maxX:a,maxY:i}=et(e);return{x:r,y:s,width:a-r,height:i-s}}function st(t,e){e&&t.attr("style",e)}function at(t){const e=(0,h.Ltv)(document.createElementNS("http://www.w3.org/2000/svg","foreignObject")),r=e.append("xhtml:div"),s=t.label,a=t.isNode?"nodeLabel":"edgeLabel",i=r.append("span");return i.html(s),st(i,t.labelStyle),i.attr("class",a),st(r,t.labelStyle),r.style("display","inline-block"),r.style("white-space","nowrap"),r.attr("xmlns","http://www.w3.org/1999/xhtml"),e.node()}(0,o.K2)(Q,"setBlockSizes"),(0,o.K2)(tt,"layoutBlocks"),(0,o.K2)(et,"findBounds"),(0,o.K2)(rt,"layout"),(0,o.K2)(st,"applyStyle"),(0,o.K2)(at,"addHtmlLabel");var it=(0,o.K2)(((t,e,r,s)=>{let a=t||"";if("object"==typeof a&&(a=a[0]),(0,o._3)((0,o.D7)().flowchart.htmlLabels)){a=a.replace(/\\n|\n/g,"<br />"),o.Rm.debug("vertexText"+a);return at({isNode:s,label:(0,i.hE)((0,n.Sm)(a)),labelStyle:e.replace("fill:","color:")})}{const t=document.createElementNS("http://www.w3.org/2000/svg","text");t.setAttribute("style",e.replace("color:","fill:"));let s=[];s="string"==typeof a?a.split(/\\n|\n|<br\s*\/?>/gi):Array.isArray(a)?a:[];for(const e of s){const s=document.createElementNS("http://www.w3.org/2000/svg","tspan");s.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),s.setAttribute("dy","1em"),s.setAttribute("x","0"),r?s.setAttribute("class","title-row"):s.setAttribute("class","row"),s.textContent=e.trim(),t.appendChild(s)}return t}}),"createLabel"),nt=(0,o.K2)(((t,e,r,s,a)=>{e.arrowTypeStart&<(t,"start",e.arrowTypeStart,r,s,a),e.arrowTypeEnd&<(t,"end",e.arrowTypeEnd,r,s,a)}),"addEdgeMarkers"),ot={arrow_cross:"cross",arrow_point:"point",arrow_barb:"barb",arrow_circle:"circle",aggregation:"aggregation",extension:"extension",composition:"composition",dependency:"dependency",lollipop:"lollipop"},lt=(0,o.K2)(((t,e,r,s,a,i)=>{const n=ot[r];if(!n)return void o.Rm.warn(`Unknown arrow type: ${r}`);const l="start"===e?"Start":"End";t.attr(`marker-${e}`,`url(${s}#${a}_${i}-${n}${l})`)}),"addEdgeMarker"),ct={},dt={},ht=(0,o.K2)(((t,e)=>{const r=(0,o.D7)(),s=(0,o._3)(r.flowchart.htmlLabels),a="markdown"===e.labelType?(0,i.GZ)(t,e.label,{style:e.labelStyle,useHtmlLabels:s,addSvgBackground:!0},r):it(e.label,e.labelStyle),n=t.insert("g").attr("class","edgeLabel"),l=n.insert("g").attr("class","label");l.node().appendChild(a);let c,d=a.getBBox();if(s){const t=a.children[0],e=(0,h.Ltv)(a);d=t.getBoundingClientRect(),e.attr("width",d.width),e.attr("height",d.height)}if(l.attr("transform","translate("+-d.width/2+", "+-d.height/2+")"),ct[e.id]=n,e.width=d.width,e.height=d.height,e.startLabelLeft){const r=it(e.startLabelLeft,e.labelStyle),s=t.insert("g").attr("class","edgeTerminals"),a=s.insert("g").attr("class","inner");c=a.node().appendChild(r);const i=r.getBBox();a.attr("transform","translate("+-i.width/2+", "+-i.height/2+")"),dt[e.id]||(dt[e.id]={}),dt[e.id].startLeft=s,gt(c,e.startLabelLeft)}if(e.startLabelRight){const r=it(e.startLabelRight,e.labelStyle),s=t.insert("g").attr("class","edgeTerminals"),a=s.insert("g").attr("class","inner");c=s.node().appendChild(r),a.node().appendChild(r);const i=r.getBBox();a.attr("transform","translate("+-i.width/2+", "+-i.height/2+")"),dt[e.id]||(dt[e.id]={}),dt[e.id].startRight=s,gt(c,e.startLabelRight)}if(e.endLabelLeft){const r=it(e.endLabelLeft,e.labelStyle),s=t.insert("g").attr("class","edgeTerminals"),a=s.insert("g").attr("class","inner");c=a.node().appendChild(r);const i=r.getBBox();a.attr("transform","translate("+-i.width/2+", "+-i.height/2+")"),s.node().appendChild(r),dt[e.id]||(dt[e.id]={}),dt[e.id].endLeft=s,gt(c,e.endLabelLeft)}if(e.endLabelRight){const r=it(e.endLabelRight,e.labelStyle),s=t.insert("g").attr("class","edgeTerminals"),a=s.insert("g").attr("class","inner");c=a.node().appendChild(r);const i=r.getBBox();a.attr("transform","translate("+-i.width/2+", "+-i.height/2+")"),s.node().appendChild(r),dt[e.id]||(dt[e.id]={}),dt[e.id].endRight=s,gt(c,e.endLabelRight)}return a}),"insertEdgeLabel");function gt(t,e){(0,o.D7)().flowchart.htmlLabels&&t&&(t.style.width=9*e.length+"px",t.style.height="12px")}(0,o.K2)(gt,"setTerminalWidth");var ut=(0,o.K2)(((t,e)=>{o.Rm.debug("Moving label abc88 ",t.id,t.label,ct[t.id],e);let r=e.updatedPath?e.updatedPath:e.originalPath;const s=(0,o.D7)(),{subGraphTitleTotalMargin:i}=(0,a.O)(s);if(t.label){const s=ct[t.id];let a=t.x,l=t.y;if(r){const s=n._K.calcLabelPosition(r);o.Rm.debug("Moving label "+t.label+" from (",a,",",l,") to (",s.x,",",s.y,") abc88"),e.updatedPath&&(a=s.x,l=s.y)}s.attr("transform",`translate(${a}, ${l+i/2})`)}if(t.startLabelLeft){const e=dt[t.id].startLeft;let s=t.x,a=t.y;if(r){const e=n._K.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_left",r);s=e.x,a=e.y}e.attr("transform",`translate(${s}, ${a})`)}if(t.startLabelRight){const e=dt[t.id].startRight;let s=t.x,a=t.y;if(r){const e=n._K.calcTerminalLabelPosition(t.arrowTypeStart?10:0,"start_right",r);s=e.x,a=e.y}e.attr("transform",`translate(${s}, ${a})`)}if(t.endLabelLeft){const e=dt[t.id].endLeft;let s=t.x,a=t.y;if(r){const e=n._K.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_left",r);s=e.x,a=e.y}e.attr("transform",`translate(${s}, ${a})`)}if(t.endLabelRight){const e=dt[t.id].endRight;let s=t.x,a=t.y;if(r){const e=n._K.calcTerminalLabelPosition(t.arrowTypeEnd?10:0,"end_right",r);s=e.x,a=e.y}e.attr("transform",`translate(${s}, ${a})`)}}),"positionEdgeLabel"),pt=(0,o.K2)(((t,e)=>{const r=t.x,s=t.y,a=Math.abs(e.x-r),i=Math.abs(e.y-s),n=t.width/2,o=t.height/2;return a>=n||i>=o}),"outsideNode"),yt=(0,o.K2)(((t,e,r)=>{o.Rm.debug(`intersection calc abc89:\n outsidePoint: ${JSON.stringify(e)}\n insidePoint : ${JSON.stringify(r)}\n node : x:${t.x} y:${t.y} w:${t.width} h:${t.height}`);const s=t.x,a=t.y,i=Math.abs(s-r.x),n=t.width/2;let l=r.x<e.x?n-i:n+i;const c=t.height/2,d=Math.abs(e.y-r.y),h=Math.abs(e.x-r.x);if(Math.abs(a-e.y)*n>Math.abs(s-e.x)*c){let t=r.y<e.y?e.y-c-a:a-c-e.y;l=h*t/d;const s={x:r.x<e.x?r.x+l:r.x-h+l,y:r.y<e.y?r.y+d-t:r.y-d+t};return 0===l&&(s.x=e.x,s.y=e.y),0===h&&(s.x=e.x),0===d&&(s.y=e.y),o.Rm.debug(`abc89 topp/bott calc, Q ${d}, q ${t}, R ${h}, r ${l}`,s),s}{l=r.x<e.x?e.x-n-s:s-n-e.x;let t=d*l/h,a=r.x<e.x?r.x+h-l:r.x-h+l,i=r.y<e.y?r.y+t:r.y-t;return o.Rm.debug(`sides calc abc89, Q ${d}, q ${t}, R ${h}, r ${l}`,{_x:a,_y:i}),0===l&&(a=e.x,i=e.y),0===h&&(a=e.x),0===d&&(i=e.y),{x:a,y:i}}}),"intersection"),bt=(0,o.K2)(((t,e)=>{o.Rm.debug("abc88 cutPathAtIntersect",t,e);let r=[],s=t[0],a=!1;return t.forEach((t=>{if(pt(e,t)||a)s=t,a||r.push(t);else{const i=yt(e,s,t);let n=!1;r.forEach((t=>{n=n||t.x===i.x&&t.y===i.y})),r.some((t=>t.x===i.x&&t.y===i.y))||r.push(i),a=!0}})),r}),"cutPathAtIntersect"),xt=(0,o.K2)((function(t,e,r,a,i,n,l){let c=r.points;o.Rm.debug("abc88 InsertEdge: edge=",r,"e=",e);let d=!1;const g=n.node(e.v);var u=n.node(e.w);u?.intersect&&g?.intersect&&(c=c.slice(1,r.points.length-1),c.unshift(g.intersect(c[0])),c.push(u.intersect(c[c.length-1]))),r.toCluster&&(o.Rm.debug("to cluster abc88",a[r.toCluster]),c=bt(r.points,a[r.toCluster].node),d=!0),r.fromCluster&&(o.Rm.debug("from cluster abc88",a[r.fromCluster]),c=bt(c.reverse(),a[r.fromCluster].node).reverse(),d=!0);const p=c.filter((t=>!Number.isNaN(t.y)));let y=h.qrM;!r.curve||"graph"!==i&&"flowchart"!==i||(y=r.curve);const{x:b,y:x}=(0,s.R)(r),f=(0,h.n8j)().x(b).y(x).curve(y);let m;switch(r.thickness){case"normal":m="edge-thickness-normal";break;case"thick":case"invisible":m="edge-thickness-thick";break;default:m=""}switch(r.pattern){case"solid":m+=" edge-pattern-solid";break;case"dotted":m+=" edge-pattern-dotted";break;case"dashed":m+=" edge-pattern-dashed"}const w=t.append("path").attr("d",f(p)).attr("id",r.id).attr("class"," "+m+(r.classes?" "+r.classes:"")).attr("style",r.style);let _="";((0,o.D7)().flowchart.arrowMarkerAbsolute||(0,o.D7)().state.arrowMarkerAbsolute)&&(_=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,_=_.replace(/\(/g,"\\("),_=_.replace(/\)/g,"\\)")),nt(w,r,_,l,i);let L={};return d&&(L.updatedPath=c),L.originalPath=r.points,L}),"insertEdge"),ft=(0,o.K2)((t=>{const e=new Set;for(const r of t)switch(r){case"x":e.add("right"),e.add("left");break;case"y":e.add("up"),e.add("down");break;default:e.add(r)}return e}),"expandAndDeduplicateDirections"),mt=(0,o.K2)(((t,e,r)=>{const s=ft(t),a=e.height+2*r.padding,i=a/2,n=e.width+2*i+r.padding,o=r.padding/2;return s.has("right")&&s.has("left")&&s.has("up")&&s.has("down")?[{x:0,y:0},{x:i,y:0},{x:n/2,y:2*o},{x:n-i,y:0},{x:n,y:0},{x:n,y:-a/3},{x:n+2*o,y:-a/2},{x:n,y:-2*a/3},{x:n,y:-a},{x:n-i,y:-a},{x:n/2,y:-a-2*o},{x:i,y:-a},{x:0,y:-a},{x:0,y:-2*a/3},{x:-2*o,y:-a/2},{x:0,y:-a/3}]:s.has("right")&&s.has("left")&&s.has("up")?[{x:i,y:0},{x:n-i,y:0},{x:n,y:-a/2},{x:n-i,y:-a},{x:i,y:-a},{x:0,y:-a/2}]:s.has("right")&&s.has("left")&&s.has("down")?[{x:0,y:0},{x:i,y:-a},{x:n-i,y:-a},{x:n,y:0}]:s.has("right")&&s.has("up")&&s.has("down")?[{x:0,y:0},{x:n,y:-i},{x:n,y:-a+i},{x:0,y:-a}]:s.has("left")&&s.has("up")&&s.has("down")?[{x:n,y:0},{x:0,y:-i},{x:0,y:-a+i},{x:n,y:-a}]:s.has("right")&&s.has("left")?[{x:i,y:0},{x:i,y:-o},{x:n-i,y:-o},{x:n-i,y:0},{x:n,y:-a/2},{x:n-i,y:-a},{x:n-i,y:-a+o},{x:i,y:-a+o},{x:i,y:-a},{x:0,y:-a/2}]:s.has("up")&&s.has("down")?[{x:n/2,y:0},{x:0,y:-o},{x:i,y:-o},{x:i,y:-a+o},{x:0,y:-a+o},{x:n/2,y:-a},{x:n,y:-a+o},{x:n-i,y:-a+o},{x:n-i,y:-o},{x:n,y:-o}]:s.has("right")&&s.has("up")?[{x:0,y:0},{x:n,y:-i},{x:0,y:-a}]:s.has("right")&&s.has("down")?[{x:0,y:0},{x:n,y:0},{x:0,y:-a}]:s.has("left")&&s.has("up")?[{x:n,y:0},{x:0,y:-i},{x:n,y:-a}]:s.has("left")&&s.has("down")?[{x:n,y:0},{x:0,y:0},{x:n,y:-a}]:s.has("right")?[{x:i,y:-o},{x:i,y:-o},{x:n-i,y:-o},{x:n-i,y:0},{x:n,y:-a/2},{x:n-i,y:-a},{x:n-i,y:-a+o},{x:i,y:-a+o},{x:i,y:-a+o}]:s.has("left")?[{x:i,y:0},{x:i,y:-o},{x:n-i,y:-o},{x:n-i,y:-a+o},{x:i,y:-a+o},{x:i,y:-a},{x:0,y:-a/2}]:s.has("up")?[{x:i,y:-o},{x:i,y:-a+o},{x:0,y:-a+o},{x:n/2,y:-a},{x:n,y:-a+o},{x:n-i,y:-a+o},{x:n-i,y:-o}]:s.has("down")?[{x:n/2,y:0},{x:0,y:-o},{x:i,y:-o},{x:i,y:-a+o},{x:n-i,y:-a+o},{x:n-i,y:-o},{x:n,y:-o}]:[{x:0,y:0}]}),"getArrowPoints");function wt(t,e){return t.intersect(e)}(0,o.K2)(wt,"intersectNode");var _t=wt;function Lt(t,e,r,s){var a=t.x,i=t.y,n=a-s.x,o=i-s.y,l=Math.sqrt(e*e*o*o+r*r*n*n),c=Math.abs(e*r*n/l);s.x<a&&(c=-c);var d=Math.abs(e*r*o/l);return s.y<i&&(d=-d),{x:a+c,y:i+d}}(0,o.K2)(Lt,"intersectEllipse");var kt=Lt;function St(t,e,r){return kt(t,e,e,r)}(0,o.K2)(St,"intersectCircle");var vt=St;function Et(t,e,r,s){var a,i,n,o,l,c,d,h,g,u,p,y,b;if(a=e.y-t.y,n=t.x-e.x,l=e.x*t.y-t.x*e.y,g=a*r.x+n*r.y+l,u=a*s.x+n*s.y+l,!(0!==g&&0!==u&&Dt(g,u)||(i=s.y-r.y,o=r.x-s.x,c=s.x*r.y-r.x*s.y,d=i*t.x+o*t.y+c,h=i*e.x+o*e.y+c,0!==d&&0!==h&&Dt(d,h)||0==(p=a*o-i*n))))return y=Math.abs(p/2),{x:(b=n*c-o*l)<0?(b-y)/p:(b+y)/p,y:(b=i*l-a*c)<0?(b-y)/p:(b+y)/p}}function Dt(t,e){return t*e>0}(0,o.K2)(Et,"intersectLine"),(0,o.K2)(Dt,"sameSign");var Ct=Et,Rt=Kt;function Kt(t,e,r){var s=t.x,a=t.y,i=[],n=Number.POSITIVE_INFINITY,o=Number.POSITIVE_INFINITY;"function"==typeof e.forEach?e.forEach((function(t){n=Math.min(n,t.x),o=Math.min(o,t.y)})):(n=Math.min(n,e.x),o=Math.min(o,e.y));for(var l=s-t.width/2-n,c=a-t.height/2-o,d=0;d<e.length;d++){var h=e[d],g=e[d<e.length-1?d+1:0],u=Ct(t,r,{x:l+h.x,y:c+h.y},{x:l+g.x,y:c+g.y});u&&i.push(u)}return i.length?(i.length>1&&i.sort((function(t,e){var s=t.x-r.x,a=t.y-r.y,i=Math.sqrt(s*s+a*a),n=e.x-r.x,o=e.y-r.y,l=Math.sqrt(n*n+o*o);return i<l?-1:i===l?0:1})),i[0]):t}(0,o.K2)(Kt,"intersectPolygon");var Nt={node:_t,circle:vt,ellipse:kt,polygon:Rt,rect:(0,o.K2)(((t,e)=>{var r,s,a=t.x,i=t.y,n=e.x-a,o=e.y-i,l=t.width/2,c=t.height/2;return Math.abs(o)*l>Math.abs(n)*c?(o<0&&(c=-c),r=0===o?0:c*n/o,s=c):(n<0&&(l=-l),r=l,s=0===n?0:l*o/n),{x:a+r,y:i+s}}),"intersectRect")},Tt=(0,o.K2)((async(t,e,r,s)=>{const a=(0,o.D7)();let l;const c=e.useHtmlLabels||(0,o._3)(a.flowchart.htmlLabels);l=r||"node default";const d=t.insert("g").attr("class",l).attr("id",e.domId||e.id),g=d.insert("g").attr("class","label").attr("style",e.labelStyle);let u;u=void 0===e.labelText?"":"string"==typeof e.labelText?e.labelText:e.labelText[0];const p=g.node();let y;y="markdown"===e.labelType?(0,i.GZ)(g,(0,o.jZ)((0,n.Sm)(u),a),{useHtmlLabels:c,width:e.width||a.flowchart.wrappingWidth,classes:"markdown-node-label"},a):p.appendChild(it((0,o.jZ)((0,n.Sm)(u),a),e.labelStyle,!1,s));let b=y.getBBox();const x=e.padding/2;if((0,o._3)(a.flowchart.htmlLabels)){const t=y.children[0],e=(0,h.Ltv)(y),r=t.getElementsByTagName("img");if(r){const t=""===u.replace(/<img[^>]*>/g,"").trim();await Promise.all([...r].map((e=>new Promise((r=>{function s(){if(e.style.display="flex",e.style.flexDirection="column",t){const t=a.fontSize?a.fontSize:window.getComputedStyle(document.body).fontSize,r=5,s=parseInt(t,10)*r+"px";e.style.minWidth=s,e.style.maxWidth=s}else e.style.width="100%";r(e)}(0,o.K2)(s,"setupImage"),setTimeout((()=>{e.complete&&s()})),e.addEventListener("error",s),e.addEventListener("load",s)})))))}b=t.getBoundingClientRect(),e.attr("width",b.width),e.attr("height",b.height)}return c?g.attr("transform","translate("+-b.width/2+", "+-b.height/2+")"):g.attr("transform","translate(0, "+-b.height/2+")"),e.centerLabel&&g.attr("transform","translate("+-b.width/2+", "+-b.height/2+")"),g.insert("rect",":first-child"),{shapeSvg:d,bbox:b,halfPadding:x,label:g}}),"labelHelper"),$t=(0,o.K2)(((t,e)=>{const r=e.node().getBBox();t.width=r.width,t.height=r.height}),"updateNodeBounds");function At(t,e,r,s){return t.insert("polygon",":first-child").attr("points",s.map((function(t){return t.x+","+t.y})).join(" ")).attr("class","label-container").attr("transform","translate("+-e/2+","+r/2+")")}(0,o.K2)(At,"insertPolygonShape");var It=(0,o.K2)((async(t,e)=>{e.useHtmlLabels||(0,o.D7)().flowchart.htmlLabels||(e.centerLabel=!0);const{shapeSvg:r,bbox:s,halfPadding:a}=await Tt(t,e,"node "+e.classes,!0);o.Rm.info("Classes = ",e.classes);const i=r.insert("rect",":first-child");return i.attr("rx",e.rx).attr("ry",e.ry).attr("x",-s.width/2-a).attr("y",-s.height/2-a).attr("width",s.width+e.padding).attr("height",s.height+e.padding),$t(e,i),e.intersect=function(t){return Nt.rect(e,t)},r}),"note"),Ot=(0,o.K2)((t=>t?" "+t:""),"formatClass"),Bt=(0,o.K2)(((t,e)=>`${e||"node default"}${Ot(t.classes)} ${Ot(t.class)}`),"getClassesFromNode"),zt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding+(s.height+e.padding),i=[{x:a/2,y:0},{x:a,y:-a/2},{x:a/2,y:-a},{x:0,y:-a/2}];o.Rm.info("Question main (Circle)");const n=At(r,a,a,i);return n.attr("style",e.style),$t(e,n),e.intersect=function(t){return o.Rm.warn("Intersect called"),Nt.polygon(e,i,t)},r}),"question"),Mt=(0,o.K2)(((t,e)=>{const r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),s=[{x:0,y:14},{x:14,y:0},{x:0,y:-14},{x:-14,y:0}];return r.insert("polygon",":first-child").attr("points",s.map((function(t){return t.x+","+t.y})).join(" ")).attr("class","state-start").attr("r",7).attr("width",28).attr("height",28),e.width=28,e.height=28,e.intersect=function(t){return Nt.circle(e,14,t)},r}),"choice"),Pt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.height+e.padding,i=a/4,n=s.width+2*i+e.padding,o=[{x:i,y:0},{x:n-i,y:0},{x:n,y:-a/2},{x:n-i,y:-a},{x:i,y:-a},{x:0,y:-a/2}],l=At(r,n,a,o);return l.attr("style",e.style),$t(e,l),e.intersect=function(t){return Nt.polygon(e,o,t)},r}),"hexagon"),Yt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,void 0,!0),a=s.height+2*e.padding,i=a/2,n=s.width+2*i+e.padding,o=mt(e.directions,s,e),l=At(r,n,a,o);return l.attr("style",e.style),$t(e,l),e.intersect=function(t){return Nt.polygon(e,o,t)},r}),"block_arrow"),Ft=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:-i/2,y:0},{x:a,y:0},{x:a,y:-i},{x:-i/2,y:-i},{x:0,y:-i/2}];return At(r,a,i,n).attr("style",e.style),e.width=a+i,e.height=i,e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"rect_left_inv_arrow"),jt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:-2*i/6,y:0},{x:a-i/6,y:0},{x:a+2*i/6,y:-i},{x:i/6,y:-i}],o=At(r,a,i,n);return o.attr("style",e.style),$t(e,o),e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"lean_right"),Wt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:2*i/6,y:0},{x:a+i/6,y:0},{x:a-2*i/6,y:-i},{x:-i/6,y:-i}],o=At(r,a,i,n);return o.attr("style",e.style),$t(e,o),e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"lean_left"),Xt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:-2*i/6,y:0},{x:a+2*i/6,y:0},{x:a-i/6,y:-i},{x:i/6,y:-i}],o=At(r,a,i,n);return o.attr("style",e.style),$t(e,o),e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"trapezoid"),Ht=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:i/6,y:0},{x:a-i/6,y:0},{x:a+2*i/6,y:-i},{x:-2*i/6,y:-i}],o=At(r,a,i,n);return o.attr("style",e.style),$t(e,o),e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"inv_trapezoid"),Ut=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:0,y:0},{x:a+i/2,y:0},{x:a,y:-i/2},{x:a+i/2,y:-i},{x:0,y:-i}],o=At(r,a,i,n);return o.attr("style",e.style),$t(e,o),e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"rect_right_inv_arrow"),Zt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=a/2,n=i/(2.5+a/50),o=s.height+n+e.padding,l="M 0,"+n+" a "+i+","+n+" 0,0,0 "+a+" 0 a "+i+","+n+" 0,0,0 "+-a+" 0 l 0,"+o+" a "+i+","+n+" 0,0,0 "+a+" 0 l 0,"+-o,c=r.attr("label-offset-y",n).insert("path",":first-child").attr("style",e.style).attr("d",l).attr("transform","translate("+-a/2+","+-(o/2+n)+")");return $t(e,c),e.intersect=function(t){const r=Nt.rect(e,t),s=r.x-e.x;if(0!=i&&(Math.abs(s)<e.width/2||Math.abs(s)==e.width/2&&Math.abs(r.y-e.y)>e.height/2-n)){let a=n*n*(1-s*s/(i*i));0!=a&&(a=Math.sqrt(a)),a=n-a,t.y-e.y>0&&(a=-a),r.y+=a}return r},r}),"cylinder"),qt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s,halfPadding:a}=await Tt(t,e,"node "+e.classes+" "+e.class,!0),i=r.insert("rect",":first-child"),n=e.positioned?e.width:s.width+e.padding,l=e.positioned?e.height:s.height+e.padding,c=e.positioned?-n/2:-s.width/2-a,d=e.positioned?-l/2:-s.height/2-a;if(i.attr("class","basic label-container").attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",c).attr("y",d).attr("width",n).attr("height",l),e.props){const t=new Set(Object.keys(e.props));e.props.borders&&(Vt(i,e.props.borders,n,l),t.delete("borders")),t.forEach((t=>{o.Rm.warn(`Unknown node property ${t}`)}))}return $t(e,i),e.intersect=function(t){return Nt.rect(e,t)},r}),"rect"),Gt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s,halfPadding:a}=await Tt(t,e,"node "+e.classes,!0),i=r.insert("rect",":first-child"),n=e.positioned?e.width:s.width+e.padding,l=e.positioned?e.height:s.height+e.padding,c=e.positioned?-n/2:-s.width/2-a,d=e.positioned?-l/2:-s.height/2-a;if(i.attr("class","basic cluster composite label-container").attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("x",c).attr("y",d).attr("width",n).attr("height",l),e.props){const t=new Set(Object.keys(e.props));e.props.borders&&(Vt(i,e.props.borders,n,l),t.delete("borders")),t.forEach((t=>{o.Rm.warn(`Unknown node property ${t}`)}))}return $t(e,i),e.intersect=function(t){return Nt.rect(e,t)},r}),"composite"),Jt=(0,o.K2)((async(t,e)=>{const{shapeSvg:r}=await Tt(t,e,"label",!0);o.Rm.trace("Classes = ",e.class);const s=r.insert("rect",":first-child");if(s.attr("width",0).attr("height",0),r.attr("class","label edgeLabel"),e.props){const t=new Set(Object.keys(e.props));e.props.borders&&(Vt(s,e.props.borders,0,0),t.delete("borders")),t.forEach((t=>{o.Rm.warn(`Unknown node property ${t}`)}))}return $t(e,s),e.intersect=function(t){return Nt.rect(e,t)},r}),"labelRect");function Vt(t,e,r,s){const a=[],i=(0,o.K2)((t=>{a.push(t,0)}),"addBorder"),n=(0,o.K2)((t=>{a.push(0,t)}),"skipBorder");e.includes("t")?(o.Rm.debug("add top border"),i(r)):n(r),e.includes("r")?(o.Rm.debug("add right border"),i(s)):n(s),e.includes("b")?(o.Rm.debug("add bottom border"),i(r)):n(r),e.includes("l")?(o.Rm.debug("add left border"),i(s)):n(s),t.attr("stroke-dasharray",a.join(" "))}(0,o.K2)(Vt,"applyNodePropertyBorders");var Qt=(0,o.K2)(((t,e)=>{let r;r=e.classes?"node "+e.classes:"node default";const s=t.insert("g").attr("class",r).attr("id",e.domId||e.id),a=s.insert("rect",":first-child"),i=s.insert("line"),n=s.insert("g").attr("class","label"),l=e.labelText.flat?e.labelText.flat():e.labelText;let c="";c="object"==typeof l?l[0]:l,o.Rm.info("Label text abc79",c,l,"object"==typeof l);const d=n.node().appendChild(it(c,e.labelStyle,!0,!0));let g={width:0,height:0};if((0,o._3)((0,o.D7)().flowchart.htmlLabels)){const t=d.children[0],e=(0,h.Ltv)(d);g=t.getBoundingClientRect(),e.attr("width",g.width),e.attr("height",g.height)}o.Rm.info("Text 2",l);const u=l.slice(1,l.length);let p=d.getBBox();const y=n.node().appendChild(it(u.join?u.join("<br/>"):u,e.labelStyle,!0,!0));if((0,o._3)((0,o.D7)().flowchart.htmlLabels)){const t=y.children[0],e=(0,h.Ltv)(y);g=t.getBoundingClientRect(),e.attr("width",g.width),e.attr("height",g.height)}const b=e.padding/2;return(0,h.Ltv)(y).attr("transform","translate( "+(g.width>p.width?0:(p.width-g.width)/2)+", "+(p.height+b+5)+")"),(0,h.Ltv)(d).attr("transform","translate( "+(g.width<p.width?0:-(p.width-g.width)/2)+", 0)"),g=n.node().getBBox(),n.attr("transform","translate("+-g.width/2+", "+(-g.height/2-b+3)+")"),a.attr("class","outer title-state").attr("x",-g.width/2-b).attr("y",-g.height/2-b).attr("width",g.width+e.padding).attr("height",g.height+e.padding),i.attr("class","divider").attr("x1",-g.width/2-b).attr("x2",g.width/2+b).attr("y1",-g.height/2-b+p.height+b).attr("y2",-g.height/2-b+p.height+b),$t(e,a),e.intersect=function(t){return Nt.rect(e,t)},s}),"rectWithTitle"),te=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.height+e.padding,i=s.width+a/4+e.padding,n=r.insert("rect",":first-child").attr("style",e.style).attr("rx",a/2).attr("ry",a/2).attr("x",-i/2).attr("y",-a/2).attr("width",i).attr("height",a);return $t(e,n),e.intersect=function(t){return Nt.rect(e,t)},r}),"stadium"),ee=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s,halfPadding:a}=await Tt(t,e,Bt(e,void 0),!0),i=r.insert("circle",":first-child");return i.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("r",s.width/2+a).attr("width",s.width+e.padding).attr("height",s.height+e.padding),o.Rm.info("Circle main"),$t(e,i),e.intersect=function(t){return o.Rm.info("Circle intersect",e,s.width/2+a,t),Nt.circle(e,s.width/2+a,t)},r}),"circle"),re=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s,halfPadding:a}=await Tt(t,e,Bt(e,void 0),!0),i=r.insert("g",":first-child"),n=i.insert("circle"),l=i.insert("circle");return i.attr("class",e.class),n.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("r",s.width/2+a+5).attr("width",s.width+e.padding+10).attr("height",s.height+e.padding+10),l.attr("style",e.style).attr("rx",e.rx).attr("ry",e.ry).attr("r",s.width/2+a).attr("width",s.width+e.padding).attr("height",s.height+e.padding),o.Rm.info("DoubleCircle main"),$t(e,n),e.intersect=function(t){return o.Rm.info("DoubleCircle intersect",e,s.width/2+a+5,t),Nt.circle(e,s.width/2+a+5,t)},r}),"doublecircle"),se=(0,o.K2)((async(t,e)=>{const{shapeSvg:r,bbox:s}=await Tt(t,e,Bt(e,void 0),!0),a=s.width+e.padding,i=s.height+e.padding,n=[{x:0,y:0},{x:a,y:0},{x:a,y:-i},{x:0,y:-i},{x:0,y:0},{x:-8,y:0},{x:a+8,y:0},{x:a+8,y:-i},{x:-8,y:-i},{x:-8,y:0}],o=At(r,a,i,n);return o.attr("style",e.style),$t(e,o),e.intersect=function(t){return Nt.polygon(e,n,t)},r}),"subroutine"),ae=(0,o.K2)(((t,e)=>{const r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),s=r.insert("circle",":first-child");return s.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),$t(e,s),e.intersect=function(t){return Nt.circle(e,7,t)},r}),"start"),ie=(0,o.K2)(((t,e,r)=>{const s=t.insert("g").attr("class","node default").attr("id",e.domId||e.id);let a=70,i=10;"LR"===r&&(a=10,i=70);const n=s.append("rect").attr("x",-1*a/2).attr("y",-1*i/2).attr("width",a).attr("height",i).attr("class","fork-join");return $t(e,n),e.height=e.height+e.padding/2,e.width=e.width+e.padding/2,e.intersect=function(t){return Nt.rect(e,t)},s}),"forkJoin"),ne={rhombus:zt,composite:Gt,question:zt,rect:qt,labelRect:Jt,rectWithTitle:Qt,choice:Mt,circle:ee,doublecircle:re,stadium:te,hexagon:Pt,block_arrow:Yt,rect_left_inv_arrow:Ft,lean_right:jt,lean_left:Wt,trapezoid:Xt,inv_trapezoid:Ht,rect_right_inv_arrow:Ut,cylinder:Zt,start:ae,end:(0,o.K2)(((t,e)=>{const r=t.insert("g").attr("class","node default").attr("id",e.domId||e.id),s=r.insert("circle",":first-child"),a=r.insert("circle",":first-child");return a.attr("class","state-start").attr("r",7).attr("width",14).attr("height",14),s.attr("class","state-end").attr("r",5).attr("width",10).attr("height",10),$t(e,a),e.intersect=function(t){return Nt.circle(e,7,t)},r}),"end"),note:It,subroutine:se,fork:ie,join:ie,class_box:(0,o.K2)(((t,e)=>{const r=e.padding/2;let s;s=e.classes?"node "+e.classes:"node default";const a=t.insert("g").attr("class",s).attr("id",e.domId||e.id),i=a.insert("rect",":first-child"),n=a.insert("line"),l=a.insert("line");let c=0,d=4;const g=a.insert("g").attr("class","label");let u=0;const p=e.classData.annotations?.[0],y=e.classData.annotations[0]?"\xab"+e.classData.annotations[0]+"\xbb":"",b=g.node().appendChild(it(y,e.labelStyle,!0,!0));let x=b.getBBox();if((0,o._3)((0,o.D7)().flowchart.htmlLabels)){const t=b.children[0],e=(0,h.Ltv)(b);x=t.getBoundingClientRect(),e.attr("width",x.width),e.attr("height",x.height)}e.classData.annotations[0]&&(d+=x.height+4,c+=x.width);let f=e.classData.label;void 0!==e.classData.type&&""!==e.classData.type&&((0,o.D7)().flowchart.htmlLabels?f+="<"+e.classData.type+">":f+="<"+e.classData.type+">");const m=g.node().appendChild(it(f,e.labelStyle,!0,!0));(0,h.Ltv)(m).attr("class","classTitle");let w=m.getBBox();if((0,o._3)((0,o.D7)().flowchart.htmlLabels)){const t=m.children[0],e=(0,h.Ltv)(m);w=t.getBoundingClientRect(),e.attr("width",w.width),e.attr("height",w.height)}d+=w.height+4,w.width>c&&(c=w.width);const _=[];e.classData.members.forEach((t=>{const r=t.getDisplayDetails();let s=r.displayText;(0,o.D7)().flowchart.htmlLabels&&(s=s.replace(/</g,"<").replace(/>/g,">"));const a=g.node().appendChild(it(s,r.cssStyle?r.cssStyle:e.labelStyle,!0,!0));let i=a.getBBox();if((0,o._3)((0,o.D7)().flowchart.htmlLabels)){const t=a.children[0],e=(0,h.Ltv)(a);i=t.getBoundingClientRect(),e.attr("width",i.width),e.attr("height",i.height)}i.width>c&&(c=i.width),d+=i.height+4,_.push(a)})),d+=8;const L=[];if(e.classData.methods.forEach((t=>{const r=t.getDisplayDetails();let s=r.displayText;(0,o.D7)().flowchart.htmlLabels&&(s=s.replace(/</g,"<").replace(/>/g,">"));const a=g.node().appendChild(it(s,r.cssStyle?r.cssStyle:e.labelStyle,!0,!0));let i=a.getBBox();if((0,o._3)((0,o.D7)().flowchart.htmlLabels)){const t=a.children[0],e=(0,h.Ltv)(a);i=t.getBoundingClientRect(),e.attr("width",i.width),e.attr("height",i.height)}i.width>c&&(c=i.width),d+=i.height+4,L.push(a)})),d+=8,p){let t=(c-x.width)/2;(0,h.Ltv)(b).attr("transform","translate( "+(-1*c/2+t)+", "+-1*d/2+")"),u=x.height+4}let k=(c-w.width)/2;return(0,h.Ltv)(m).attr("transform","translate( "+(-1*c/2+k)+", "+(-1*d/2+u)+")"),u+=w.height+4,n.attr("class","divider").attr("x1",-c/2-r).attr("x2",c/2+r).attr("y1",-d/2-r+8+u).attr("y2",-d/2-r+8+u),u+=8,_.forEach((t=>{(0,h.Ltv)(t).attr("transform","translate( "+-c/2+", "+(-1*d/2+u+4)+")");const e=t?.getBBox();u+=(e?.height??0)+4})),u+=8,l.attr("class","divider").attr("x1",-c/2-r).attr("x2",c/2+r).attr("y1",-d/2-r+8+u).attr("y2",-d/2-r+8+u),u+=8,L.forEach((t=>{(0,h.Ltv)(t).attr("transform","translate( "+-c/2+", "+(-1*d/2+u)+")");const e=t?.getBBox();u+=(e?.height??0)+4})),i.attr("style",e.style).attr("class","outer title-state").attr("x",-c/2-r).attr("y",-d/2-r).attr("width",c+e.padding).attr("height",d+e.padding),$t(e,i),e.intersect=function(t){return Nt.rect(e,t)},a}),"class_box")},oe={},le=(0,o.K2)((async(t,e,r)=>{let s,a;if(e.link){let i;"sandbox"===(0,o.D7)().securityLevel?i="_top":e.linkTarget&&(i=e.linkTarget||"_blank"),s=t.insert("svg:a").attr("xlink:href",e.link).attr("target",i),a=await ne[e.shape](s,e,r)}else a=await ne[e.shape](t,e,r),s=a;return e.tooltip&&a.attr("title",e.tooltip),e.class&&a.attr("class","node default "+e.class),oe[e.id]=s,e.haveCallback&&oe[e.id].attr("class",oe[e.id].attr("class")+" clickable"),s}),"insertNode"),ce=(0,o.K2)((t=>{const e=oe[t.id];o.Rm.trace("Transforming node",t.diff,t,"translate("+(t.x-t.width/2-5)+", "+t.width/2+")");const r=t.diff||0;return t.clusterNode?e.attr("transform","translate("+(t.x+r-t.width/2)+", "+(t.y-t.height/2-8)+")"):e.attr("transform","translate("+t.x+", "+t.y+")"),r}),"positionNode");function de(t,e,r=!1){const s=t;let a="default";(s?.classes?.length||0)>0&&(a=(s?.classes??[]).join(" ")),a+=" flowchart-label";let i,l=0,c="";switch(s.type){case"round":l=5,c="rect";break;case"composite":l=0,c="composite",i=0;break;case"square":case"group":default:c="rect";break;case"diamond":c="question";break;case"hexagon":c="hexagon";break;case"block_arrow":c="block_arrow";break;case"odd":case"rect_left_inv_arrow":c="rect_left_inv_arrow";break;case"lean_right":c="lean_right";break;case"lean_left":c="lean_left";break;case"trapezoid":c="trapezoid";break;case"inv_trapezoid":c="inv_trapezoid";break;case"circle":c="circle";break;case"ellipse":c="ellipse";break;case"stadium":c="stadium";break;case"subroutine":c="subroutine";break;case"cylinder":c="cylinder";break;case"doublecircle":c="doublecircle"}const d=(0,n.sM)(s?.styles??[]),h=s.label,g=s.size??{width:0,height:0,x:0,y:0};return{labelStyle:d.labelStyle,shape:c,labelText:h,rx:l,ry:l,class:a,style:d.style,id:s.id,directions:s.directions,width:g.width,height:g.height,x:g.x,y:g.y,positioned:r,intersect:void 0,type:s.type,padding:i??(0,o.zj)()?.block?.padding??0}}async function he(t,e,r){const s=de(e,0,!1);if("group"===s.type)return;const a=(0,o.zj)(),i=await le(t,s,{config:a}),n=i.node().getBBox(),l=r.getBlock(s.id);l.size={width:n.width,height:n.height,x:0,y:0,node:i},r.setBlock(l),i.remove()}async function ge(t,e,r){const s=de(e,0,!0);if("space"!==r.getBlock(s.id).type){const r=(0,o.zj)();await le(t,s,{config:r}),e.intersect=s?.intersect,ce(s)}}async function ue(t,e,r,s){for(const a of e)await s(t,a,r),a.children&&await ue(t,a.children,r,s)}async function pe(t,e,r){await ue(t,e,r,he)}async function ye(t,e,r){await ue(t,e,r,ge)}async function be(t,e,r,s,a){const i=new g.T({multigraph:!0,compound:!0});i.setGraph({rankdir:"TB",nodesep:10,ranksep:10,marginx:8,marginy:8});for(const n of r)n.size&&i.setNode(n.id,{width:n.size.width,height:n.size.height,intersect:n.intersect});for(const n of e)if(n.start&&n.end){const e=s.getBlock(n.start),r=s.getBlock(n.end);if(e?.size&&r?.size){const s=e.size,o=r.size,l=[{x:s.x,y:s.y},{x:s.x+(o.x-s.x)/2,y:s.y+(o.y-s.y)/2},{x:o.x,y:o.y}];xt(t,{v:n.start,w:n.end,name:n.id},{...n,arrowTypeEnd:n.arrowTypeEnd,arrowTypeStart:n.arrowTypeStart,points:l,classes:"edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1"},void 0,"block",i,a),n.label&&(await ht(t,{...n,label:n.label,labelStyle:"stroke: #333; stroke-width: 1.5px;fill:none;",arrowTypeEnd:n.arrowTypeEnd,arrowTypeStart:n.arrowTypeStart,points:l,classes:"edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1"}),ut({...n,x:l[1].x,y:l[1].y},{originalPath:l}))}}}(0,o.K2)(de,"getNodeFromBlock"),(0,o.K2)(he,"calculateBlockSize"),(0,o.K2)(ge,"insertBlockPositioned"),(0,o.K2)(ue,"performOperations"),(0,o.K2)(pe,"calculateBlockSizes"),(0,o.K2)(ye,"insertBlocks"),(0,o.K2)(be,"insertEdges");var xe=(0,o.K2)((function(t,e){return e.db.getClasses()}),"getClasses"),fe={parser:p,db:W,renderer:{draw:(0,o.K2)((async function(t,e,r,s){const{securityLevel:a,block:i}=(0,o.zj)(),n=s.db;let l;"sandbox"===a&&(l=(0,h.Ltv)("#i"+e));const c="sandbox"===a?(0,h.Ltv)(l.nodes()[0].contentDocument.body):(0,h.Ltv)("body"),d="sandbox"===a?c.select(`[id="${e}"]`):(0,h.Ltv)(`[id="${e}"]`);q(d,["point","circle","cross"],s.type,e);const g=n.getBlocks(),u=n.getBlocksFlat(),p=n.getEdges(),y=d.insert("g").attr("class","block");await pe(y,g,n);const b=rt(n);if(await ye(y,g,n),await be(y,p,u,n,e),b){const t=b,e=Math.max(1,Math.round(t.width/t.height*.125)),r=t.height+e+10,s=t.width+10,{useMaxWidth:a}=i;(0,o.a$)(d,r,s,!!a),o.Rm.debug("Here Bounds",b,t),d.attr("viewBox",`${t.x-5} ${t.y-5} ${t.width+10} ${t.height+10}`)}}),"draw"),getClasses:xe},styles:H}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/545.7563beb4.js b/pr-preview/pr-1071/assets/js/545.7563beb4.js deleted file mode 100644 index 7edd58c8c0..0000000000 --- a/pr-preview/pr-1071/assets/js/545.7563beb4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[545],{50545:(t,i,e)=>{e.d(i,{diagram:()=>J});var s=e(10483),n=e(8159),a=e(77286),h=e(10009),o=e(20007),r=function(){var t=(0,h.K2)((function(t,i,e,s){for(e=e||{},s=t.length;s--;e[t[s]]=i);return e}),"o"),i=[1,10,12,14,16,18,19,21,23],e=[2,6],s=[1,3],n=[1,5],a=[1,6],o=[1,7],r=[1,5,10,12,14,16,18,19,21,23,34,35,36],l=[1,25],c=[1,26],g=[1,28],u=[1,29],x=[1,30],d=[1,31],p=[1,32],f=[1,33],y=[1,34],m=[1,35],b=[1,36],A=[1,37],S=[1,43],C=[1,42],w=[1,47],k=[1,50],_=[1,10,12,14,16,18,19,21,23,34,35,36],T=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],R=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],D=[1,64],L={trace:(0,h.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:(0,h.K2)((function(t,i,e,s,n,a,h){var o=a.length-1;switch(n){case 5:s.setOrientation(a[o]);break;case 9:s.setDiagramTitle(a[o].text.trim());break;case 12:s.setLineData({text:"",type:"text"},a[o]);break;case 13:s.setLineData(a[o-1],a[o]);break;case 14:s.setBarData({text:"",type:"text"},a[o]);break;case 15:s.setBarData(a[o-1],a[o]);break;case 16:this.$=a[o].trim(),s.setAccTitle(this.$);break;case 17:case 18:this.$=a[o].trim(),s.setAccDescription(this.$);break;case 19:case 27:this.$=a[o-1];break;case 20:this.$=[Number(a[o-2]),...a[o]];break;case 21:this.$=[Number(a[o])];break;case 22:s.setXAxisTitle(a[o]);break;case 23:s.setXAxisTitle(a[o-1]);break;case 24:s.setXAxisTitle({type:"text",text:""});break;case 25:s.setXAxisBand(a[o]);break;case 26:s.setXAxisRangeData(Number(a[o-2]),Number(a[o]));break;case 28:this.$=[a[o-2],...a[o]];break;case 29:this.$=[a[o]];break;case 30:s.setYAxisTitle(a[o]);break;case 31:s.setYAxisTitle(a[o-1]);break;case 32:s.setYAxisTitle({type:"text",text:""});break;case 33:s.setYAxisRangeData(Number(a[o-2]),Number(a[o]));break;case 37:case 38:this.$={text:a[o],type:"text"};break;case 39:this.$={text:a[o],type:"markdown"};break;case 40:this.$=a[o];break;case 41:this.$=a[o-1]+""+a[o]}}),"anonymous"),table:[t(i,e,{3:1,4:2,7:4,5:s,34:n,35:a,36:o}),{1:[3]},t(i,e,{4:2,7:4,3:8,5:s,34:n,35:a,36:o}),t(i,e,{4:2,7:4,6:9,3:10,5:s,8:[1,11],34:n,35:a,36:o}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},t(r,[2,34]),t(r,[2,35]),t(r,[2,36]),{1:[2,1]},t(i,e,{4:2,7:4,3:21,5:s,34:n,35:a,36:o}),{1:[2,3]},t(r,[2,5]),t(i,[2,7],{4:22,34:n,35:a,36:o}),{11:23,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},{11:39,13:38,24:S,27:C,29:40,30:41,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},{11:45,15:44,27:w,33:46,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},{11:49,17:48,24:k,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},{11:52,17:51,24:k,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},{20:[1,53]},{22:[1,54]},t(_,[2,18]),{1:[2,2]},t(_,[2,8]),t(_,[2,9]),t(T,[2,37],{40:55,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A}),t(T,[2,38]),t(T,[2,39]),t(R,[2,40]),t(R,[2,42]),t(R,[2,43]),t(R,[2,44]),t(R,[2,45]),t(R,[2,46]),t(R,[2,47]),t(R,[2,48]),t(R,[2,49]),t(R,[2,50]),t(R,[2,51]),t(_,[2,10]),t(_,[2,22],{30:41,29:56,24:S,27:C}),t(_,[2,24]),t(_,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},t(_,[2,11]),t(_,[2,30],{33:60,27:w}),t(_,[2,32]),{31:[1,61]},t(_,[2,12]),{17:62,24:k},{25:63,27:D},t(_,[2,14]),{17:65,24:k},t(_,[2,16]),t(_,[2,17]),t(R,[2,41]),t(_,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},t(_,[2,31]),{27:[1,69]},t(_,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},t(_,[2,15]),t(_,[2,26]),t(_,[2,27]),{11:59,32:72,37:24,38:l,39:c,40:27,41:g,42:u,43:x,44:d,45:p,46:f,47:y,48:m,49:b,50:A},t(_,[2,33]),t(_,[2,19]),{25:73,27:D},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:(0,h.K2)((function(t,i){if(!i.recoverable){var e=new Error(t);throw e.hash=i,e}this.trace(t)}),"parseError"),parse:(0,h.K2)((function(t){var i=this,e=[0],s=[],n=[null],a=[],o=this.table,r="",l=0,c=0,g=0,u=a.slice.call(arguments,1),x=Object.create(this.lexer),d={yy:{}};for(var p in this.yy)Object.prototype.hasOwnProperty.call(this.yy,p)&&(d.yy[p]=this.yy[p]);x.setInput(t,d.yy),d.yy.lexer=x,d.yy.parser=this,void 0===x.yylloc&&(x.yylloc={});var f=x.yylloc;a.push(f);var y=x.options&&x.options.ranges;function m(){var t;return"number"!=typeof(t=s.pop()||x.lex()||1)&&(t instanceof Array&&(t=(s=t).pop()),t=i.symbols_[t]||t),t}"function"==typeof d.yy.parseError?this.parseError=d.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,h.K2)((function(t){e.length=e.length-2*t,n.length=n.length-t,a.length=a.length-t}),"popStack"),(0,h.K2)(m,"lex");for(var b,A,S,C,w,k,_,T,R,D={};;){if(S=e[e.length-1],this.defaultActions[S]?C=this.defaultActions[S]:(null==b&&(b=m()),C=o[S]&&o[S][b]),void 0===C||!C.length||!C[0]){var L="";for(k in R=[],o[S])this.terminals_[k]&&k>2&&R.push("'"+this.terminals_[k]+"'");L=x.showPosition?"Parse error on line "+(l+1)+":\n"+x.showPosition()+"\nExpecting "+R.join(", ")+", got '"+(this.terminals_[b]||b)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==b?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(L,{text:x.match,token:this.terminals_[b]||b,line:x.yylineno,loc:f,expected:R})}if(C[0]instanceof Array&&C.length>1)throw new Error("Parse Error: multiple actions possible at state: "+S+", token: "+b);switch(C[0]){case 1:e.push(b),n.push(x.yytext),a.push(x.yylloc),e.push(C[1]),b=null,A?(b=A,A=null):(c=x.yyleng,r=x.yytext,l=x.yylineno,f=x.yylloc,g>0&&g--);break;case 2:if(_=this.productions_[C[1]][1],D.$=n[n.length-_],D._$={first_line:a[a.length-(_||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(_||1)].first_column,last_column:a[a.length-1].last_column},y&&(D._$.range=[a[a.length-(_||1)].range[0],a[a.length-1].range[1]]),void 0!==(w=this.performAction.apply(D,[r,c,l,d.yy,C[1],n,a].concat(u))))return w;_&&(e=e.slice(0,-1*_*2),n=n.slice(0,-1*_),a=a.slice(0,-1*_)),e.push(this.productions_[C[1]][0]),n.push(D.$),a.push(D._$),T=o[e[e.length-2]][e[e.length-1]],e.push(T);break;case 3:return!0}}return!0}),"parse")},P=function(){return{EOF:1,parseError:(0,h.K2)((function(t,i){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,i)}),"parseError"),setInput:(0,h.K2)((function(t,i){return this.yy=i||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,h.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,h.K2)((function(t){var i=t.length,e=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-i),this.offset-=i;var s=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),e.length-1&&(this.yylineno-=e.length-1);var n=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:e?(e.length===s.length?this.yylloc.first_column:0)+s[s.length-e.length].length-e[0].length:this.yylloc.first_column-i},this.options.ranges&&(this.yylloc.range=[n[0],n[0]+this.yyleng-i]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,h.K2)((function(){return this._more=!0,this}),"more"),reject:(0,h.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,h.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,h.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,h.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,h.K2)((function(){var t=this.pastInput(),i=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+i+"^"}),"showPosition"),test_match:(0,h.K2)((function(t,i){var e,s,n;if(this.options.backtrack_lexer&&(n={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(n.yylloc.range=this.yylloc.range.slice(0))),(s=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=s.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:s?s[s.length-1].length-s[s.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],e=this.performAction.call(this,this.yy,this,i,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),e)return e;if(this._backtrack){for(var a in n)this[a]=n[a];return!1}return!1}),"test_match"),next:(0,h.K2)((function(){if(this.done)return this.EOF;var t,i,e,s;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var n=this._currentRules(),a=0;a<n.length;a++)if((e=this._input.match(this.rules[n[a]]))&&(!i||e[0].length>i[0].length)){if(i=e,s=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(e,n[a])))return t;if(this._backtrack){i=!1;continue}return!1}if(!this.options.flex)break}return i?!1!==(t=this.test_match(i,n[s]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,h.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,h.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,h.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,h.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,h.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,h.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,h.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,h.K2)((function(t,i,e,s){switch(e){case 0:case 1:case 5:case 43:break;case 2:case 3:return this.popState(),34;case 4:return 34;case 6:return 10;case 7:return this.pushState("acc_title"),19;case 8:return this.popState(),"acc_title_value";case 9:return this.pushState("acc_descr"),21;case 10:return this.popState(),"acc_descr_value";case 11:this.pushState("acc_descr_multiline");break;case 12:case 25:case 27:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 5;case 15:return 8;case 16:return this.pushState("axis_data"),"X_AXIS";case 17:return this.pushState("axis_data"),"Y_AXIS";case 18:return this.pushState("axis_band_data"),24;case 19:return 31;case 20:return this.pushState("data"),16;case 21:return this.pushState("data"),18;case 22:return this.pushState("data_inner"),24;case 23:return 27;case 24:return this.popState(),26;case 26:this.pushState("string");break;case 28:return"STR";case 29:return 24;case 30:return 26;case 31:return 43;case 32:return"COLON";case 33:return 44;case 34:return 28;case 35:return 45;case 36:return 46;case 37:return 48;case 38:return 50;case 39:return 47;case 40:return 41;case 41:return 49;case 42:return 42;case 44:return 35;case 45:return 36}}),"anonymous"),rules:[/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:(\r?\n))/i,/^(?:(\r?\n))/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:title\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:\{)/i,/^(?:[^\}]*)/i,/^(?:xychart-beta\b)/i,/^(?:(?:vertical|horizontal))/i,/^(?:x-axis\b)/i,/^(?:y-axis\b)/i,/^(?:\[)/i,/^(?:-->)/i,/^(?:line\b)/i,/^(?:bar\b)/i,/^(?:\[)/i,/^(?:[+-]?(?:\d+(?:\.\d+)?|\.\d+))/i,/^(?:\])/i,/^(?:(?:`\) \{ this\.pushState\(md_string\); \}\n<md_string>\(\?:\(\?!`"\)\.\)\+ \{ return MD_STR; \}\n<md_string>\(\?:`))/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:\[)/i,/^(?:\])/i,/^(?:[A-Za-z]+)/i,/^(?::)/i,/^(?:\+)/i,/^(?:,)/i,/^(?:=)/i,/^(?:\*)/i,/^(?:#)/i,/^(?:[\_])/i,/^(?:\.)/i,/^(?:&)/i,/^(?:-)/i,/^(?:[0-9]+)/i,/^(?:\s+)/i,/^(?:;)/i,/^(?:$)/i],conditions:{data_inner:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,20,21,23,24,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},data:{rules:[0,1,3,4,5,6,7,9,11,14,15,16,17,20,21,22,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},axis_band_data:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,20,21,24,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},axis_data:{rules:[0,1,2,4,5,6,7,9,11,14,15,16,17,18,19,20,21,23,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0},acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},title:{rules:[],inclusive:!1},md_string:{rules:[],inclusive:!1},string:{rules:[27,28],inclusive:!1},INITIAL:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,20,21,25,26,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],inclusive:!0}}}}();function E(){this.yy={}}return L.lexer=P,(0,h.K2)(E,"Parser"),E.prototype=L,L.Parser=E,new E}();r.parser=r;var l=r;function c(t){return"bar"===t.type}function g(t){return"band"===t.type}function u(t){return"linear"===t.type}(0,h.K2)(c,"isBarPlot"),(0,h.K2)(g,"isBandAxisData"),(0,h.K2)(u,"isLinearAxisData");var x=class{constructor(t){this.parentGroup=t}static{(0,h.K2)(this,"TextDimensionCalculatorWithFont")}getMaxDimension(t,i){if(!this.parentGroup)return{width:t.reduce(((t,i)=>Math.max(i.length,t)),0)*i,height:i};const e={width:0,height:0},n=this.parentGroup.append("g").attr("visibility","hidden").attr("font-size",i);for(const a of t){const t=(0,s.W6)(n,1,a),h=t?t.width:a.length*i,o=t?t.height:i;e.width=Math.max(e.width,h),e.height=Math.max(e.height,o)}return n.remove(),e}},d=class{constructor(t,i,e,s){this.axisConfig=t,this.title=i,this.textDimensionCalculator=e,this.axisThemeConfig=s,this.boundingRect={x:0,y:0,width:0,height:0},this.axisPosition="left",this.showTitle=!1,this.showLabel=!1,this.showTick=!1,this.showAxisLine=!1,this.outerPadding=0,this.titleTextHeight=0,this.labelTextHeight=0,this.range=[0,10],this.boundingRect={x:0,y:0,width:0,height:0},this.axisPosition="left"}static{(0,h.K2)(this,"BaseAxis")}setRange(t){this.range=t,"left"===this.axisPosition||"right"===this.axisPosition?this.boundingRect.height=t[1]-t[0]:this.boundingRect.width=t[1]-t[0],this.recalculateScale()}getRange(){return[this.range[0]+this.outerPadding,this.range[1]-this.outerPadding]}setAxisPosition(t){this.axisPosition=t,this.setRange(this.range)}getTickDistance(){const t=this.getRange();return Math.abs(t[0]-t[1])/this.getTickValues().length}getAxisOuterPadding(){return this.outerPadding}getLabelDimension(){return this.textDimensionCalculator.getMaxDimension(this.getTickValues().map((t=>t.toString())),this.axisConfig.labelFontSize)}recalculateOuterPaddingToDrawBar(){.7*this.getTickDistance()>2*this.outerPadding&&(this.outerPadding=Math.floor(.7*this.getTickDistance()/2)),this.recalculateScale()}calculateSpaceIfDrawnHorizontally(t){let i=t.height;if(this.axisConfig.showAxisLine&&i>this.axisConfig.axisLineWidth&&(i-=this.axisConfig.axisLineWidth,this.showAxisLine=!0),this.axisConfig.showLabel){const e=this.getLabelDimension(),s=.2*t.width;this.outerPadding=Math.min(e.width/2,s);const n=e.height+2*this.axisConfig.labelPadding;this.labelTextHeight=e.height,n<=i&&(i-=n,this.showLabel=!0)}if(this.axisConfig.showTick&&i>=this.axisConfig.tickLength&&(this.showTick=!0,i-=this.axisConfig.tickLength),this.axisConfig.showTitle&&this.title){const t=this.textDimensionCalculator.getMaxDimension([this.title],this.axisConfig.titleFontSize),e=t.height+2*this.axisConfig.titlePadding;this.titleTextHeight=t.height,e<=i&&(i-=e,this.showTitle=!0)}this.boundingRect.width=t.width,this.boundingRect.height=t.height-i}calculateSpaceIfDrawnVertical(t){let i=t.width;if(this.axisConfig.showAxisLine&&i>this.axisConfig.axisLineWidth&&(i-=this.axisConfig.axisLineWidth,this.showAxisLine=!0),this.axisConfig.showLabel){const e=this.getLabelDimension(),s=.2*t.height;this.outerPadding=Math.min(e.height/2,s);const n=e.width+2*this.axisConfig.labelPadding;n<=i&&(i-=n,this.showLabel=!0)}if(this.axisConfig.showTick&&i>=this.axisConfig.tickLength&&(this.showTick=!0,i-=this.axisConfig.tickLength),this.axisConfig.showTitle&&this.title){const t=this.textDimensionCalculator.getMaxDimension([this.title],this.axisConfig.titleFontSize),e=t.height+2*this.axisConfig.titlePadding;this.titleTextHeight=t.height,e<=i&&(i-=e,this.showTitle=!0)}this.boundingRect.width=t.width-i,this.boundingRect.height=t.height}calculateSpace(t){return"left"===this.axisPosition||"right"===this.axisPosition?this.calculateSpaceIfDrawnVertical(t):this.calculateSpaceIfDrawnHorizontally(t),this.recalculateScale(),{width:this.boundingRect.width,height:this.boundingRect.height}}setBoundingBoxXY(t){this.boundingRect.x=t.x,this.boundingRect.y=t.y}getDrawableElementsForLeftAxis(){const t=[];if(this.showAxisLine){const i=this.boundingRect.x+this.boundingRect.width-this.axisConfig.axisLineWidth/2;t.push({type:"path",groupTexts:["left-axis","axisl-line"],data:[{path:`M ${i},${this.boundingRect.y} L ${i},${this.boundingRect.y+this.boundingRect.height} `,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&t.push({type:"text",groupTexts:["left-axis","label"],data:this.getTickValues().map((t=>({text:t.toString(),x:this.boundingRect.x+this.boundingRect.width-(this.showLabel?this.axisConfig.labelPadding:0)-(this.showTick?this.axisConfig.tickLength:0)-(this.showAxisLine?this.axisConfig.axisLineWidth:0),y:this.getScaleValue(t),fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"middle",horizontalPos:"right"})))}),this.showTick){const i=this.boundingRect.x+this.boundingRect.width-(this.showAxisLine?this.axisConfig.axisLineWidth:0);t.push({type:"path",groupTexts:["left-axis","ticks"],data:this.getTickValues().map((t=>({path:`M ${i},${this.getScaleValue(t)} L ${i-this.axisConfig.tickLength},${this.getScaleValue(t)}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth})))})}return this.showTitle&&t.push({type:"text",groupTexts:["left-axis","title"],data:[{text:this.title,x:this.boundingRect.x+this.axisConfig.titlePadding,y:this.boundingRect.y+this.boundingRect.height/2,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:270,verticalPos:"top",horizontalPos:"center"}]}),t}getDrawableElementsForBottomAxis(){const t=[];if(this.showAxisLine){const i=this.boundingRect.y+this.axisConfig.axisLineWidth/2;t.push({type:"path",groupTexts:["bottom-axis","axis-line"],data:[{path:`M ${this.boundingRect.x},${i} L ${this.boundingRect.x+this.boundingRect.width},${i}`,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&t.push({type:"text",groupTexts:["bottom-axis","label"],data:this.getTickValues().map((t=>({text:t.toString(),x:this.getScaleValue(t),y:this.boundingRect.y+this.axisConfig.labelPadding+(this.showTick?this.axisConfig.tickLength:0)+(this.showAxisLine?this.axisConfig.axisLineWidth:0),fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"})))}),this.showTick){const i=this.boundingRect.y+(this.showAxisLine?this.axisConfig.axisLineWidth:0);t.push({type:"path",groupTexts:["bottom-axis","ticks"],data:this.getTickValues().map((t=>({path:`M ${this.getScaleValue(t)},${i} L ${this.getScaleValue(t)},${i+this.axisConfig.tickLength}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth})))})}return this.showTitle&&t.push({type:"text",groupTexts:["bottom-axis","title"],data:[{text:this.title,x:this.range[0]+(this.range[1]-this.range[0])/2,y:this.boundingRect.y+this.boundingRect.height-this.axisConfig.titlePadding-this.titleTextHeight,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}]}),t}getDrawableElementsForTopAxis(){const t=[];if(this.showAxisLine){const i=this.boundingRect.y+this.boundingRect.height-this.axisConfig.axisLineWidth/2;t.push({type:"path",groupTexts:["top-axis","axis-line"],data:[{path:`M ${this.boundingRect.x},${i} L ${this.boundingRect.x+this.boundingRect.width},${i}`,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&t.push({type:"text",groupTexts:["top-axis","label"],data:this.getTickValues().map((t=>({text:t.toString(),x:this.getScaleValue(t),y:this.boundingRect.y+(this.showTitle?this.titleTextHeight+2*this.axisConfig.titlePadding:0)+this.axisConfig.labelPadding,fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"})))}),this.showTick){const i=this.boundingRect.y;t.push({type:"path",groupTexts:["top-axis","ticks"],data:this.getTickValues().map((t=>({path:`M ${this.getScaleValue(t)},${i+this.boundingRect.height-(this.showAxisLine?this.axisConfig.axisLineWidth:0)} L ${this.getScaleValue(t)},${i+this.boundingRect.height-this.axisConfig.tickLength-(this.showAxisLine?this.axisConfig.axisLineWidth:0)}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth})))})}return this.showTitle&&t.push({type:"text",groupTexts:["top-axis","title"],data:[{text:this.title,x:this.boundingRect.x+this.boundingRect.width/2,y:this.boundingRect.y+this.axisConfig.titlePadding,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}]}),t}getDrawableElements(){if("left"===this.axisPosition)return this.getDrawableElementsForLeftAxis();if("right"===this.axisPosition)throw Error("Drawing of right axis is not implemented");return"bottom"===this.axisPosition?this.getDrawableElementsForBottomAxis():"top"===this.axisPosition?this.getDrawableElementsForTopAxis():[]}},p=class extends d{static{(0,h.K2)(this,"BandAxis")}constructor(t,i,e,s,n){super(t,s,n,i),this.categories=e,this.scale=(0,o.WH)().domain(this.categories).range(this.getRange())}setRange(t){super.setRange(t)}recalculateScale(){this.scale=(0,o.WH)().domain(this.categories).range(this.getRange()).paddingInner(1).paddingOuter(0).align(.5),h.Rm.trace("BandAxis axis final categories, range: ",this.categories,this.getRange())}getTickValues(){return this.categories}getScaleValue(t){return this.scale(t)??this.getRange()[0]}},f=class extends d{static{(0,h.K2)(this,"LinearAxis")}constructor(t,i,e,s,n){super(t,s,n,i),this.domain=e,this.scale=(0,o.m4Y)().domain(this.domain).range(this.getRange())}getTickValues(){return this.scale.ticks()}recalculateScale(){const t=[...this.domain];"left"===this.axisPosition&&t.reverse(),this.scale=(0,o.m4Y)().domain(t).range(this.getRange())}getScaleValue(t){return this.scale(t)}};function y(t,i,e,s){const n=new x(s);return g(t)?new p(i,e,t.categories,t.title,n):new f(i,e,[t.min,t.max],t.title,n)}(0,h.K2)(y,"getAxis");var m=class{constructor(t,i,e,s){this.textDimensionCalculator=t,this.chartConfig=i,this.chartData=e,this.chartThemeConfig=s,this.boundingRect={x:0,y:0,width:0,height:0},this.showChartTitle=!1}static{(0,h.K2)(this,"ChartTitle")}setBoundingBoxXY(t){this.boundingRect.x=t.x,this.boundingRect.y=t.y}calculateSpace(t){const i=this.textDimensionCalculator.getMaxDimension([this.chartData.title],this.chartConfig.titleFontSize),e=Math.max(i.width,t.width),s=i.height+2*this.chartConfig.titlePadding;return i.width<=e&&i.height<=s&&this.chartConfig.showTitle&&this.chartData.title&&(this.boundingRect.width=e,this.boundingRect.height=s,this.showChartTitle=!0),{width:this.boundingRect.width,height:this.boundingRect.height}}getDrawableElements(){const t=[];return this.showChartTitle&&t.push({groupTexts:["chart-title"],type:"text",data:[{fontSize:this.chartConfig.titleFontSize,text:this.chartData.title,verticalPos:"middle",horizontalPos:"center",x:this.boundingRect.x+this.boundingRect.width/2,y:this.boundingRect.y+this.boundingRect.height/2,fill:this.chartThemeConfig.titleColor,rotation:0}]}),t}};function b(t,i,e,s){const n=new x(s);return new m(n,t,i,e)}(0,h.K2)(b,"getChartTitleComponent");var A=class{constructor(t,i,e,s,n){this.plotData=t,this.xAxis=i,this.yAxis=e,this.orientation=s,this.plotIndex=n}static{(0,h.K2)(this,"LinePlot")}getDrawableElement(){const t=this.plotData.data.map((t=>[this.xAxis.getScaleValue(t[0]),this.yAxis.getScaleValue(t[1])]));let i;return i="horizontal"===this.orientation?(0,o.n8j)().y((t=>t[0])).x((t=>t[1]))(t):(0,o.n8j)().x((t=>t[0])).y((t=>t[1]))(t),i?[{groupTexts:["plot",`line-plot-${this.plotIndex}`],type:"path",data:[{path:i,strokeFill:this.plotData.strokeFill,strokeWidth:this.plotData.strokeWidth}]}]:[]}},S=class{constructor(t,i,e,s,n,a){this.barData=t,this.boundingRect=i,this.xAxis=e,this.yAxis=s,this.orientation=n,this.plotIndex=a}static{(0,h.K2)(this,"BarPlot")}getDrawableElement(){const t=this.barData.data.map((t=>[this.xAxis.getScaleValue(t[0]),this.yAxis.getScaleValue(t[1])])),i=.95*Math.min(2*this.xAxis.getAxisOuterPadding(),this.xAxis.getTickDistance()),e=i/2;return"horizontal"===this.orientation?[{groupTexts:["plot",`bar-plot-${this.plotIndex}`],type:"rect",data:t.map((t=>({x:this.boundingRect.x,y:t[0]-e,height:i,width:t[1]-this.boundingRect.x,fill:this.barData.fill,strokeWidth:0,strokeFill:this.barData.fill})))}]:[{groupTexts:["plot",`bar-plot-${this.plotIndex}`],type:"rect",data:t.map((t=>({x:t[0]-e,y:t[1],width:i,height:this.boundingRect.y+this.boundingRect.height-t[1],fill:this.barData.fill,strokeWidth:0,strokeFill:this.barData.fill})))}]}},C=class{constructor(t,i,e){this.chartConfig=t,this.chartData=i,this.chartThemeConfig=e,this.boundingRect={x:0,y:0,width:0,height:0}}static{(0,h.K2)(this,"BasePlot")}setAxes(t,i){this.xAxis=t,this.yAxis=i}setBoundingBoxXY(t){this.boundingRect.x=t.x,this.boundingRect.y=t.y}calculateSpace(t){return this.boundingRect.width=t.width,this.boundingRect.height=t.height,{width:this.boundingRect.width,height:this.boundingRect.height}}getDrawableElements(){if(!this.xAxis||!this.yAxis)throw Error("Axes must be passed to render Plots");const t=[];for(const[i,e]of this.chartData.plots.entries())switch(e.type){case"line":{const s=new A(e,this.xAxis,this.yAxis,this.chartConfig.chartOrientation,i);t.push(...s.getDrawableElement())}break;case"bar":{const s=new S(e,this.boundingRect,this.xAxis,this.yAxis,this.chartConfig.chartOrientation,i);t.push(...s.getDrawableElement())}}return t}};function w(t,i,e){return new C(t,i,e)}(0,h.K2)(w,"getPlotComponent");var k,_=class{constructor(t,i,e,s){this.chartConfig=t,this.chartData=i,this.componentStore={title:b(t,i,e,s),plot:w(t,i,e),xAxis:y(i.xAxis,t.xAxis,{titleColor:e.xAxisTitleColor,labelColor:e.xAxisLabelColor,tickColor:e.xAxisTickColor,axisLineColor:e.xAxisLineColor},s),yAxis:y(i.yAxis,t.yAxis,{titleColor:e.yAxisTitleColor,labelColor:e.yAxisLabelColor,tickColor:e.yAxisTickColor,axisLineColor:e.yAxisLineColor},s)}}static{(0,h.K2)(this,"Orchestrator")}calculateVerticalSpace(){let t=this.chartConfig.width,i=this.chartConfig.height,e=0,s=0,n=Math.floor(t*this.chartConfig.plotReservedSpacePercent/100),a=Math.floor(i*this.chartConfig.plotReservedSpacePercent/100),h=this.componentStore.plot.calculateSpace({width:n,height:a});t-=h.width,i-=h.height,h=this.componentStore.title.calculateSpace({width:this.chartConfig.width,height:i}),s=h.height,i-=h.height,this.componentStore.xAxis.setAxisPosition("bottom"),h=this.componentStore.xAxis.calculateSpace({width:t,height:i}),i-=h.height,this.componentStore.yAxis.setAxisPosition("left"),h=this.componentStore.yAxis.calculateSpace({width:t,height:i}),e=h.width,t-=h.width,t>0&&(n+=t,t=0),i>0&&(a+=i,i=0),this.componentStore.plot.calculateSpace({width:n,height:a}),this.componentStore.plot.setBoundingBoxXY({x:e,y:s}),this.componentStore.xAxis.setRange([e,e+n]),this.componentStore.xAxis.setBoundingBoxXY({x:e,y:s+a}),this.componentStore.yAxis.setRange([s,s+a]),this.componentStore.yAxis.setBoundingBoxXY({x:0,y:s}),this.chartData.plots.some((t=>c(t)))&&this.componentStore.xAxis.recalculateOuterPaddingToDrawBar()}calculateHorizontalSpace(){let t=this.chartConfig.width,i=this.chartConfig.height,e=0,s=0,n=0,a=Math.floor(t*this.chartConfig.plotReservedSpacePercent/100),h=Math.floor(i*this.chartConfig.plotReservedSpacePercent/100),o=this.componentStore.plot.calculateSpace({width:a,height:h});t-=o.width,i-=o.height,o=this.componentStore.title.calculateSpace({width:this.chartConfig.width,height:i}),e=o.height,i-=o.height,this.componentStore.xAxis.setAxisPosition("left"),o=this.componentStore.xAxis.calculateSpace({width:t,height:i}),t-=o.width,s=o.width,this.componentStore.yAxis.setAxisPosition("top"),o=this.componentStore.yAxis.calculateSpace({width:t,height:i}),i-=o.height,n=e+o.height,t>0&&(a+=t,t=0),i>0&&(h+=i,i=0),this.componentStore.plot.calculateSpace({width:a,height:h}),this.componentStore.plot.setBoundingBoxXY({x:s,y:n}),this.componentStore.yAxis.setRange([s,s+a]),this.componentStore.yAxis.setBoundingBoxXY({x:s,y:e}),this.componentStore.xAxis.setRange([n,n+h]),this.componentStore.xAxis.setBoundingBoxXY({x:0,y:n}),this.chartData.plots.some((t=>c(t)))&&this.componentStore.xAxis.recalculateOuterPaddingToDrawBar()}calculateSpace(){"horizontal"===this.chartConfig.chartOrientation?this.calculateHorizontalSpace():this.calculateVerticalSpace()}getDrawableElement(){this.calculateSpace();const t=[];this.componentStore.plot.setAxes(this.componentStore.xAxis,this.componentStore.yAxis);for(const i of Object.values(this.componentStore))t.push(...i.getDrawableElements());return t}},T=class{static{(0,h.K2)(this,"XYChartBuilder")}static build(t,i,e,s){return new _(t,i,e,s).getDrawableElement()}},R=0,D=$(),L=I(),P=M(),E=L.plotColorPalette.split(",").map((t=>t.trim())),v=!1,K=!1;function I(){const t=(0,h.P$)(),i=(0,h.zj)();return(0,n.$t)(t.xyChart,i.themeVariables.xyChart)}function $(){const t=(0,h.zj)();return(0,n.$t)(h.UI.xyChart,t.xyChart)}function M(){return{yAxis:{type:"linear",title:"",min:1/0,max:-1/0},xAxis:{type:"band",title:"",categories:[]},title:"",plots:[]}}function B(t){const i=(0,h.zj)();return(0,h.jZ)(t.trim(),i)}function z(t){k=t}function W(t){D.chartOrientation="horizontal"===t?"horizontal":"vertical"}function O(t){P.xAxis.title=B(t.text)}function F(t,i){P.xAxis={type:"linear",title:P.xAxis.title,min:t,max:i},v=!0}function N(t){P.xAxis={type:"band",title:P.xAxis.title,categories:t.map((t=>B(t.text)))},v=!0}function V(t){P.yAxis.title=B(t.text)}function X(t,i){P.yAxis={type:"linear",title:P.yAxis.title,min:t,max:i},K=!0}function Y(t){const i=Math.min(...t),e=Math.max(...t),s=u(P.yAxis)?P.yAxis.min:1/0,n=u(P.yAxis)?P.yAxis.max:-1/0;P.yAxis={type:"linear",title:P.yAxis.title,min:Math.min(s,i),max:Math.max(n,e)}}function U(t){let i=[];if(0===t.length)return i;if(!v){const i=u(P.xAxis)?P.xAxis.min:1/0,e=u(P.xAxis)?P.xAxis.max:-1/0;F(Math.min(i,1),Math.max(e,t.length))}if(K||Y(t),g(P.xAxis)&&(i=P.xAxis.categories.map(((i,e)=>[i,t[e]]))),u(P.xAxis)){const e=P.xAxis.min,s=P.xAxis.max,n=(s-e)/(t.length-1),a=[];for(let t=e;t<=s;t+=n)a.push(`${t}`);i=a.map(((i,e)=>[i,t[e]]))}return i}function H(t){return E[0===t?0:t%E.length]}function j(t,i){const e=U(i);P.plots.push({type:"line",strokeFill:H(R),strokeWidth:2,data:e}),R++}function G(t,i){const e=U(i);P.plots.push({type:"bar",fill:H(R),data:e}),R++}function Q(){if(0===P.plots.length)throw Error("No Plot to render, please provide a plot with some data");return P.title=(0,h.ab)(),T.build(D,P,L,k)}function Z(){return L}function q(){return D}(0,h.K2)(I,"getChartDefaultThemeConfig"),(0,h.K2)($,"getChartDefaultConfig"),(0,h.K2)(M,"getChartDefaultData"),(0,h.K2)(B,"textSanitizer"),(0,h.K2)(z,"setTmpSVGG"),(0,h.K2)(W,"setOrientation"),(0,h.K2)(O,"setXAxisTitle"),(0,h.K2)(F,"setXAxisRangeData"),(0,h.K2)(N,"setXAxisBand"),(0,h.K2)(V,"setYAxisTitle"),(0,h.K2)(X,"setYAxisRangeData"),(0,h.K2)(Y,"setYAxisRangeFromPlotData"),(0,h.K2)(U,"transformDataWithoutCategory"),(0,h.K2)(H,"getPlotColorFromPalette"),(0,h.K2)(j,"setLineData"),(0,h.K2)(G,"setBarData"),(0,h.K2)(Q,"getDrawableElem"),(0,h.K2)(Z,"getChartThemeConfig"),(0,h.K2)(q,"getChartConfig");var J={parser:l,db:{getDrawableElem:Q,clear:(0,h.K2)((function(){(0,h.IU)(),R=0,D=$(),P={yAxis:{type:"linear",title:"",min:1/0,max:-1/0},xAxis:{type:"band",title:"",categories:[]},title:"",plots:[]},L=I(),E=L.plotColorPalette.split(",").map((t=>t.trim())),v=!1,K=!1}),"clear"),setAccTitle:h.SV,getAccTitle:h.iN,setDiagramTitle:h.ke,getDiagramTitle:h.ab,getAccDescription:h.m7,setAccDescription:h.EI,setOrientation:W,setXAxisTitle:O,setXAxisRangeData:F,setXAxisBand:N,setYAxisTitle:V,setYAxisRangeData:X,setLineData:j,setBarData:G,setTmpSVGG:z,getChartThemeConfig:Z,getChartConfig:q},renderer:{draw:(0,h.K2)(((t,i,e,s)=>{const n=s.db,o=n.getChartThemeConfig(),r=n.getChartConfig();function l(t){return"top"===t?"text-before-edge":"middle"}function c(t){return"left"===t?"start":"right"===t?"end":"middle"}function g(t){return`translate(${t.x}, ${t.y}) rotate(${t.rotation||0})`}(0,h.K2)(l,"getDominantBaseLine"),(0,h.K2)(c,"getTextAnchor"),(0,h.K2)(g,"getTextTransformation"),h.Rm.debug("Rendering xychart chart\n"+t);const u=(0,a.D)(i),x=u.append("g").attr("class","main"),d=x.append("rect").attr("width",r.width).attr("height",r.height).attr("class","background");(0,h.a$)(u,r.height,r.width,!0),u.attr("viewBox",`0 0 ${r.width} ${r.height}`),d.attr("fill",o.backgroundColor),n.setTmpSVGG(u.append("g").attr("class","mermaid-tmp-group"));const p=n.getDrawableElem(),f={};function y(t){let i=x,e="";for(const[s]of t.entries()){let n=x;s>0&&f[e]&&(n=f[e]),e+=t[s],i=f[e],i||(i=f[e]=n.append("g").attr("class",t[s]))}return i}(0,h.K2)(y,"getGroup");for(const a of p){if(0===a.data.length)continue;const t=y(a.groupTexts);switch(a.type){case"rect":t.selectAll("rect").data(a.data).enter().append("rect").attr("x",(t=>t.x)).attr("y",(t=>t.y)).attr("width",(t=>t.width)).attr("height",(t=>t.height)).attr("fill",(t=>t.fill)).attr("stroke",(t=>t.strokeFill)).attr("stroke-width",(t=>t.strokeWidth));break;case"text":t.selectAll("text").data(a.data).enter().append("text").attr("x",0).attr("y",0).attr("fill",(t=>t.fill)).attr("font-size",(t=>t.fontSize)).attr("dominant-baseline",(t=>l(t.verticalPos))).attr("text-anchor",(t=>c(t.horizontalPos))).attr("transform",(t=>g(t))).text((t=>t.text));break;case"path":t.selectAll("path").data(a.data).enter().append("path").attr("d",(t=>t.path)).attr("fill",(t=>t.fill?t.fill:"none")).attr("stroke",(t=>t.strokeFill)).attr("stroke-width",(t=>t.strokeWidth))}}}),"draw")}}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/54c6367b.1dffaa95.js b/pr-preview/pr-1071/assets/js/54c6367b.1dffaa95.js deleted file mode 100644 index ae2586dd02..0000000000 --- a/pr-preview/pr-1071/assets/js/54c6367b.1dffaa95.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5999],{84608:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"components/service-mesh","title":"Service Mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-0.6/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/components/service-mesh.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.6/components/policies"},"next":{"title":"Architecture","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/"}}');var s=t(74848),r=t(28453);const o={},c="Service Mesh",a={},h=[{value:"Configuring the Proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"service-mesh",children:"Service Mesh"})}),"\n",(0,s.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The service mesh can be enabled on a per-pod basis by adding the ",(0,s.jsx)(n.code,{children:"service-mesh"}),"\ncontainer as a ",(0,s.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar container"}),".\nThe service mesh container first sets up ",(0,s.jsx)(n.code,{children:"iptables"}),"\nrules based on its configuration and then starts ",(0,s.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"}),"\nfor TLS origination and termination."]}),"\n",(0,s.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the Proxy"}),"\n",(0,s.jsxs)(n.p,{children:["The service mesh container can be configured using the ",(0,s.jsx)(n.code,{children:"EDG_INGRESS_PROXY_CONFIG"}),"\nand ",(0,s.jsx)(n.code,{children:"EDG_EGRESS_PROXY_CONFIG"})," environment variables."]}),"\n",(0,s.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,s.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,s.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,s.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,s.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the environment variable ",(0,s.jsx)(n.code,{children:"EDG_INGRESS_PROXY_CONFIG"})," as\n",(0,s.jsx)(n.code,{children:"<name>#<port>#false"}),". Separate multiple entries with ",(0,s.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the\ninformational-only field ",(0,s.jsx)(n.code,{children:"<name>"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,s.jsx)(n.code,{children:"<name>#<port>#true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,s.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n initContainers:\n - name: initializer\n image: "ghcr.io/edgelesssys/contrast/initializer@sha256:..."\n env:\n - name: COORDINATOR_HOST\n value: coordinator\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n - name: sidecar\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy@sha256:..."\n restartPolicy: Always\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n env:\n - name: EDG_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n securityContext:\n privileged: true\n capabilities:\n add:\n - NET_ADMIN\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n volumes:\n - name: tls-certs\n emptyDir: {}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,s.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,s.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,s.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,s.jsxs)(n.li,{children:["Set ",(0,s.jsx)(n.code,{children:"<name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port>"}),"\nas ",(0,s.jsx)(n.code,{children:"EDG_EGRESS_PROXY_CONFIG"}),". Separate multiple entries with ",(0,s.jsx)(n.code,{children:"##"}),". Choose any\nstring identifying the service on the given port as ",(0,s.jsx)(n.code,{children:"<name>"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,s.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are themselves part\nof the confidential deployment. One is reachable under ",(0,s.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,s.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n initContainers:\n - name: initializer\n image: "ghcr.io/edgelesssys/contrast/initializer@sha256:..."\n env:\n - name: COORDINATOR_HOST\n value: coordinator\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n - name: sidecar\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy@sha256:..."\n restartPolicy: Always\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n env:\n - name: EDG_EGRESS_PROXY_CONFIG\n value: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\n securityContext:\n privileged: true\n capabilities:\n add:\n - NET_ADMIN\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n volumes:\n - name: tls-certs\n emptyDir: {}\n'})})]})}function d(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var i=t(96540);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/567e04ee.a3475875.js b/pr-preview/pr-1071/assets/js/567e04ee.a3475875.js deleted file mode 100644 index ac5fccacab..0000000000 --- a/pr-preview/pr-1071/assets/js/567e04ee.a3475875.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6440],{71871:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-0.6/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/0.6/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/components/policies.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.6/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh"}}');var s=n(74848),o=n(28453);const r={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(96540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5978.63ed3047.js b/pr-preview/pr-1071/assets/js/5978.63ed3047.js deleted file mode 100644 index 71cba18b7e..0000000000 --- a/pr-preview/pr-1071/assets/js/5978.63ed3047.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5978],{98160:(t,r,e)=>{e.d(r,{m:()=>o});var n=e(10009),o=class{constructor(t){this.init=t,this.records=this.init()}static{(0,n.K2)(this,"ImperativeState")}reset(){this.records=this.init()}}},63933:(t,r,e)=>{function n(t,r){t.accDescr&&r.setAccDescription?.(t.accDescr),t.accTitle&&r.setAccTitle?.(t.accTitle),t.title&&r.setDiagramTitle?.(t.title)}e.d(r,{S:()=>n}),(0,e(10009).K2)(n,"populateCommonDb")},45978:(t,r,e)=>{e.d(r,{diagram:()=>ft});var n=e(63933),o=e(98160),a=e(8159),c=e(10009),s=e(78731),i=e(20007),h={NORMAL:0,REVERSE:1,HIGHLIGHT:2,MERGE:3,CHERRY_PICK:4},d=c.UI.gitGraph,m=(0,c.K2)((()=>(0,a.$t)({...d,...(0,c.zj)().gitGraph})),"getConfig"),$=new o.m((()=>{const t=m(),r=t.mainBranchName,e=t.mainBranchOrder;return{mainBranchName:r,commits:new Map,head:null,branchConfig:new Map([[r,{name:r,order:e}]]),branches:new Map([[r,null]]),currBranch:r,direction:"LR",seq:0,options:{}}}));function l(){return(0,a.yT)({length:7})}function y(t,r){const e=Object.create(null);return t.reduce(((t,n)=>{const o=r(n);return e[o]||(e[o]=!0,t.push(n)),t}),[])}(0,c.K2)(l,"getID"),(0,c.K2)(y,"uniqBy");var g=(0,c.K2)((function(t){$.records.direction=t}),"setDirection"),p=(0,c.K2)((function(t){c.Rm.debug("options str",t),t=t?.trim(),t=t||"{}";try{$.records.options=JSON.parse(t)}catch(r){c.Rm.error("error while parsing gitGraph options",r.message)}}),"setOptions"),x=(0,c.K2)((function(){return $.records.options}),"getOptions"),f=(0,c.K2)((function(t){let r=t.msg,e=t.id;const n=t.type;let o=t.tags;c.Rm.info("commit",r,e,n,o),c.Rm.debug("Entering commit:",r,e,n,o);const a=m();e=c.Y2.sanitizeText(e,a),r=c.Y2.sanitizeText(r,a),o=o?.map((t=>c.Y2.sanitizeText(t,a)));const s={id:e||$.records.seq+"-"+l(),message:r,seq:$.records.seq++,type:n??h.NORMAL,tags:o??[],parents:null==$.records.head?[]:[$.records.head.id],branch:$.records.currBranch};$.records.head=s,c.Rm.info("main branch",a.mainBranchName),$.records.commits.set(s.id,s),$.records.branches.set($.records.currBranch,s.id),c.Rm.debug("in pushCommit "+s.id)}),"commit"),u=(0,c.K2)((function(t){let r=t.name;const e=t.order;if(r=c.Y2.sanitizeText(r,m()),$.records.branches.has(r))throw new Error(`Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ${r}")`);$.records.branches.set(r,null!=$.records.head?$.records.head.id:null),$.records.branchConfig.set(r,{name:r,order:e}),B(r),c.Rm.debug("in createBranch")}),"branch"),b=(0,c.K2)((t=>{let r=t.branch,e=t.id;const n=t.type,o=t.tags,a=m();r=c.Y2.sanitizeText(r,a),e&&(e=c.Y2.sanitizeText(e,a));const s=$.records.branches.get($.records.currBranch),i=$.records.branches.get(r),d=s?$.records.commits.get(s):void 0,y=i?$.records.commits.get(i):void 0;if(d&&y&&d.branch===r)throw new Error(`Cannot merge branch '${r}' into itself.`);if($.records.currBranch===r){const t=new Error('Incorrect usage of "merge". Cannot merge a branch to itself');throw t.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["branch abc"]},t}if(void 0===d||!d){const t=new Error(`Incorrect usage of "merge". Current branch (${$.records.currBranch})has no commits`);throw t.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["commit"]},t}if(!$.records.branches.has(r)){const t=new Error('Incorrect usage of "merge". Branch to be merged ('+r+") does not exist");throw t.hash={text:`merge ${r}`,token:`merge ${r}`,expected:[`branch ${r}`]},t}if(void 0===y||!y){const t=new Error('Incorrect usage of "merge". Branch to be merged ('+r+") has no commits");throw t.hash={text:`merge ${r}`,token:`merge ${r}`,expected:['"commit"']},t}if(d===y){const t=new Error('Incorrect usage of "merge". Both branches have same head');throw t.hash={text:`merge ${r}`,token:`merge ${r}`,expected:["branch abc"]},t}if(e&&$.records.commits.has(e)){const t=new Error('Incorrect usage of "merge". Commit with id:'+e+" already exists, use different custom Id");throw t.hash={text:`merge ${r} ${e} ${n} ${o?.join(" ")}`,token:`merge ${r} ${e} ${n} ${o?.join(" ")}`,expected:[`merge ${r} ${e}_UNIQUE ${n} ${o?.join(" ")}`]},t}const g=i||"",p={id:e||`${$.records.seq}-${l()}`,message:`merged branch ${r} into ${$.records.currBranch}`,seq:$.records.seq++,parents:null==$.records.head?[]:[$.records.head.id,g],branch:$.records.currBranch,type:h.MERGE,customType:n,customId:!!e,tags:o??[]};$.records.head=p,$.records.commits.set(p.id,p),$.records.branches.set($.records.currBranch,p.id),c.Rm.debug($.records.branches),c.Rm.debug("in mergeBranch")}),"merge"),w=(0,c.K2)((function(t){let r=t.id,e=t.targetId,n=t.tags,o=t.parent;c.Rm.debug("Entering cherryPick:",r,e,n);const a=m();if(r=c.Y2.sanitizeText(r,a),e=c.Y2.sanitizeText(e,a),n=n?.map((t=>c.Y2.sanitizeText(t,a))),o=c.Y2.sanitizeText(o,a),!r||!$.records.commits.has(r)){const t=new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');throw t.hash={text:`cherryPick ${r} ${e}`,token:`cherryPick ${r} ${e}`,expected:["cherry-pick abc"]},t}const s=$.records.commits.get(r);if(void 0===s||!s)throw new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');if(o&&(!Array.isArray(s.parents)||!s.parents.includes(o))){throw new Error("Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.")}const i=s.branch;if(s.type===h.MERGE&&!o){throw new Error("Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.")}if(!e||!$.records.commits.has(e)){if(i===$.records.currBranch){const t=new Error('Incorrect usage of "cherryPick". Source commit is already on current branch');throw t.hash={text:`cherryPick ${r} ${e}`,token:`cherryPick ${r} ${e}`,expected:["cherry-pick abc"]},t}const t=$.records.branches.get($.records.currBranch);if(void 0===t||!t){const t=new Error(`Incorrect usage of "cherry-pick". Current branch (${$.records.currBranch})has no commits`);throw t.hash={text:`cherryPick ${r} ${e}`,token:`cherryPick ${r} ${e}`,expected:["cherry-pick abc"]},t}const a=$.records.commits.get(t);if(void 0===a||!a){const t=new Error(`Incorrect usage of "cherry-pick". Current branch (${$.records.currBranch})has no commits`);throw t.hash={text:`cherryPick ${r} ${e}`,token:`cherryPick ${r} ${e}`,expected:["cherry-pick abc"]},t}const d={id:$.records.seq+"-"+l(),message:`cherry-picked ${s?.message} into ${$.records.currBranch}`,seq:$.records.seq++,parents:null==$.records.head?[]:[$.records.head.id,s.id],branch:$.records.currBranch,type:h.CHERRY_PICK,tags:n?n.filter(Boolean):[`cherry-pick:${s.id}${s.type===h.MERGE?`|parent:${o}`:""}`]};$.records.head=d,$.records.commits.set(d.id,d),$.records.branches.set($.records.currBranch,d.id),c.Rm.debug($.records.branches),c.Rm.debug("in cherryPick")}}),"cherryPick"),B=(0,c.K2)((function(t){if(t=c.Y2.sanitizeText(t,m()),!$.records.branches.has(t)){const r=new Error(`Trying to checkout branch which is not yet created. (Help try using "branch ${t}")`);throw r.hash={text:`checkout ${t}`,token:`checkout ${t}`,expected:[`branch ${t}`]},r}{$.records.currBranch=t;const r=$.records.branches.get($.records.currBranch);$.records.head=void 0!==r&&r?$.records.commits.get(r)??null:null}}),"checkout");function E(t,r,e){const n=t.indexOf(r);-1===n?t.push(e):t.splice(n,1,e)}function k(t){const r=t.reduce(((t,r)=>t.seq>r.seq?t:r),t[0]);let e="";t.forEach((function(t){e+=t===r?"\t*":"\t|"}));const n=[e,r.id,r.seq];for(const o in $.records.branches)$.records.branches.get(o)===r.id&&n.push(o);if(c.Rm.debug(n.join(" ")),r.parents&&2==r.parents.length&&r.parents[0]&&r.parents[1]){const e=$.records.commits.get(r.parents[0]);E(t,r,e),r.parents[1]&&t.push($.records.commits.get(r.parents[1]))}else{if(0==r.parents.length)return;if(r.parents[0]){const e=$.records.commits.get(r.parents[0]);E(t,r,e)}}k(t=y(t,(t=>t.id)))}(0,c.K2)(E,"upsert"),(0,c.K2)(k,"prettyPrintCommitHistory");var C=(0,c.K2)((function(){c.Rm.debug($.records.commits);k([R()[0]])}),"prettyPrint"),T=(0,c.K2)((function(){$.reset(),(0,c.IU)()}),"clear"),L=(0,c.K2)((function(){return[...$.records.branchConfig.values()].map(((t,r)=>null!==t.order&&void 0!==t.order?t:{...t,order:parseFloat(`0.${r}`)})).sort(((t,r)=>(t.order??0)-(r.order??0))).map((({name:t})=>({name:t})))}),"getBranchesAsObjArray"),K=(0,c.K2)((function(){return $.records.branches}),"getBranches"),M=(0,c.K2)((function(){return $.records.commits}),"getCommits"),R=(0,c.K2)((function(){const t=[...$.records.commits.values()];return t.forEach((function(t){c.Rm.debug(t.id)})),t.sort(((t,r)=>t.seq-r.seq)),t}),"getCommitsArray"),v={commitType:h,getConfig:m,setDirection:g,setOptions:p,getOptions:x,commit:f,branch:u,merge:b,cherryPick:w,checkout:B,prettyPrint:C,clear:T,getBranchesAsObjArray:L,getBranches:K,getCommits:M,getCommitsArray:R,getCurrentBranch:(0,c.K2)((function(){return $.records.currBranch}),"getCurrentBranch"),getDirection:(0,c.K2)((function(){return $.records.direction}),"getDirection"),getHead:(0,c.K2)((function(){return $.records.head}),"getHead"),setAccTitle:c.SV,getAccTitle:c.iN,getAccDescription:c.m7,setAccDescription:c.EI,setDiagramTitle:c.ke,getDiagramTitle:c.ab},P=(0,c.K2)(((t,r)=>{(0,n.S)(t,r),t.dir&&r.setDirection(t.dir);for(const e of t.statements)I(e,r)}),"populate"),I=(0,c.K2)(((t,r)=>{const e={Commit:(0,c.K2)((t=>r.commit(A(t))),"Commit"),Branch:(0,c.K2)((t=>r.branch(G(t))),"Branch"),Merge:(0,c.K2)((t=>r.merge(O(t))),"Merge"),Checkout:(0,c.K2)((t=>r.checkout(q(t))),"Checkout"),CherryPicking:(0,c.K2)((t=>r.cherryPick(z(t))),"CherryPicking")}[t.$type];e?e(t):c.Rm.error(`Unknown statement type: ${t.$type}`)}),"parseStatement"),A=(0,c.K2)((t=>({id:t.id,msg:t.message??"",type:void 0!==t.type?h[t.type]:h.NORMAL,tags:t.tags??void 0})),"parseCommit"),G=(0,c.K2)((t=>({name:t.name,order:t.order??0})),"parseBranch"),O=(0,c.K2)((t=>({branch:t.branch,id:t.id??"",type:void 0!==t.type?h[t.type]:void 0,tags:t.tags??void 0})),"parseMerge"),q=(0,c.K2)((t=>t.branch),"parseCheckout"),z=(0,c.K2)((t=>({id:t.id,targetId:"",tags:0===t.tags?.length?void 0:t.tags,parent:t.parent})),"parseCherryPicking"),H={parse:(0,c.K2)((async t=>{const r=await(0,s.qg)("gitGraph",t);c.Rm.debug(r),P(r,v)}),"parse")};var S=(0,c.D7)(),D=S?.gitGraph,Y=10,N=40,j=new Map,W=new Map,_=new Map,F=[],U=0,V="LR",J=(0,c.K2)((()=>{j.clear(),W.clear(),_.clear(),U=0,F=[],V="LR"}),"clear"),Q=(0,c.K2)((t=>{const r=document.createElementNS("http://www.w3.org/2000/svg","text");return("string"==typeof t?t.split(/\\n|\n|<br\s*\/?>/gi):t).forEach((t=>{const e=document.createElementNS("http://www.w3.org/2000/svg","tspan");e.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),e.setAttribute("dy","1em"),e.setAttribute("x","0"),e.setAttribute("class","row"),e.textContent=t.trim(),r.appendChild(e)})),r}),"drawText"),X=(0,c.K2)((t=>{let r,e,n;return"BT"===V?(e=(0,c.K2)(((t,r)=>t<=r),"comparisonFunc"),n=1/0):(e=(0,c.K2)(((t,r)=>t>=r),"comparisonFunc"),n=0),t.forEach((t=>{const o="TB"===V||"BT"==V?W.get(t)?.y:W.get(t)?.x;void 0!==o&&e(o,n)&&(r=t,n=o)})),r}),"findClosestParent"),Z=(0,c.K2)((t=>{let r="",e=1/0;return t.forEach((t=>{const n=W.get(t).y;n<=e&&(r=t,e=n)})),r||void 0}),"findClosestParentBT"),tt=(0,c.K2)(((t,r,e)=>{let n=e,o=e;const a=[];t.forEach((t=>{const e=r.get(t);if(!e)throw new Error(`Commit not found for key ${t}`);e.parents.length?(n=et(e),o=Math.max(n,o)):a.push(e),nt(e,n)})),n=o,a.forEach((t=>{ot(t,n,e)})),t.forEach((t=>{const e=r.get(t);if(e?.parents.length){const t=Z(e.parents);n=W.get(t).y-N,n<=o&&(o=n);const r=j.get(e.branch).pos,a=n-Y;W.set(e.id,{x:r,y:a})}}))}),"setParallelBTPos"),rt=(0,c.K2)((t=>{const r=X(t.parents.filter((t=>null!==t)));if(!r)throw new Error(`Closest parent not found for commit ${t.id}`);const e=W.get(r)?.y;if(void 0===e)throw new Error(`Closest parent position not found for commit ${t.id}`);return e}),"findClosestParentPos"),et=(0,c.K2)((t=>rt(t)+N),"calculateCommitPosition"),nt=(0,c.K2)(((t,r)=>{const e=j.get(t.branch);if(!e)throw new Error(`Branch not found for commit ${t.id}`);const n=e.pos,o=r+Y;return W.set(t.id,{x:n,y:o}),{x:n,y:o}}),"setCommitPosition"),ot=(0,c.K2)(((t,r,e)=>{const n=j.get(t.branch);if(!n)throw new Error(`Branch not found for commit ${t.id}`);const o=r+e,a=n.pos;W.set(t.id,{x:a,y:o})}),"setRootPosition"),at=(0,c.K2)(((t,r,e,n,o,a)=>{if(a===h.HIGHLIGHT)t.append("rect").attr("x",e.x-10).attr("y",e.y-10).attr("width",20).attr("height",20).attr("class",`commit ${r.id} commit-highlight${o%8} ${n}-outer`),t.append("rect").attr("x",e.x-6).attr("y",e.y-6).attr("width",12).attr("height",12).attr("class",`commit ${r.id} commit${o%8} ${n}-inner`);else if(a===h.CHERRY_PICK)t.append("circle").attr("cx",e.x).attr("cy",e.y).attr("r",10).attr("class",`commit ${r.id} ${n}`),t.append("circle").attr("cx",e.x-3).attr("cy",e.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${r.id} ${n}`),t.append("circle").attr("cx",e.x+3).attr("cy",e.y+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${r.id} ${n}`),t.append("line").attr("x1",e.x+3).attr("y1",e.y+1).attr("x2",e.x).attr("y2",e.y-5).attr("stroke","#fff").attr("class",`commit ${r.id} ${n}`),t.append("line").attr("x1",e.x-3).attr("y1",e.y+1).attr("x2",e.x).attr("y2",e.y-5).attr("stroke","#fff").attr("class",`commit ${r.id} ${n}`);else{const c=t.append("circle");if(c.attr("cx",e.x),c.attr("cy",e.y),c.attr("r",r.type===h.MERGE?9:10),c.attr("class",`commit ${r.id} commit${o%8}`),a===h.MERGE){const a=t.append("circle");a.attr("cx",e.x),a.attr("cy",e.y),a.attr("r",6),a.attr("class",`commit ${n} ${r.id} commit${o%8}`)}if(a===h.REVERSE){t.append("path").attr("d",`M ${e.x-5},${e.y-5}L${e.x+5},${e.y+5}M${e.x-5},${e.y+5}L${e.x+5},${e.y-5}`).attr("class",`commit ${n} ${r.id} commit${o%8}`)}}}),"drawCommitBullet"),ct=(0,c.K2)(((t,r,e,n)=>{if(r.type!==h.CHERRY_PICK&&(r.customId&&r.type===h.MERGE||r.type!==h.MERGE)&&D?.showCommitLabel){const o=t.append("g"),a=o.insert("rect").attr("class","commit-label-bkg"),c=o.append("text").attr("x",n).attr("y",e.y+25).attr("class","commit-label").text(r.id),s=c.node()?.getBBox();if(s&&(a.attr("x",e.posWithOffset-s.width/2-2).attr("y",e.y+13.5).attr("width",s.width+4).attr("height",s.height+4),"TB"===V||"BT"===V?(a.attr("x",e.x-(s.width+16+5)).attr("y",e.y-12),c.attr("x",e.x-(s.width+16)).attr("y",e.y+s.height-12)):c.attr("x",e.posWithOffset-s.width/2),D.rotateCommitLabel))if("TB"===V||"BT"===V)c.attr("transform","rotate(-45, "+e.x+", "+e.y+")"),a.attr("transform","rotate(-45, "+e.x+", "+e.y+")");else{const t=-7.5-(s.width+10)/25*9.5,r=10+s.width/25*8.5;o.attr("transform","translate("+t+", "+r+") rotate(-45, "+n+", "+e.y+")")}}}),"drawCommitLabel"),st=(0,c.K2)(((t,r,e,n)=>{if(r.tags.length>0){let o=0,a=0,c=0;const s=[];for(const n of r.tags.reverse()){const r=t.insert("polygon"),i=t.append("circle"),h=t.append("text").attr("y",e.y-16-o).attr("class","tag-label").text(n),d=h.node()?.getBBox();if(!d)throw new Error("Tag bbox not found");a=Math.max(a,d.width),c=Math.max(c,d.height),h.attr("x",e.posWithOffset-d.width/2),s.push({tag:h,hole:i,rect:r,yOffset:o}),o+=20}for(const{tag:t,hole:r,rect:i,yOffset:h}of s){const o=c/2,s=e.y-19.2-h;if(i.attr("class","tag-label-bkg").attr("points",`\n ${n-a/2-2},${s+2} \n ${n-a/2-2},${s-2}\n ${e.posWithOffset-a/2-4},${s-o-2}\n ${e.posWithOffset+a/2+4},${s-o-2}\n ${e.posWithOffset+a/2+4},${s+o+2}\n ${e.posWithOffset-a/2-4},${s+o+2}`),r.attr("cy",s).attr("cx",n-a/2+2).attr("r",1.5).attr("class","tag-hole"),"TB"===V||"BT"===V){const c=n+h;i.attr("class","tag-label-bkg").attr("points",`\n ${e.x},${c+2}\n ${e.x},${c-2}\n ${e.x+Y},${c-o-2}\n ${e.x+Y+a+4},${c-o-2}\n ${e.x+Y+a+4},${c+o+2}\n ${e.x+Y},${c+o+2}`).attr("transform","translate(12,12) rotate(45, "+e.x+","+n+")"),r.attr("cx",e.x+2).attr("cy",c).attr("transform","translate(12,12) rotate(45, "+e.x+","+n+")"),t.attr("x",e.x+5).attr("y",c+3).attr("transform","translate(14,14) rotate(45, "+e.x+","+n+")")}}}}),"drawCommitTags"),it=(0,c.K2)((t=>{switch(t.customType??t.type){case h.NORMAL:return"commit-normal";case h.REVERSE:return"commit-reverse";case h.HIGHLIGHT:return"commit-highlight";case h.MERGE:return"commit-merge";case h.CHERRY_PICK:return"commit-cherry-pick";default:return"commit-normal"}}),"getCommitClassType"),ht=(0,c.K2)(((t,r,e,n)=>{const o={x:0,y:0};if(!(t.parents.length>0)){if("TB"===r)return 30;if("BT"===r){return(n.get(t.id)??o).y-N}return 0}{const e=X(t.parents);if(e){const a=n.get(e)??o;if("TB"===r)return a.y+N;if("BT"===r){return(n.get(t.id)??o).y-N}return a.x+N}}return 0}),"calculatePosition"),dt=(0,c.K2)(((t,r,e)=>{const n="BT"===V&&e?r:r+Y,o="TB"===V||"BT"===V?n:j.get(t.branch)?.pos,a="TB"===V||"BT"===V?j.get(t.branch)?.pos:n;if(void 0===a||void 0===o)throw new Error(`Position were undefined for commit ${t.id}`);return{x:a,y:o,posWithOffset:n}}),"getCommitPosition"),mt=(0,c.K2)(((t,r,e)=>{if(!D)throw new Error("GitGraph config not found");const n=t.append("g").attr("class","commit-bullets"),o=t.append("g").attr("class","commit-labels");let a="TB"===V||"BT"===V?30:0;const s=[...r.keys()],i=D?.parallelCommits??!1,h=(0,c.K2)(((t,e)=>{const n=r.get(t)?.seq,o=r.get(e)?.seq;return void 0!==n&&void 0!==o?n-o:0}),"sortKeys");let d=s.sort(h);"BT"===V&&(i&&tt(d,r,a),d=d.reverse()),d.forEach((t=>{const c=r.get(t);if(!c)throw new Error(`Commit not found for key ${t}`);i&&(a=ht(c,V,a,W));const s=dt(c,a,i);if(e){const t=it(c),r=c.customType??c.type,e=j.get(c.branch)?.index??0;at(n,c,s,t,e,r),ct(o,c,s,a),st(o,c,s,a)}"TB"===V||"BT"===V?W.set(c.id,{x:s.x,y:s.posWithOffset}):W.set(c.id,{x:s.posWithOffset,y:s.y}),a="BT"===V&&i?a+N:a+N+Y,a>U&&(U=a)}))}),"drawCommits"),$t=(0,c.K2)(((t,r,e,n,o)=>{const a=("TB"===V||"BT"===V?e.x<n.x:e.y<n.y)?r.branch:t.branch,s=(0,c.K2)((t=>t.branch===a),"isOnBranchToGetCurve"),i=(0,c.K2)((e=>e.seq>t.seq&&e.seq<r.seq),"isBetweenCommits");return[...o.values()].some((t=>i(t)&&s(t)))}),"shouldRerouteArrow"),lt=(0,c.K2)(((t,r,e=0)=>{const n=t+Math.abs(t-r)/2;if(e>5)return n;if(F.every((t=>Math.abs(t-n)>=10)))return F.push(n),n;const o=Math.abs(t-r);return lt(t,r-o/5,e+1)}),"findLane"),yt=(0,c.K2)(((t,r,e,n)=>{const o=W.get(r.id),a=W.get(e.id);if(void 0===o||void 0===a)throw new Error(`Commit positions not found for commits ${r.id} and ${e.id}`);const c=$t(r,e,o,a,n);let s,i="",d="",m=0,$=0,l=j.get(e.branch)?.index;if(e.type===h.MERGE&&r.id!==e.parents[0]&&(l=j.get(r.branch)?.index),c){i="A 10 10, 0, 0, 0,",d="A 10 10, 0, 0, 1,",m=10,$=10;const t=o.y<a.y?lt(o.y,a.y):lt(a.y,o.y),e=o.x<a.x?lt(o.x,a.x):lt(a.x,o.x);"TB"===V?o.x<a.x?s=`M ${o.x} ${o.y} L ${e-m} ${o.y} ${d} ${e} ${o.y+$} L ${e} ${a.y-m} ${i} ${e+$} ${a.y} L ${a.x} ${a.y}`:(l=j.get(r.branch)?.index,s=`M ${o.x} ${o.y} L ${e+m} ${o.y} ${i} ${e} ${o.y+$} L ${e} ${a.y-m} ${d} ${e-$} ${a.y} L ${a.x} ${a.y}`):"BT"===V?o.x<a.x?s=`M ${o.x} ${o.y} L ${e-m} ${o.y} ${i} ${e} ${o.y-$} L ${e} ${a.y+m} ${d} ${e+$} ${a.y} L ${a.x} ${a.y}`:(l=j.get(r.branch)?.index,s=`M ${o.x} ${o.y} L ${e+m} ${o.y} ${d} ${e} ${o.y-$} L ${e} ${a.y+m} ${i} ${e-$} ${a.y} L ${a.x} ${a.y}`):o.y<a.y?s=`M ${o.x} ${o.y} L ${o.x} ${t-m} ${i} ${o.x+$} ${t} L ${a.x-m} ${t} ${d} ${a.x} ${t+$} L ${a.x} ${a.y}`:(l=j.get(r.branch)?.index,s=`M ${o.x} ${o.y} L ${o.x} ${t+m} ${d} ${o.x+$} ${t} L ${a.x-m} ${t} ${i} ${a.x} ${t-$} L ${a.x} ${a.y}`)}else i="A 20 20, 0, 0, 0,",d="A 20 20, 0, 0, 1,",m=20,$=20,"TB"===V?(o.x<a.x&&(s=e.type===h.MERGE&&r.id!==e.parents[0]?`M ${o.x} ${o.y} L ${o.x} ${a.y-m} ${i} ${o.x+$} ${a.y} L ${a.x} ${a.y}`:`M ${o.x} ${o.y} L ${a.x-m} ${o.y} ${d} ${a.x} ${o.y+$} L ${a.x} ${a.y}`),o.x>a.x&&(i="A 20 20, 0, 0, 0,",d="A 20 20, 0, 0, 1,",m=20,$=20,s=e.type===h.MERGE&&r.id!==e.parents[0]?`M ${o.x} ${o.y} L ${o.x} ${a.y-m} ${d} ${o.x-$} ${a.y} L ${a.x} ${a.y}`:`M ${o.x} ${o.y} L ${a.x+m} ${o.y} ${i} ${a.x} ${o.y+$} L ${a.x} ${a.y}`),o.x===a.x&&(s=`M ${o.x} ${o.y} L ${a.x} ${a.y}`)):"BT"===V?(o.x<a.x&&(s=e.type===h.MERGE&&r.id!==e.parents[0]?`M ${o.x} ${o.y} L ${o.x} ${a.y+m} ${d} ${o.x+$} ${a.y} L ${a.x} ${a.y}`:`M ${o.x} ${o.y} L ${a.x-m} ${o.y} ${i} ${a.x} ${o.y-$} L ${a.x} ${a.y}`),o.x>a.x&&(i="A 20 20, 0, 0, 0,",d="A 20 20, 0, 0, 1,",m=20,$=20,s=e.type===h.MERGE&&r.id!==e.parents[0]?`M ${o.x} ${o.y} L ${o.x} ${a.y+m} ${i} ${o.x-$} ${a.y} L ${a.x} ${a.y}`:`M ${o.x} ${o.y} L ${a.x-m} ${o.y} ${i} ${a.x} ${o.y-$} L ${a.x} ${a.y}`),o.x===a.x&&(s=`M ${o.x} ${o.y} L ${a.x} ${a.y}`)):(o.y<a.y&&(s=e.type===h.MERGE&&r.id!==e.parents[0]?`M ${o.x} ${o.y} L ${a.x-m} ${o.y} ${d} ${a.x} ${o.y+$} L ${a.x} ${a.y}`:`M ${o.x} ${o.y} L ${o.x} ${a.y-m} ${i} ${o.x+$} ${a.y} L ${a.x} ${a.y}`),o.y>a.y&&(s=e.type===h.MERGE&&r.id!==e.parents[0]?`M ${o.x} ${o.y} L ${a.x-m} ${o.y} ${i} ${a.x} ${o.y-$} L ${a.x} ${a.y}`:`M ${o.x} ${o.y} L ${o.x} ${a.y+m} ${d} ${o.x+$} ${a.y} L ${a.x} ${a.y}`),o.y===a.y&&(s=`M ${o.x} ${o.y} L ${a.x} ${a.y}`));if(void 0===s)throw new Error("Line definition not found");t.append("path").attr("d",s).attr("class","arrow arrow"+l%8)}),"drawArrow"),gt=(0,c.K2)(((t,r)=>{const e=t.append("g").attr("class","commit-arrows");[...r.keys()].forEach((t=>{const n=r.get(t);n.parents&&n.parents.length>0&&n.parents.forEach((t=>{yt(e,r.get(t),n,r)}))}))}),"drawArrows"),pt=(0,c.K2)(((t,r)=>{const e=t.append("g");r.forEach(((t,r)=>{const n=r%8,o=j.get(t.name)?.pos;if(void 0===o)throw new Error(`Position not found for branch ${t.name}`);const a=e.append("line");a.attr("x1",0),a.attr("y1",o),a.attr("x2",U),a.attr("y2",o),a.attr("class","branch branch"+n),"TB"===V?(a.attr("y1",30),a.attr("x1",o),a.attr("y2",U),a.attr("x2",o)):"BT"===V&&(a.attr("y1",U),a.attr("x1",o),a.attr("y2",30),a.attr("x2",o)),F.push(o);const c=t.name,s=Q(c),i=e.insert("rect"),h=e.insert("g").attr("class","branchLabel").insert("g").attr("class","label branch-label"+n);h.node().appendChild(s);const d=s.getBBox();i.attr("class","branchLabelBkg label"+n).attr("rx",4).attr("ry",4).attr("x",-d.width-4-(!0===D?.rotateCommitLabel?30:0)).attr("y",-d.height/2+8).attr("width",d.width+18).attr("height",d.height+4),h.attr("transform","translate("+(-d.width-14-(!0===D?.rotateCommitLabel?30:0))+", "+(o-d.height/2-1)+")"),"TB"===V?(i.attr("x",o-d.width/2-10).attr("y",0),h.attr("transform","translate("+(o-d.width/2-5)+", 0)")):"BT"===V?(i.attr("x",o-d.width/2-10).attr("y",U),h.attr("transform","translate("+(o-d.width/2-5)+", "+U+")")):i.attr("transform","translate(-19, "+(o-d.height/2)+")")}))}),"drawBranches"),xt=(0,c.K2)((function(t,r,e,n,o){return j.set(t,{pos:r,index:e}),r+=50+(o?40:0)+("TB"===V||"BT"===V?n.width/2:0)}),"setBranchPosition");var ft={parser:H,db:v,renderer:{draw:(0,c.K2)((function(t,r,e,n){if(J(),c.Rm.debug("in gitgraph renderer",t+"\n","id:",r,e),!D)throw new Error("GitGraph config not found");const o=D.rotateCommitLabel??!1,s=n.db;_=s.getCommits();const h=s.getBranchesAsObjArray();V=s.getDirection();const d=(0,i.Ltv)(`[id="${r}"]`);let m=0;h.forEach(((t,r)=>{const e=Q(t.name),n=d.append("g"),a=n.insert("g").attr("class","branchLabel"),c=a.insert("g").attr("class","label branch-label");c.node()?.appendChild(e);const s=e.getBBox();m=xt(t.name,m,r,s,o),c.remove(),a.remove(),n.remove()})),mt(d,_,!1),D.showBranches&&pt(d,h),gt(d,_),mt(d,_,!0),a._K.insertTitle(d,"gitTitleText",D.titleTopMargin??0,s.getDiagramTitle()),(0,c.mj)(void 0,d,D.diagramPadding,D.useMaxWidth)}),"draw")},styles:(0,c.K2)((t=>`\n .commit-id,\n .commit-msg,\n .branch-label {\n fill: lightgrey;\n color: lightgrey;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n }\n ${[0,1,2,3,4,5,6,7].map((r=>`\n .branch-label${r} { fill: ${t["gitBranchLabel"+r]}; }\n .commit${r} { stroke: ${t["git"+r]}; fill: ${t["git"+r]}; }\n .commit-highlight${r} { stroke: ${t["gitInv"+r]}; fill: ${t["gitInv"+r]}; }\n .label${r} { fill: ${t["git"+r]}; }\n .arrow${r} { stroke: ${t["git"+r]}; }\n `)).join("\n")}\n\n .branch {\n stroke-width: 1;\n stroke: ${t.lineColor};\n stroke-dasharray: 2;\n }\n .commit-label { font-size: ${t.commitLabelFontSize}; fill: ${t.commitLabelColor};}\n .commit-label-bkg { font-size: ${t.commitLabelFontSize}; fill: ${t.commitLabelBackground}; opacity: 0.5; }\n .tag-label { font-size: ${t.tagLabelFontSize}; fill: ${t.tagLabelColor};}\n .tag-label-bkg { fill: ${t.tagLabelBackground}; stroke: ${t.tagLabelBorder}; }\n .tag-hole { fill: ${t.textColor}; }\n\n .commit-merge {\n stroke: ${t.primaryColor};\n fill: ${t.primaryColor};\n }\n .commit-reverse {\n stroke: ${t.primaryColor};\n fill: ${t.primaryColor};\n stroke-width: 3;\n }\n .commit-highlight-outer {\n }\n .commit-highlight-inner {\n stroke: ${t.primaryColor};\n fill: ${t.primaryColor};\n }\n\n .arrow { stroke-width: 8; stroke-linecap: round; fill: none}\n .gitTitleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.textColor};\n }\n`),"getStyles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5c6fa5d3.cb92794e.js b/pr-preview/pr-1071/assets/js/5c6fa5d3.cb92794e.js deleted file mode 100644 index 375484850f..0000000000 --- a/pr-preview/pr-1071/assets/js/5c6fa5d3.cb92794e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[722],{30014:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-1.1/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/examples/emojivoto.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Bare metal setup","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/1.1/deployment"}}');var o=n(74848),s=n(28453);const a={},r="Confidential emoji voting",l={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Download the deployment files",id:"download-the-deployment-files",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Verifying the deployment as a user",id:"verifying-the-deployment-as-a-user",level:2},{value:"Verifying the Coordinator",id:"verifying-the-coordinator",level:3},{value:"Auditing the manifest history and artifacts",id:"auditing-the-manifest-history-and-artifacts",level:3},{value:"Connecting securely to the application",id:"connecting-securely-to-the-application",level:3},{value:"Updating the certificate SAN and the manifest (optional)",id:"updating-the-certificate-san-and-the-manifest-optional",level:2},{value:"Configuring the service SAN in the manifest",id:"configuring-the-service-san-in-the-manifest",level:3},{value:"Updating the manifest",id:"updating-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components},{TabItem:i,Tabs:a}=t;return i||p("TabItem",!0),a||p("Tabs",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(2740).A+"",width:"1503",height:"732"})}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,o.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voter's perspective."]})}),"\n",(0,o.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,o.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,o.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,o.jsx)(t.code,{children:"voting"}),"). The ",(0,o.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,o.jsx)(t.p,{children:"Emojivoto can be seen as a lighthearted example of an app dealing with sensitive data.\nContrast protects emojivoto in two ways. First, it shields emojivoto as a whole from the infrastructure, for example, Azure.\nSecond, it can be configured to also prevent data access even from the administrator of the app. In the case of emojivoto, this gives assurance to users that their votes remain secret."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,o.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installed Contrast CLI"}),"\n",(0,o.jsxs)(t.li,{children:["A running Kubernetes cluster with support for confidential containers, either on ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup",children:"AKS"})," or on ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal",children:"bare metal"}),"."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,o.jsx)(t.h3,{id:"download-the-deployment-files",children:"Download the deployment files"}),"\n",(0,o.jsx)(t.p,{children:"The emojivoto deployment files are part of the Contrast release. You can download them by running:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.1.1/emojivoto-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,o.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/runtime",children:"custom Kubernetes RuntimeClass"}),",\nwhich needs to be installed to the cluster initially.\nThis consists of a ",(0,o.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,o.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-aks-clh-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-k3s-qemu-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,o.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,o.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-aks-clh-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-k3s-qemu-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.1.1/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,o.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,o.jsxs)(t.p,{children:["Run the ",(0,o.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,o.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})})}),(0,o.jsxs)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp deployment/\n"})}),(0,o.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,o.jsxs)(t.p,{children:["On bare-metal SEV-SNP, ",(0,o.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,o.jsx)(t.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,o.jsx)(t.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,o.jsxs)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx deployment/\n"})}),(0,o.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,o.jsxs)(t.p,{children:["On bare-metal TDX, ",(0,o.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,o.jsx)(t.code,{children:"MinimumTeeTcbSvn"})," and ",(0,o.jsx)(t.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,o.jsx)(t.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,o.jsx)(t.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,o.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,o.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,o.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/components/runtime",children:"runtime class"})," ",(0,o.jsx)(t.code,{children:"contrast-cc-<platform>-<runtime-hash>"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,o.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,o.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,o.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,o.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,o.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,o.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,o.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,o.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,o.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,o.jsx)(t.h2,{id:"verifying-the-deployment-as-a-user",children:"Verifying the deployment as a user"}),"\n",(0,o.jsx)(t.p,{children:"In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before casting a vote.\nWith Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment.\nContrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future.\nSuccessful verification of the Coordinator means that the user can be sure that the given manifest will be enforced."}),"\n",(0,o.jsx)(t.h3,{id:"verifying-the-coordinator",children:"Verifying the Coordinator"}),"\n",(0,o.jsx)(t.p,{children:"A user can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,o.jsxs)(t.p,{children:["The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,o.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,o.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,o.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"auditing-the-manifest-history-and-artifacts",children:"Auditing the manifest history and artifacts"}),"\n",(0,o.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,o.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,o.jsx)(t.h3,{id:"connecting-securely-to-the-application",children:"Connecting securely to the application"}),"\n",(0,o.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, the user can securely connect\nto the application using the Coordinator's ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,o.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,o.jsxs)(t.p,{children:["Using ",(0,o.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,o.jsx)(t.h2,{id:"updating-the-certificate-san-and-the-manifest-optional",children:"Updating the certificate SAN and the manifest (optional)"}),"\n",(0,o.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,o.jsx)(t.h3,{id:"configuring-the-service-san-in-the-manifest",children:"Configuring the service SAN in the manifest"}),"\n",(0,o.jsxs)(t.p,{children:["The ",(0,o.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,o.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,o.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {\n "SANs": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n "WorkloadSecretID": "web"\n },\n'})}),"\n",(0,o.jsx)(t.h3,{id:"updating-the-manifest",children:"Updating the manifest"}),"\n",(0,o.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,o.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,o.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,o.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}function p(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},2740:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var i=n(96540);const o={},s=i.createContext(o);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5e95c892.4198b464.js b/pr-preview/pr-1071/assets/js/5e95c892.4198b464.js deleted file mode 100644 index 6a43982d37..0000000000 --- a/pr-preview/pr-1071/assets/js/5e95c892.4198b464.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9647],{83124:(s,e,r)=>{r.r(e),r.d(e,{default:()=>d});r(96540);var c=r(34164),t=r(69817),a=r(18630),n=r(22831),u=r(53022),o=r(74848);function d(s){return(0,o.jsx)(t.e3,{className:(0,c.A)(a.G.wrapper.docsPages),children:(0,o.jsx)(u.A,{children:(0,n.v)(s.route.routes)})})}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5eab7755.5b4faa8a.js b/pr-preview/pr-1071/assets/js/5eab7755.5b4faa8a.js deleted file mode 100644 index b83c6cbc17..0000000000 --- a/pr-preview/pr-1071/assets/js/5eab7755.5b4faa8a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2772],{80601:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>c,metadata:()=>r,toc:()=>d});const r=JSON.parse('{"id":"getting-started/index","title":"Getting started","description":"","source":"@site/versioned_docs/version-0.7/getting-started/index.md","sourceDirName":"getting-started","slug":"/getting-started/","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/getting-started/index.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/features"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/install"}}');var s=n(74848),o=n(28453),i=n(44074);const c={},a="Getting started",l={},d=[];function u(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"getting-started",children:"Getting started"})}),"\n","\n",(0,s.jsx)(i.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>k});var r=n(96540),s=n(34164),o=n(45357),i=n(14783),c=n(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const d={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function u(){const{i18n:{currentLocale:e}}=(0,c.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),d}}),[e])}function m(){const e=u();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const g={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var x=n(74848);function j(e){let{href:t,children:n}=e;return(0,x.jsx)(i.A,{href:t,className:(0,s.A)("card padding--lg",g.cardContainer),children:n})}function v(e){let{href:t,icon:n,title:r,description:o}=e;return(0,x.jsxs)(j,{href:t,children:[(0,x.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",g.cardTitle),title:r,children:[n," ",r]}),o&&(0,x.jsx)("p",{className:(0,s.A)("text--truncate",g.cardDescription),title:o,children:o})]})}function w(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,x.jsx)(v,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function y(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,x.jsx)(v,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function b(e){let{item:t}=e;switch(t.type){case"link":return(0,x.jsx)(y,{item:t});case"category":return(0,x.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const n=(0,o.$S)();return(0,x.jsx)(k,{items:n.items,className:t})}function k(e){const{items:t,className:n}=e;if(!t)return(0,x.jsx)(N,{...e});const r=(0,o.d1)(t);return(0,x.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,x.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,x.jsx)(b,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>c});var r=n(96540);const s={},o=r.createContext(s);function i(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5ecc20d3.6c4d8685.js b/pr-preview/pr-1071/assets/js/5ecc20d3.6c4d8685.js deleted file mode 100644 index 11213c4566..0000000000 --- a/pr-preview/pr-1071/assets/js/5ecc20d3.6c4d8685.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1954],{71417:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-1.1/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/architecture/certificates.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/secrets"},"next":{"title":"Security considerations","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(95900).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},95900:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5f62f97d.200d33a5.js b/pr-preview/pr-1071/assets/js/5f62f97d.200d33a5.js deleted file mode 100644 index f21fd8863c..0000000000 --- a/pr-preview/pr-1071/assets/js/5f62f97d.200d33a5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2756],{59528:t=>{t.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Certificates and Identities","slug":"/category/certificates-and-identities","permalink":"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities","sidebar":"docs","navigation":{"previous":{"title":"Coordinator","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator"},"next":{"title":"PKI","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/5f998a2f.b65db294.js b/pr-preview/pr-1071/assets/js/5f998a2f.b65db294.js deleted file mode 100644 index 144634f228..0000000000 --- a/pr-preview/pr-1071/assets/js/5f998a2f.b65db294.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[941],{67785:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-1.1/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/1.1/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/intro.md","tags":[],"version":"1.1","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/getting-started/install",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6009a9aa.10bee6c5.js b/pr-preview/pr-1071/assets/js/6009a9aa.10bee6c5.js deleted file mode 100644 index 38e6c514b1..0000000000 --- a/pr-preview/pr-1071/assets/js/6009a9aa.10bee6c5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8212],{80621:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-0.9/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/0.9/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/components/runtime.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/0.9/components/overview"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.9/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"<code>cloud-hypervisor</code> virtual machine manager (VMM)",id:"cloud-hypervisor-virtual-machine-manager-vmm",level:3},{value:"<code>Tardev snapshotter</code>",id:"tardev-snapshotter",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(60010).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"cloud-hypervisor-virtual-machine-manager-vmm",children:[(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," virtual machine manager (VMM)"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})})," to create a confidential virtual machine for every pod.\nThis requires the ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," binary to be installed on every node (responsibility of the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),")."]}),"\n",(0,i.jsx)(n.h3,{id:"tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"Tardev snapshotter"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses a special ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotter"]})," (",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})}),") to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},60010:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6100b425.7022e9ad.js b/pr-preview/pr-1071/assets/js/6100b425.7022e9ad.js deleted file mode 100644 index 67eed3a326..0000000000 --- a/pr-preview/pr-1071/assets/js/6100b425.7022e9ad.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3129],{11768:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-0.9/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/basics/features.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.9/getting-started/install"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/616c9a0e.67cbd3fc.js b/pr-preview/pr-1071/assets/js/616c9a0e.67cbd3fc.js deleted file mode 100644 index 9e41185b6c..0000000000 --- a/pr-preview/pr-1071/assets/js/616c9a0e.67cbd3fc.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9562],{5354:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-1.2/components/overview.md","sourceDirName":"components","slug":"/components/overview","permalink":"/contrast/pr-preview/pr-1071/components/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/components/overview.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/troubleshooting"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},l=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(56580).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},56580:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6237.fb5352b8.js b/pr-preview/pr-1071/assets/js/6237.fb5352b8.js deleted file mode 100644 index 2bac505a3e..0000000000 --- a/pr-preview/pr-1071/assets/js/6237.fb5352b8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6237],{83814:(t,e,n)=>{n.d(e,{CP:()=>l,HT:()=>u,PB:()=>h,aC:()=>c,lC:()=>a,m:()=>o,tk:()=>r});var i=n(10009),s=n(16750),r=(0,i.K2)(((t,e)=>{const n=t.append("rect");if(n.attr("x",e.x),n.attr("y",e.y),n.attr("fill",e.fill),n.attr("stroke",e.stroke),n.attr("width",e.width),n.attr("height",e.height),e.name&&n.attr("name",e.name),e.rx&&n.attr("rx",e.rx),e.ry&&n.attr("ry",e.ry),void 0!==e.attrs)for(const i in e.attrs)n.attr(i,e.attrs[i]);return e.class&&n.attr("class",e.class),n}),"drawRect"),a=(0,i.K2)(((t,e)=>{const n={x:e.startx,y:e.starty,width:e.stopx-e.startx,height:e.stopy-e.starty,fill:e.fill,stroke:e.stroke,class:"rect"};r(t,n).lower()}),"drawBackgroundRect"),o=(0,i.K2)(((t,e)=>{const n=e.text.replace(i.H1," "),s=t.append("text");s.attr("x",e.x),s.attr("y",e.y),s.attr("class","legend"),s.style("text-anchor",e.anchor),e.class&&s.attr("class",e.class);const r=s.append("tspan");return r.attr("x",e.x+2*e.textMargin),r.text(n),s}),"drawText"),c=(0,i.K2)(((t,e,n,i)=>{const r=t.append("image");r.attr("x",e),r.attr("y",n);const a=(0,s.J)(i);r.attr("xlink:href",a)}),"drawImage"),l=(0,i.K2)(((t,e,n,i)=>{const r=t.append("use");r.attr("x",e),r.attr("y",n);const a=(0,s.J)(i);r.attr("xlink:href",`#${a}`)}),"drawEmbeddedImage"),h=(0,i.K2)((()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0})),"getNoteRect"),u=(0,i.K2)((()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0})),"getTextObj")},26237:(t,e,n)=>{n.d(e,{diagram:()=>Y});var i=n(83814),s=n(10009),r=n(20007),a=function(){var t=(0,s.K2)((function(t,e,n,i){for(n=n||{},i=t.length;i--;n[t[i]]=e);return n}),"o"),e=[6,8,10,11,12,14,16,17,18],n=[1,9],i=[1,10],r=[1,11],a=[1,12],o=[1,13],c=[1,14],l={trace:(0,s.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,taskName:18,taskData:19,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",18:"taskName",19:"taskData"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,2]],performAction:(0,s.K2)((function(t,e,n,i,s,r,a){var o=r.length-1;switch(s){case 1:return r[o-1];case 2:case 6:case 7:this.$=[];break;case 3:r[o-1].push(r[o]),this.$=r[o-1];break;case 4:case 5:this.$=r[o];break;case 8:i.setDiagramTitle(r[o].substr(6)),this.$=r[o].substr(6);break;case 9:this.$=r[o].trim(),i.setAccTitle(this.$);break;case 10:case 11:this.$=r[o].trim(),i.setAccDescription(this.$);break;case 12:i.addSection(r[o].substr(8)),this.$=r[o].substr(8);break;case 13:i.addTask(r[o-1],r[o]),this.$="task"}}),"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:n,12:i,14:r,16:a,17:o,18:c},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:15,11:n,12:i,14:r,16:a,17:o,18:c},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,16]},{15:[1,17]},t(e,[2,11]),t(e,[2,12]),{19:[1,18]},t(e,[2,4]),t(e,[2,9]),t(e,[2,10]),t(e,[2,13])],defaultActions:{},parseError:(0,s.K2)((function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)}),"parseError"),parse:(0,s.K2)((function(t){var e=this,n=[0],i=[],r=[null],a=[],o=this.table,c="",l=0,h=0,u=0,y=a.slice.call(arguments,1),p=Object.create(this.lexer),d={yy:{}};for(var f in this.yy)Object.prototype.hasOwnProperty.call(this.yy,f)&&(d.yy[f]=this.yy[f]);p.setInput(t,d.yy),d.yy.lexer=p,d.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var g=p.yylloc;a.push(g);var x=p.options&&p.options.ranges;function m(){var t;return"number"!=typeof(t=i.pop()||p.lex()||1)&&(t instanceof Array&&(t=(i=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof d.yy.parseError?this.parseError=d.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,s.K2)((function(t){n.length=n.length-2*t,r.length=r.length-t,a.length=a.length-t}),"popStack"),(0,s.K2)(m,"lex");for(var k,_,b,w,v,K,$,T,M,S={};;){if(b=n[n.length-1],this.defaultActions[b]?w=this.defaultActions[b]:(null==k&&(k=m()),w=o[b]&&o[b][k]),void 0===w||!w.length||!w[0]){var E="";for(K in M=[],o[b])this.terminals_[K]&&K>2&&M.push("'"+this.terminals_[K]+"'");E=p.showPosition?"Parse error on line "+(l+1)+":\n"+p.showPosition()+"\nExpecting "+M.join(", ")+", got '"+(this.terminals_[k]||k)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==k?"end of input":"'"+(this.terminals_[k]||k)+"'"),this.parseError(E,{text:p.match,token:this.terminals_[k]||k,line:p.yylineno,loc:g,expected:M})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+b+", token: "+k);switch(w[0]){case 1:n.push(k),r.push(p.yytext),a.push(p.yylloc),n.push(w[1]),k=null,_?(k=_,_=null):(h=p.yyleng,c=p.yytext,l=p.yylineno,g=p.yylloc,u>0&&u--);break;case 2:if($=this.productions_[w[1]][1],S.$=r[r.length-$],S._$={first_line:a[a.length-($||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-($||1)].first_column,last_column:a[a.length-1].last_column},x&&(S._$.range=[a[a.length-($||1)].range[0],a[a.length-1].range[1]]),void 0!==(v=this.performAction.apply(S,[c,h,l,d.yy,w[1],r,a].concat(y))))return v;$&&(n=n.slice(0,-1*$*2),r=r.slice(0,-1*$),a=a.slice(0,-1*$)),n.push(this.productions_[w[1]][0]),r.push(S.$),a.push(S._$),T=o[n[n.length-2]][n[n.length-1]],n.push(T);break;case 3:return!0}}return!0}),"parse")},h=function(){return{EOF:1,parseError:(0,s.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,s.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,s.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,s.K2)((function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var i=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===i.length?this.yylloc.first_column:0)+i[i.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,s.K2)((function(){return this._more=!0,this}),"more"),reject:(0,s.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,s.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,s.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,s.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,s.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,s.K2)((function(t,e){var n,i,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),(i=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var r in s)this[r]=s[r];return!1}return!1}),"test_match"),next:(0,s.K2)((function(){if(this.done)return this.EOF;var t,e,n,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),r=0;r<s.length;r++)if((n=this._input.match(this.rules[s[r]]))&&(!e||n[0].length>e[0].length)){if(e=n,i=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,s[r])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,s[i]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,s.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,s.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,s.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,s.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,s.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,s.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,s.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,s.K2)((function(t,e,n,i){switch(n){case 0:case 1:case 3:case 4:break;case 2:return 10;case 5:return 4;case 6:return 11;case 7:return this.begin("acc_title"),12;case 8:return this.popState(),"acc_title_value";case 9:return this.begin("acc_descr"),14;case 10:return this.popState(),"acc_descr_value";case 11:this.begin("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 17;case 15:return 18;case 16:return 19;case 17:return":";case 18:return 6;case 19:return"INVALID"}}),"anonymous"),rules:[/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,9,11,14,15,16,17,18,19],inclusive:!0}}}}();function u(){this.yy={}}return l.lexer=h,(0,s.K2)(u,"Parser"),u.prototype=l,l.Parser=u,new u}();a.parser=a;var o=a,c="",l=[],h=[],u=[],y=(0,s.K2)((function(){l.length=0,h.length=0,c="",u.length=0,(0,s.IU)()}),"clear"),p=(0,s.K2)((function(t){c=t,l.push(t)}),"addSection"),d=(0,s.K2)((function(){return l}),"getSections"),f=(0,s.K2)((function(){let t=k();let e=0;for(;!t&&e<100;)t=k(),e++;return h.push(...u),h}),"getTasks"),g=(0,s.K2)((function(){const t=[];h.forEach((e=>{e.people&&t.push(...e.people)}));return[...new Set(t)].sort()}),"updateActors"),x=(0,s.K2)((function(t,e){const n=e.substr(1).split(":");let i=0,s=[];1===n.length?(i=Number(n[0]),s=[]):(i=Number(n[0]),s=n[1].split(","));const r=s.map((t=>t.trim())),a={section:c,type:c,people:r,task:t,score:i};u.push(a)}),"addTask"),m=(0,s.K2)((function(t){const e={section:c,type:c,description:t,task:t,classes:[]};h.push(e)}),"addTaskOrg"),k=(0,s.K2)((function(){const t=(0,s.K2)((function(t){return u[t].processed}),"compileTask");let e=!0;for(const[n,i]of u.entries())t(n),e=e&&i.processed;return e}),"compileTasks"),_=(0,s.K2)((function(){return g()}),"getActors"),b={getConfig:(0,s.K2)((()=>(0,s.D7)().journey),"getConfig"),clear:y,setDiagramTitle:s.ke,getDiagramTitle:s.ab,setAccTitle:s.SV,getAccTitle:s.iN,setAccDescription:s.EI,getAccDescription:s.m7,addSection:p,getSections:d,getTasks:f,addTask:x,addTaskOrg:m,getActors:_},w=(0,s.K2)((t=>`.label {\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n color: ${t.textColor};\n }\n .mouth {\n stroke: #666;\n }\n\n line {\n stroke: ${t.textColor}\n }\n\n .legend {\n fill: ${t.textColor};\n }\n\n .label text {\n fill: #333;\n }\n .label {\n color: ${t.textColor}\n }\n\n .face {\n ${t.faceColor?`fill: ${t.faceColor}`:"fill: #FFF8DC"};\n stroke: #999;\n }\n\n .node rect,\n .node circle,\n .node ellipse,\n .node polygon,\n .node path {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n stroke-width: 1px;\n }\n\n .node .label {\n text-align: center;\n }\n .node.clickable {\n cursor: pointer;\n }\n\n .arrowheadPath {\n fill: ${t.arrowheadColor};\n }\n\n .edgePath .path {\n stroke: ${t.lineColor};\n stroke-width: 1.5px;\n }\n\n .flowchart-link {\n stroke: ${t.lineColor};\n fill: none;\n }\n\n .edgeLabel {\n background-color: ${t.edgeLabelBackground};\n rect {\n opacity: 0.5;\n }\n text-align: center;\n }\n\n .cluster rect {\n }\n\n .cluster text {\n fill: ${t.titleColor};\n }\n\n div.mermaidTooltip {\n position: absolute;\n text-align: center;\n max-width: 200px;\n padding: 2px;\n font-family: 'trebuchet ms', verdana, arial, sans-serif;\n font-family: var(--mermaid-font-family);\n font-size: 12px;\n background: ${t.tertiaryColor};\n border: 1px solid ${t.border2};\n border-radius: 2px;\n pointer-events: none;\n z-index: 100;\n }\n\n .task-type-0, .section-type-0 {\n ${t.fillType0?`fill: ${t.fillType0}`:""};\n }\n .task-type-1, .section-type-1 {\n ${t.fillType0?`fill: ${t.fillType1}`:""};\n }\n .task-type-2, .section-type-2 {\n ${t.fillType0?`fill: ${t.fillType2}`:""};\n }\n .task-type-3, .section-type-3 {\n ${t.fillType0?`fill: ${t.fillType3}`:""};\n }\n .task-type-4, .section-type-4 {\n ${t.fillType0?`fill: ${t.fillType4}`:""};\n }\n .task-type-5, .section-type-5 {\n ${t.fillType0?`fill: ${t.fillType5}`:""};\n }\n .task-type-6, .section-type-6 {\n ${t.fillType0?`fill: ${t.fillType6}`:""};\n }\n .task-type-7, .section-type-7 {\n ${t.fillType0?`fill: ${t.fillType7}`:""};\n }\n\n .actor-0 {\n ${t.actor0?`fill: ${t.actor0}`:""};\n }\n .actor-1 {\n ${t.actor1?`fill: ${t.actor1}`:""};\n }\n .actor-2 {\n ${t.actor2?`fill: ${t.actor2}`:""};\n }\n .actor-3 {\n ${t.actor3?`fill: ${t.actor3}`:""};\n }\n .actor-4 {\n ${t.actor4?`fill: ${t.actor4}`:""};\n }\n .actor-5 {\n ${t.actor5?`fill: ${t.actor5}`:""};\n }\n`),"getStyles"),v=(0,s.K2)((function(t,e){return(0,i.tk)(t,e)}),"drawRect"),K=(0,s.K2)((function(t,e){const n=15,i=t.append("circle").attr("cx",e.cx).attr("cy",e.cy).attr("class","face").attr("r",n).attr("stroke-width",2).attr("overflow","visible"),a=t.append("g");function o(t){const i=(0,r.JLW)().startAngle(Math.PI/2).endAngle(Math.PI/2*3).innerRadius(7.5).outerRadius(n/2.2);t.append("path").attr("class","mouth").attr("d",i).attr("transform","translate("+e.cx+","+(e.cy+2)+")")}function c(t){const i=(0,r.JLW)().startAngle(3*Math.PI/2).endAngle(Math.PI/2*5).innerRadius(7.5).outerRadius(n/2.2);t.append("path").attr("class","mouth").attr("d",i).attr("transform","translate("+e.cx+","+(e.cy+7)+")")}function l(t){t.append("line").attr("class","mouth").attr("stroke",2).attr("x1",e.cx-5).attr("y1",e.cy+7).attr("x2",e.cx+5).attr("y2",e.cy+7).attr("class","mouth").attr("stroke-width","1px").attr("stroke","#666")}return a.append("circle").attr("cx",e.cx-5).attr("cy",e.cy-5).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),a.append("circle").attr("cx",e.cx+5).attr("cy",e.cy-5).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),(0,s.K2)(o,"smile"),(0,s.K2)(c,"sad"),(0,s.K2)(l,"ambivalent"),e.score>3?o(a):e.score<3?c(a):l(a),i}),"drawFace"),$=(0,s.K2)((function(t,e){const n=t.append("circle");return n.attr("cx",e.cx),n.attr("cy",e.cy),n.attr("class","actor-"+e.pos),n.attr("fill",e.fill),n.attr("stroke",e.stroke),n.attr("r",e.r),void 0!==n.class&&n.attr("class",n.class),void 0!==e.title&&n.append("title").text(e.title),n}),"drawCircle"),T=(0,s.K2)((function(t,e){return(0,i.m)(t,e)}),"drawText"),M=(0,s.K2)((function(t,e){function n(t,e,n,i,s){return t+","+e+" "+(t+n)+","+e+" "+(t+n)+","+(e+i-s)+" "+(t+n-1.2*s)+","+(e+i)+" "+t+","+(e+i)}(0,s.K2)(n,"genPoints");const i=t.append("polygon");i.attr("points",n(e.x,e.y,50,20,7)),i.attr("class","labelBox"),e.y=e.y+e.labelMargin,e.x=e.x+.5*e.labelMargin,T(t,e)}),"drawLabel"),S=(0,s.K2)((function(t,e,n){const s=t.append("g"),r=(0,i.PB)();r.x=e.x,r.y=e.y,r.fill=e.fill,r.width=n.width*e.taskCount+n.diagramMarginX*(e.taskCount-1),r.height=n.height,r.class="journey-section section-type-"+e.num,r.rx=3,r.ry=3,v(s,r),C(n)(e.text,s,r.x,r.y,r.width,r.height,{class:"journey-section section-type-"+e.num},n,e.colour)}),"drawSection"),E=-1,I=(0,s.K2)((function(t,e,n){const s=e.x+n.width/2,r=t.append("g");E++;r.append("line").attr("id","task"+E).attr("x1",s).attr("y1",e.y).attr("x2",s).attr("y2",450).attr("class","task-line").attr("stroke-width","1px").attr("stroke-dasharray","4 2").attr("stroke","#666"),K(r,{cx:s,cy:300+30*(5-e.score),score:e.score});const a=(0,i.PB)();a.x=e.x,a.y=e.y,a.fill=e.fill,a.width=n.width,a.height=n.height,a.class="task task-type-"+e.num,a.rx=3,a.ry=3,v(r,a);let o=e.x+14;e.people.forEach((t=>{const n=e.actors[t].color,i={cx:o,cy:e.y,r:7,fill:n,stroke:"#000",title:t,pos:e.actors[t].position};$(r,i),o+=10})),C(n)(e.task,r,a.x,a.y,a.width,a.height,{class:"task"},n,e.colour)}),"drawTask"),P=(0,s.K2)((function(t,e){(0,i.lC)(t,e)}),"drawBackgroundRect"),C=function(){function t(t,e,n,s,r,a,o,c){i(e.append("text").attr("x",n+r/2).attr("y",s+a/2+5).style("font-color",c).style("text-anchor","middle").text(t),o)}function e(t,e,n,s,r,a,o,c,l){const{taskFontSize:h,taskFontFamily:u}=c,y=t.split(/<br\s*\/?>/gi);for(let p=0;p<y.length;p++){const t=p*h-h*(y.length-1)/2,c=e.append("text").attr("x",n+r/2).attr("y",s).attr("fill",l).style("text-anchor","middle").style("font-size",h).style("font-family",u);c.append("tspan").attr("x",n+r/2).attr("dy",t).text(y[p]),c.attr("y",s+a/2).attr("dominant-baseline","central").attr("alignment-baseline","central"),i(c,o)}}function n(t,n,s,r,a,o,c,l){const h=n.append("switch"),u=h.append("foreignObject").attr("x",s).attr("y",r).attr("width",a).attr("height",o).attr("position","fixed").append("xhtml:div").style("display","table").style("height","100%").style("width","100%");u.append("div").attr("class","label").style("display","table-cell").style("text-align","center").style("vertical-align","middle").text(t),e(t,h,s,r,a,o,c,l),i(u,c)}function i(t,e){for(const n in e)n in e&&t.attr(n,e[n])}return(0,s.K2)(t,"byText"),(0,s.K2)(e,"byTspan"),(0,s.K2)(n,"byFo"),(0,s.K2)(i,"_setTextAttrs"),function(i){return"fo"===i.textPlacement?n:"old"===i.textPlacement?t:e}}(),A={drawRect:v,drawCircle:$,drawSection:S,drawText:T,drawLabel:M,drawTask:I,drawBackgroundRect:P,initGraphics:(0,s.K2)((function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",5).attr("refY",2).attr("markerWidth",6).attr("markerHeight",4).attr("orient","auto").append("path").attr("d","M 0,0 V 4 L6,2 Z")}),"initGraphics")},j=(0,s.K2)((function(t){Object.keys(t).forEach((function(e){V[e]=t[e]}))}),"setConf"),D={};function L(t){const e=(0,s.D7)().journey;let n=60;Object.keys(D).forEach((i=>{const s=D[i].color,r={cx:20,cy:n,r:7,fill:s,stroke:"#000",pos:D[i].position};A.drawCircle(t,r);const a={x:40,y:n+7,fill:"#666",text:i,textMargin:5|e.boxTextMargin};A.drawText(t,a),n+=20}))}(0,s.K2)(L,"drawActorLegend");var V=(0,s.D7)().journey,B=V.leftMargin,O=(0,s.K2)((function(t,e,n,i){const a=(0,s.D7)().journey,o=(0,s.D7)().securityLevel;let c;"sandbox"===o&&(c=(0,r.Ltv)("#i"+e));const l="sandbox"===o?(0,r.Ltv)(c.nodes()[0].contentDocument.body):(0,r.Ltv)("body");F.init();const h=l.select("#"+e);A.initGraphics(h);const u=i.db.getTasks(),y=i.db.getDiagramTitle(),p=i.db.getActors();for(const s in D)delete D[s];let d=0;p.forEach((t=>{D[t]={color:a.actorColours[d%a.actorColours.length],position:d},d++})),L(h),F.insert(0,0,B,50*Object.keys(D).length),z(h,u,0);const f=F.getBounds();y&&h.append("text").text(y).attr("x",B).attr("font-size","4ex").attr("font-weight","bold").attr("y",25);const g=f.stopy-f.starty+2*a.diagramMarginY,x=B+f.stopx+2*a.diagramMarginX;(0,s.a$)(h,g,x,a.useMaxWidth),h.append("line").attr("x1",B).attr("y1",4*a.height).attr("x2",x-B-4).attr("y2",4*a.height).attr("stroke-width",4).attr("stroke","black").attr("marker-end","url(#arrowhead)");const m=y?70:0;h.attr("viewBox",`${f.startx} -25 ${x} ${g+m}`),h.attr("preserveAspectRatio","xMinYMin meet"),h.attr("height",g+m+25)}),"draw"),F={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],init:(0,s.K2)((function(){this.sequenceItems=[],this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0}),"init"),updateVal:(0,s.K2)((function(t,e,n,i){void 0===t[e]?t[e]=n:t[e]=i(n,t[e])}),"updateVal"),updateBounds:(0,s.K2)((function(t,e,n,i){const r=(0,s.D7)().journey,a=this;let o=0;function c(c){return(0,s.K2)((function(s){o++;const l=a.sequenceItems.length-o+1;a.updateVal(s,"starty",e-l*r.boxMargin,Math.min),a.updateVal(s,"stopy",i+l*r.boxMargin,Math.max),a.updateVal(F.data,"startx",t-l*r.boxMargin,Math.min),a.updateVal(F.data,"stopx",n+l*r.boxMargin,Math.max),"activation"!==c&&(a.updateVal(s,"startx",t-l*r.boxMargin,Math.min),a.updateVal(s,"stopx",n+l*r.boxMargin,Math.max),a.updateVal(F.data,"starty",e-l*r.boxMargin,Math.min),a.updateVal(F.data,"stopy",i+l*r.boxMargin,Math.max))}),"updateItemBounds")}(0,s.K2)(c,"updateFn"),this.sequenceItems.forEach(c())}),"updateBounds"),insert:(0,s.K2)((function(t,e,n,i){const s=Math.min(t,n),r=Math.max(t,n),a=Math.min(e,i),o=Math.max(e,i);this.updateVal(F.data,"startx",s,Math.min),this.updateVal(F.data,"starty",a,Math.min),this.updateVal(F.data,"stopx",r,Math.max),this.updateVal(F.data,"stopy",o,Math.max),this.updateBounds(s,a,r,o)}),"insert"),bumpVerticalPos:(0,s.K2)((function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=this.verticalPos}),"bumpVerticalPos"),getVerticalPos:(0,s.K2)((function(){return this.verticalPos}),"getVerticalPos"),getBounds:(0,s.K2)((function(){return this.data}),"getBounds")},N=V.sectionFills,R=V.sectionColours,z=(0,s.K2)((function(t,e,n){const i=(0,s.D7)().journey;let r="";const a=n+(2*i.height+i.diagramMarginY);let o=0,c="#CCC",l="black",h=0;for(const[s,u]of e.entries()){if(r!==u.section){c=N[o%N.length],h=o%N.length,l=R[o%R.length];let n=0;const a=u.section;for(let t=s;t<e.length&&e[t].section==a;t++)n+=1;const y={x:s*i.taskMargin+s*i.width+B,y:50,text:u.section,fill:c,num:h,colour:l,taskCount:n};A.drawSection(t,y,i),r=u.section,o++}const n=u.people.reduce(((t,e)=>(D[e]&&(t[e]=D[e]),t)),{});u.x=s*i.taskMargin+s*i.width+B,u.y=a,u.width=i.diagramMarginX,u.height=i.diagramMarginY,u.colour=l,u.fill=c,u.num=h,u.actors=n,A.drawTask(t,u,i),F.insert(u.x,u.y,u.x+u.width+i.taskMargin,450)}}),"drawTasks"),W={setConf:j,draw:O},Y={parser:o,db:b,renderer:W,styles:w,init:(0,s.K2)((t=>{W.setConf(t.journey),b.clear()}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6244.e911fcbf.js b/pr-preview/pr-1071/assets/js/6244.e911fcbf.js deleted file mode 100644 index 52cee1fed0..0000000000 --- a/pr-preview/pr-1071/assets/js/6244.e911fcbf.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6244],{97375:function(t){t.exports=function(){"use strict";return function(t,e){var n=e.prototype,i=n.format;n.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return i.bind(this)(t);var s=this.$utils(),r=(t||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,(function(t){switch(t){case"Q":return Math.ceil((e.$M+1)/3);case"Do":return n.ordinal(e.$D);case"gggg":return e.weekYear();case"GGGG":return e.isoWeekYear();case"wo":return n.ordinal(e.week(),"W");case"w":case"ww":return s.s(e.week(),"w"===t?1:2,"0");case"W":case"WW":return s.s(e.isoWeek(),"W"===t?1:2,"0");case"k":case"kk":return s.s(String(0===e.$H?24:e.$H),"k"===t?1:2,"0");case"X":return Math.floor(e.$d.getTime()/1e3);case"x":return e.$d.getTime();case"z":return"["+e.offsetName()+"]";case"zzz":return"["+e.offsetName("long")+"]";default:return t}}));return i.bind(this)(r)}}}()},90445:function(t){t.exports=function(){"use strict";var t={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},e=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,n=/\d/,i=/\d\d/,s=/\d\d?/,r=/\d*[^-_:/,()\s\d]+/,a={},o=function(t){return(t=+t)+(t>68?1900:2e3)},c=function(t){return function(e){this[t]=+e}},l=[/[+-]\d\d:?(\d\d)?|Z/,function(t){(this.zone||(this.zone={})).offset=function(t){if(!t)return 0;if("Z"===t)return 0;var e=t.match(/([+-]|\d\d)/g),n=60*e[1]+(+e[2]||0);return 0===n?0:"+"===e[0]?-n:n}(t)}],d=function(t){var e=a[t];return e&&(e.indexOf?e:e.s.concat(e.f))},u=function(t,e){var n,i=a.meridiem;if(i){for(var s=1;s<=24;s+=1)if(t.indexOf(i(s,0,e))>-1){n=s>12;break}}else n=t===(e?"pm":"PM");return n},h={A:[r,function(t){this.afternoon=u(t,!1)}],a:[r,function(t){this.afternoon=u(t,!0)}],Q:[n,function(t){this.month=3*(t-1)+1}],S:[n,function(t){this.milliseconds=100*+t}],SS:[i,function(t){this.milliseconds=10*+t}],SSS:[/\d{3}/,function(t){this.milliseconds=+t}],s:[s,c("seconds")],ss:[s,c("seconds")],m:[s,c("minutes")],mm:[s,c("minutes")],H:[s,c("hours")],h:[s,c("hours")],HH:[s,c("hours")],hh:[s,c("hours")],D:[s,c("day")],DD:[i,c("day")],Do:[r,function(t){var e=a.ordinal,n=t.match(/\d+/);if(this.day=n[0],e)for(var i=1;i<=31;i+=1)e(i).replace(/\[|\]/g,"")===t&&(this.day=i)}],w:[s,c("week")],ww:[i,c("week")],M:[s,c("month")],MM:[i,c("month")],MMM:[r,function(t){var e=d("months"),n=(d("monthsShort")||e.map((function(t){return t.slice(0,3)}))).indexOf(t)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[r,function(t){var e=d("months").indexOf(t)+1;if(e<1)throw new Error;this.month=e%12||e}],Y:[/[+-]?\d+/,c("year")],YY:[i,function(t){this.year=o(t)}],YYYY:[/\d{4}/,c("year")],Z:l,ZZ:l};function f(n){var i,s;i=n,s=a&&a.formats;for(var r=(n=i.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(e,n,i){var r=i&&i.toUpperCase();return n||s[i]||t[i]||s[r].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(t,e,n){return e||n.slice(1)}))}))).match(e),o=r.length,c=0;c<o;c+=1){var l=r[c],d=h[l],u=d&&d[0],f=d&&d[1];r[c]=f?{regex:u,parser:f}:l.replace(/^\[|\]$/g,"")}return function(t){for(var e={},n=0,i=0;n<o;n+=1){var s=r[n];if("string"==typeof s)i+=s.length;else{var a=s.regex,c=s.parser,l=t.slice(i),d=a.exec(l)[0];c.call(e,d),t=t.replace(d,"")}}return function(t){var e=t.afternoon;if(void 0!==e){var n=t.hours;e?n<12&&(t.hours+=12):12===n&&(t.hours=0),delete t.afternoon}}(e),e}}return function(t,e,n){n.p.customParseFormat=!0,t&&t.parseTwoDigitYear&&(o=t.parseTwoDigitYear);var i=e.prototype,s=i.parse;i.parse=function(t){var e=t.date,i=t.utc,r=t.args;this.$u=i;var o=r[1];if("string"==typeof o){var c=!0===r[2],l=!0===r[3],d=c||l,u=r[2];l&&(u=r[2]),a=this.$locale(),!c&&u&&(a=n.Ls[u]),this.$d=function(t,e,n,i){try{if(["x","X"].indexOf(e)>-1)return new Date(("X"===e?1e3:1)*t);var s=f(e)(t),r=s.year,a=s.month,o=s.day,c=s.hours,l=s.minutes,d=s.seconds,u=s.milliseconds,h=s.zone,y=s.week,k=new Date,m=o||(r||a?1:k.getDate()),p=r||k.getFullYear(),g=0;r&&!a||(g=a>0?a-1:k.getMonth());var b,T=c||0,v=l||0,x=d||0,w=u||0;return h?new Date(Date.UTC(p,g,m,T,v,x,w+60*h.offset*1e3)):n?new Date(Date.UTC(p,g,m,T,v,x,w)):(b=new Date(p,g,m,T,v,x,w),y&&(b=i(b).week(y).toDate()),b)}catch(t){return new Date("")}}(e,o,i,n),this.init(),u&&!0!==u&&(this.$L=this.locale(u).$L),d&&e!=this.format(o)&&(this.$d=new Date("")),a={}}else if(o instanceof Array)for(var h=o.length,y=1;y<=h;y+=1){r[1]=o[y-1];var k=n.apply(this,r);if(k.isValid()){this.$d=k.$d,this.$L=k.$L,this.init();break}y===h&&(this.$d=new Date(""))}else s.call(this,t)}}}()},68313:function(t){t.exports=function(){"use strict";var t="day";return function(e,n,i){var s=function(e){return e.add(4-e.isoWeekday(),t)},r=n.prototype;r.isoWeekYear=function(){return s(this).year()},r.isoWeek=function(e){if(!this.$utils().u(e))return this.add(7*(e-this.isoWeek()),t);var n,r,a,o=s(this),c=(n=this.isoWeekYear(),a=4-(r=(this.$u?i.utc:i)().year(n).startOf("year")).isoWeekday(),r.isoWeekday()>4&&(a+=7),r.add(a,t));return o.diff(c,"week")+1},r.isoWeekday=function(t){return this.$utils().u(t)?this.day()||7:this.day(this.day()%7?t:t-7)};var a=r.startOf;r.startOf=function(t,e){var n=this.$utils(),i=!!n.u(e)||e;return"isoweek"===n.p(t)?i?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):a.bind(this)(t,e)}}}()},66244:(t,e,n)=>{"use strict";n.d(e,{diagram:()=>Yt});var i=n(8159),s=n(10009),r=n(16750),a=n(74353),o=n(68313),c=n(90445),l=n(97375),d=n(20007),u=function(){var t=(0,s.K2)((function(t,e,n,i){for(n=n||{},i=t.length;i--;n[t[i]]=e);return n}),"o"),e=[6,8,10,12,13,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,31,33,35,36,38,40],n=[1,26],i=[1,27],r=[1,28],a=[1,29],o=[1,30],c=[1,31],l=[1,32],d=[1,33],u=[1,34],h=[1,9],f=[1,10],y=[1,11],k=[1,12],m=[1,13],p=[1,14],g=[1,15],b=[1,16],T=[1,19],v=[1,20],x=[1,21],w=[1,22],_=[1,23],D=[1,25],$=[1,35],C={trace:(0,s.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,gantt:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NL:10,weekday:11,weekday_monday:12,weekday_tuesday:13,weekday_wednesday:14,weekday_thursday:15,weekday_friday:16,weekday_saturday:17,weekday_sunday:18,weekend:19,weekend_friday:20,weekend_saturday:21,dateFormat:22,inclusiveEndDates:23,topAxis:24,axisFormat:25,tickInterval:26,excludes:27,includes:28,todayMarker:29,title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,section:36,clickStatement:37,taskTxt:38,taskData:39,click:40,callbackname:41,callbackargs:42,href:43,clickStatementDebug:44,$accept:0,$end:1},terminals_:{2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",12:"weekday_monday",13:"weekday_tuesday",14:"weekday_wednesday",15:"weekday_thursday",16:"weekday_friday",17:"weekday_saturday",18:"weekday_sunday",20:"weekend_friday",21:"weekend_saturday",22:"dateFormat",23:"inclusiveEndDates",24:"topAxis",25:"axisFormat",26:"tickInterval",27:"excludes",28:"includes",29:"todayMarker",30:"title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"section",38:"taskTxt",39:"taskData",40:"click",41:"callbackname",42:"callbackargs",43:"href"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[19,1],[19,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,2],[37,2],[37,3],[37,3],[37,4],[37,3],[37,4],[37,2],[44,2],[44,3],[44,3],[44,4],[44,3],[44,4],[44,2]],performAction:(0,s.K2)((function(t,e,n,i,s,r,a){var o=r.length-1;switch(s){case 1:return r[o-1];case 2:case 6:case 7:this.$=[];break;case 3:r[o-1].push(r[o]),this.$=r[o-1];break;case 4:case 5:this.$=r[o];break;case 8:i.setWeekday("monday");break;case 9:i.setWeekday("tuesday");break;case 10:i.setWeekday("wednesday");break;case 11:i.setWeekday("thursday");break;case 12:i.setWeekday("friday");break;case 13:i.setWeekday("saturday");break;case 14:i.setWeekday("sunday");break;case 15:i.setWeekend("friday");break;case 16:i.setWeekend("saturday");break;case 17:i.setDateFormat(r[o].substr(11)),this.$=r[o].substr(11);break;case 18:i.enableInclusiveEndDates(),this.$=r[o].substr(18);break;case 19:i.TopAxis(),this.$=r[o].substr(8);break;case 20:i.setAxisFormat(r[o].substr(11)),this.$=r[o].substr(11);break;case 21:i.setTickInterval(r[o].substr(13)),this.$=r[o].substr(13);break;case 22:i.setExcludes(r[o].substr(9)),this.$=r[o].substr(9);break;case 23:i.setIncludes(r[o].substr(9)),this.$=r[o].substr(9);break;case 24:i.setTodayMarker(r[o].substr(12)),this.$=r[o].substr(12);break;case 27:i.setDiagramTitle(r[o].substr(6)),this.$=r[o].substr(6);break;case 28:this.$=r[o].trim(),i.setAccTitle(this.$);break;case 29:case 30:this.$=r[o].trim(),i.setAccDescription(this.$);break;case 31:i.addSection(r[o].substr(8)),this.$=r[o].substr(8);break;case 33:i.addTask(r[o-1],r[o]),this.$="task";break;case 34:this.$=r[o-1],i.setClickEvent(r[o-1],r[o],null);break;case 35:this.$=r[o-2],i.setClickEvent(r[o-2],r[o-1],r[o]);break;case 36:this.$=r[o-2],i.setClickEvent(r[o-2],r[o-1],null),i.setLink(r[o-2],r[o]);break;case 37:this.$=r[o-3],i.setClickEvent(r[o-3],r[o-2],r[o-1]),i.setLink(r[o-3],r[o]);break;case 38:this.$=r[o-2],i.setClickEvent(r[o-2],r[o],null),i.setLink(r[o-2],r[o-1]);break;case 39:this.$=r[o-3],i.setClickEvent(r[o-3],r[o-1],r[o]),i.setLink(r[o-3],r[o-2]);break;case 40:this.$=r[o-1],i.setLink(r[o-1],r[o]);break;case 41:case 47:this.$=r[o-1]+" "+r[o];break;case 42:case 43:case 45:this.$=r[o-2]+" "+r[o-1]+" "+r[o];break;case 44:case 46:this.$=r[o-3]+" "+r[o-2]+" "+r[o-1]+" "+r[o]}}),"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:17,12:n,13:i,14:r,15:a,16:o,17:c,18:l,19:18,20:d,21:u,22:h,23:f,24:y,25:k,26:m,27:p,28:g,29:b,30:T,31:v,33:x,35:w,36:_,37:24,38:D,40:$},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:36,11:17,12:n,13:i,14:r,15:a,16:o,17:c,18:l,19:18,20:d,21:u,22:h,23:f,24:y,25:k,26:m,27:p,28:g,29:b,30:T,31:v,33:x,35:w,36:_,37:24,38:D,40:$},t(e,[2,5]),t(e,[2,6]),t(e,[2,17]),t(e,[2,18]),t(e,[2,19]),t(e,[2,20]),t(e,[2,21]),t(e,[2,22]),t(e,[2,23]),t(e,[2,24]),t(e,[2,25]),t(e,[2,26]),t(e,[2,27]),{32:[1,37]},{34:[1,38]},t(e,[2,30]),t(e,[2,31]),t(e,[2,32]),{39:[1,39]},t(e,[2,8]),t(e,[2,9]),t(e,[2,10]),t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),{41:[1,40],43:[1,41]},t(e,[2,4]),t(e,[2,28]),t(e,[2,29]),t(e,[2,33]),t(e,[2,34],{42:[1,42],43:[1,43]}),t(e,[2,40],{41:[1,44]}),t(e,[2,35],{43:[1,45]}),t(e,[2,36]),t(e,[2,38],{42:[1,46]}),t(e,[2,37]),t(e,[2,39])],defaultActions:{},parseError:(0,s.K2)((function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)}),"parseError"),parse:(0,s.K2)((function(t){var e=this,n=[0],i=[],r=[null],a=[],o=this.table,c="",l=0,d=0,u=0,h=a.slice.call(arguments,1),f=Object.create(this.lexer),y={yy:{}};for(var k in this.yy)Object.prototype.hasOwnProperty.call(this.yy,k)&&(y.yy[k]=this.yy[k]);f.setInput(t,y.yy),y.yy.lexer=f,y.yy.parser=this,void 0===f.yylloc&&(f.yylloc={});var m=f.yylloc;a.push(m);var p=f.options&&f.options.ranges;function g(){var t;return"number"!=typeof(t=i.pop()||f.lex()||1)&&(t instanceof Array&&(t=(i=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,s.K2)((function(t){n.length=n.length-2*t,r.length=r.length-t,a.length=a.length-t}),"popStack"),(0,s.K2)(g,"lex");for(var b,T,v,x,w,_,D,$,C,S={};;){if(v=n[n.length-1],this.defaultActions[v]?x=this.defaultActions[v]:(null==b&&(b=g()),x=o[v]&&o[v][b]),void 0===x||!x.length||!x[0]){var K="";for(_ in C=[],o[v])this.terminals_[_]&&_>2&&C.push("'"+this.terminals_[_]+"'");K=f.showPosition?"Parse error on line "+(l+1)+":\n"+f.showPosition()+"\nExpecting "+C.join(", ")+", got '"+(this.terminals_[b]||b)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==b?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(K,{text:f.match,token:this.terminals_[b]||b,line:f.yylineno,loc:m,expected:C})}if(x[0]instanceof Array&&x.length>1)throw new Error("Parse Error: multiple actions possible at state: "+v+", token: "+b);switch(x[0]){case 1:n.push(b),r.push(f.yytext),a.push(f.yylloc),n.push(x[1]),b=null,T?(b=T,T=null):(d=f.yyleng,c=f.yytext,l=f.yylineno,m=f.yylloc,u>0&&u--);break;case 2:if(D=this.productions_[x[1]][1],S.$=r[r.length-D],S._$={first_line:a[a.length-(D||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(D||1)].first_column,last_column:a[a.length-1].last_column},p&&(S._$.range=[a[a.length-(D||1)].range[0],a[a.length-1].range[1]]),void 0!==(w=this.performAction.apply(S,[c,d,l,y.yy,x[1],r,a].concat(h))))return w;D&&(n=n.slice(0,-1*D*2),r=r.slice(0,-1*D),a=a.slice(0,-1*D)),n.push(this.productions_[x[1]][0]),r.push(S.$),a.push(S._$),$=o[n[n.length-2]][n[n.length-1]],n.push($);break;case 3:return!0}}return!0}),"parse")},S=function(){return{EOF:1,parseError:(0,s.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,s.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,s.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,s.K2)((function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var i=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===i.length?this.yylloc.first_column:0)+i[i.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,s.K2)((function(){return this._more=!0,this}),"more"),reject:(0,s.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,s.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,s.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,s.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,s.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,s.K2)((function(t,e){var n,i,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),(i=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var r in s)this[r]=s[r];return!1}return!1}),"test_match"),next:(0,s.K2)((function(){if(this.done)return this.EOF;var t,e,n,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),r=0;r<s.length;r++)if((n=this._input.match(this.rules[s[r]]))&&(!e||n[0].length>e[0].length)){if(e=n,i=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,s[r])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,s[i]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,s.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,s.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,s.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,s.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,s.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,s.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,s.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,s.K2)((function(t,e,n,i){switch(n){case 0:return this.begin("open_directive"),"open_directive";case 1:return this.begin("acc_title"),31;case 2:return this.popState(),"acc_title_value";case 3:return this.begin("acc_descr"),33;case 4:return this.popState(),"acc_descr_value";case 5:this.begin("acc_descr_multiline");break;case 6:case 15:case 18:case 21:case 24:this.popState();break;case 7:return"acc_descr_multiline_value";case 8:case 9:case 10:case 12:case 13:break;case 11:return 10;case 14:this.begin("href");break;case 16:return 43;case 17:this.begin("callbackname");break;case 19:this.popState(),this.begin("callbackargs");break;case 20:return 41;case 22:return 42;case 23:this.begin("click");break;case 25:return 40;case 26:return 4;case 27:return 22;case 28:return 23;case 29:return 24;case 30:return 25;case 31:return 26;case 32:return 28;case 33:return 27;case 34:return 29;case 35:return 12;case 36:return 13;case 37:return 14;case 38:return 15;case 39:return 16;case 40:return 17;case 41:return 18;case 42:return 20;case 43:return 21;case 44:return"date";case 45:return 30;case 46:return"accDescription";case 47:return 36;case 48:return 38;case 49:return 39;case 50:return":";case 51:return 6;case 52:return"INVALID"}}),"anonymous"),rules:[/^(?:%%\{)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:topAxis\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:tickInterval\s[^#\n;]+)/i,/^(?:includes\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:weekday\s+monday\b)/i,/^(?:weekday\s+tuesday\b)/i,/^(?:weekday\s+wednesday\b)/i,/^(?:weekday\s+thursday\b)/i,/^(?:weekday\s+friday\b)/i,/^(?:weekday\s+saturday\b)/i,/^(?:weekday\s+sunday\b)/i,/^(?:weekend\s+friday\b)/i,/^(?:weekend\s+saturday\b)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^\n]+)/i,/^(?:accDescription\s[^#\n;]+)/i,/^(?:section\s[^\n]+)/i,/^(?:[^:\n]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[6,7],inclusive:!1},acc_descr:{rules:[4],inclusive:!1},acc_title:{rules:[2],inclusive:!1},callbackargs:{rules:[21,22],inclusive:!1},callbackname:{rules:[18,19,20],inclusive:!1},href:{rules:[15,16],inclusive:!1},click:{rules:[24,25],inclusive:!1},INITIAL:{rules:[0,1,3,5,8,9,10,11,12,13,14,17,23,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],inclusive:!0}}}}();function K(){this.yy={}}return C.lexer=S,(0,s.K2)(K,"Parser"),K.prototype=C,C.Parser=K,new K}();u.parser=u;var h=u;a.extend(o),a.extend(c),a.extend(l);var f,y,k={friday:5,saturday:6},m="",p="",g=void 0,b="",T=[],v=[],x=new Map,w=[],_=[],D="",$="",C=["active","done","crit","milestone"],S=[],K=!1,E=!1,M="sunday",A="saturday",L=0,Y=(0,s.K2)((function(){w=[],_=[],D="",S=[],ht=0,f=void 0,y=void 0,mt=[],m="",p="",$="",g=void 0,b="",T=[],v=[],K=!1,E=!1,L=0,x=new Map,(0,s.IU)(),M="sunday",A="saturday"}),"clear"),I=(0,s.K2)((function(t){p=t}),"setAxisFormat"),W=(0,s.K2)((function(){return p}),"getAxisFormat"),F=(0,s.K2)((function(t){g=t}),"setTickInterval"),O=(0,s.K2)((function(){return g}),"getTickInterval"),P=(0,s.K2)((function(t){b=t}),"setTodayMarker"),B=(0,s.K2)((function(){return b}),"getTodayMarker"),z=(0,s.K2)((function(t){m=t}),"setDateFormat"),N=(0,s.K2)((function(){K=!0}),"enableInclusiveEndDates"),G=(0,s.K2)((function(){return K}),"endDatesAreInclusive"),H=(0,s.K2)((function(){E=!0}),"enableTopAxis"),R=(0,s.K2)((function(){return E}),"topAxisEnabled"),j=(0,s.K2)((function(t){$=t}),"setDisplayMode"),U=(0,s.K2)((function(){return $}),"getDisplayMode"),V=(0,s.K2)((function(){return m}),"getDateFormat"),Z=(0,s.K2)((function(t){T=t.toLowerCase().split(/[\s,]+/)}),"setIncludes"),X=(0,s.K2)((function(){return T}),"getIncludes"),q=(0,s.K2)((function(t){v=t.toLowerCase().split(/[\s,]+/)}),"setExcludes"),Q=(0,s.K2)((function(){return v}),"getExcludes"),J=(0,s.K2)((function(){return x}),"getLinks"),tt=(0,s.K2)((function(t){D=t,w.push(t)}),"addSection"),et=(0,s.K2)((function(){return w}),"getSections"),nt=(0,s.K2)((function(){let t=vt();let e=0;for(;!t&&e<10;)t=vt(),e++;return _=mt}),"getTasks"),it=(0,s.K2)((function(t,e,n,i){return!i.includes(t.format(e.trim()))&&(!(!n.includes("weekends")||t.isoWeekday()!==k[A]&&t.isoWeekday()!==k[A]+1)||(!!n.includes(t.format("dddd").toLowerCase())||n.includes(t.format(e.trim()))))}),"isInvalidDate"),st=(0,s.K2)((function(t){M=t}),"setWeekday"),rt=(0,s.K2)((function(){return M}),"getWeekday"),at=(0,s.K2)((function(t){A=t}),"setWeekend"),ot=(0,s.K2)((function(t,e,n,i){if(!n.length||t.manualEndTime)return;let s,r;s=t.startTime instanceof Date?a(t.startTime):a(t.startTime,e,!0),s=s.add(1,"d"),r=t.endTime instanceof Date?a(t.endTime):a(t.endTime,e,!0);const[o,c]=ct(s,r,e,n,i);t.endTime=o.toDate(),t.renderEndTime=c}),"checkTaskDates"),ct=(0,s.K2)((function(t,e,n,i,s){let r=!1,a=null;for(;t<=e;)r||(a=e.toDate()),r=it(t,n,i,s),r&&(e=e.add(1,"d")),t=t.add(1,"d");return[e,a]}),"fixTaskDates"),lt=(0,s.K2)((function(t,e,n){n=n.trim();const i=/^after\s+(?<ids>[\d\w- ]+)/.exec(n);if(null!==i){let t=null;for(const n of i.groups.ids.split(" ")){let e=bt(n);void 0!==e&&(!t||e.endTime>t.endTime)&&(t=e)}if(t)return t.endTime;const e=new Date;return e.setHours(0,0,0,0),e}let r=a(n,e.trim(),!0);if(r.isValid())return r.toDate();{s.Rm.debug("Invalid date:"+n),s.Rm.debug("With date format:"+e.trim());const t=new Date(n);if(void 0===t||isNaN(t.getTime())||t.getFullYear()<-1e4||t.getFullYear()>1e4)throw new Error("Invalid date:"+n);return t}}),"getStartDate"),dt=(0,s.K2)((function(t){const e=/^(\d+(?:\.\d+)?)([Mdhmswy]|ms)$/.exec(t.trim());return null!==e?[Number.parseFloat(e[1]),e[2]]:[NaN,"ms"]}),"parseDuration"),ut=(0,s.K2)((function(t,e,n,i=!1){n=n.trim();const s=/^until\s+(?<ids>[\d\w- ]+)/.exec(n);if(null!==s){let t=null;for(const n of s.groups.ids.split(" ")){let e=bt(n);void 0!==e&&(!t||e.startTime<t.startTime)&&(t=e)}if(t)return t.startTime;const e=new Date;return e.setHours(0,0,0,0),e}let r=a(n,e.trim(),!0);if(r.isValid())return i&&(r=r.add(1,"d")),r.toDate();let o=a(t);const[c,l]=dt(n);if(!Number.isNaN(c)){const t=o.add(c,l);t.isValid()&&(o=t)}return o.toDate()}),"getEndDate"),ht=0,ft=(0,s.K2)((function(t){return void 0===t?"task"+(ht+=1):t}),"parseId"),yt=(0,s.K2)((function(t,e){let n;n=":"===e.substr(0,1)?e.substr(1,e.length):e;const i=n.split(","),s={};Kt(i,s,C);for(let a=0;a<i.length;a++)i[a]=i[a].trim();let r="";switch(i.length){case 1:s.id=ft(),s.startTime=t.endTime,r=i[0];break;case 2:s.id=ft(),s.startTime=lt(void 0,m,i[0]),r=i[1];break;case 3:s.id=ft(i[0]),s.startTime=lt(void 0,m,i[1]),r=i[2]}return r&&(s.endTime=ut(s.startTime,m,r,K),s.manualEndTime=a(r,"YYYY-MM-DD",!0).isValid(),ot(s,m,v,T)),s}),"compileData"),kt=(0,s.K2)((function(t,e){let n;n=":"===e.substr(0,1)?e.substr(1,e.length):e;const i=n.split(","),s={};Kt(i,s,C);for(let r=0;r<i.length;r++)i[r]=i[r].trim();switch(i.length){case 1:s.id=ft(),s.startTime={type:"prevTaskEnd",id:t},s.endTime={data:i[0]};break;case 2:s.id=ft(),s.startTime={type:"getStartDate",startData:i[0]},s.endTime={data:i[1]};break;case 3:s.id=ft(i[0]),s.startTime={type:"getStartDate",startData:i[1]},s.endTime={data:i[2]}}return s}),"parseData"),mt=[],pt={},gt=(0,s.K2)((function(t,e){const n={section:D,type:D,processed:!1,manualEndTime:!1,renderEndTime:null,raw:{data:e},task:t,classes:[]},i=kt(y,e);n.raw.startTime=i.startTime,n.raw.endTime=i.endTime,n.id=i.id,n.prevTaskId=y,n.active=i.active,n.done=i.done,n.crit=i.crit,n.milestone=i.milestone,n.order=L,L++;const s=mt.push(n);y=n.id,pt[n.id]=s-1}),"addTask"),bt=(0,s.K2)((function(t){const e=pt[t];return mt[e]}),"findTaskById"),Tt=(0,s.K2)((function(t,e){const n={section:D,type:D,description:t,task:t,classes:[]},i=yt(f,e);n.startTime=i.startTime,n.endTime=i.endTime,n.id=i.id,n.active=i.active,n.done=i.done,n.crit=i.crit,n.milestone=i.milestone,f=n,_.push(n)}),"addTaskOrg"),vt=(0,s.K2)((function(){const t=(0,s.K2)((function(t){const e=mt[t];let n="";switch(mt[t].raw.startTime.type){case"prevTaskEnd":{const t=bt(e.prevTaskId);e.startTime=t.endTime;break}case"getStartDate":n=lt(void 0,m,mt[t].raw.startTime.startData),n&&(mt[t].startTime=n)}return mt[t].startTime&&(mt[t].endTime=ut(mt[t].startTime,m,mt[t].raw.endTime.data,K),mt[t].endTime&&(mt[t].processed=!0,mt[t].manualEndTime=a(mt[t].raw.endTime.data,"YYYY-MM-DD",!0).isValid(),ot(mt[t],m,v,T))),mt[t].processed}),"compileTask");let e=!0;for(const[n,i]of mt.entries())t(n),e=e&&i.processed;return e}),"compileTasks"),xt=(0,s.K2)((function(t,e){let n=e;"loose"!==(0,s.D7)().securityLevel&&(n=(0,r.J)(e)),t.split(",").forEach((function(t){void 0!==bt(t)&&(Dt(t,(()=>{window.open(n,"_self")})),x.set(t,n))})),wt(t,"clickable")}),"setLink"),wt=(0,s.K2)((function(t,e){t.split(",").forEach((function(t){let n=bt(t);void 0!==n&&n.classes.push(e)}))}),"setClass"),_t=(0,s.K2)((function(t,e,n){if("loose"!==(0,s.D7)().securityLevel)return;if(void 0===e)return;let r=[];if("string"==typeof n){r=n.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let t=0;t<r.length;t++){let e=r[t].trim();e.startsWith('"')&&e.endsWith('"')&&(e=e.substr(1,e.length-2)),r[t]=e}}0===r.length&&r.push(t),void 0!==bt(t)&&Dt(t,(()=>{i._K.runFunc(e,...r)}))}),"setClickFun"),Dt=(0,s.K2)((function(t,e){S.push((function(){const n=document.querySelector(`[id="${t}"]`);null!==n&&n.addEventListener("click",(function(){e()}))}),(function(){const n=document.querySelector(`[id="${t}-text"]`);null!==n&&n.addEventListener("click",(function(){e()}))}))}),"pushFun"),$t=(0,s.K2)((function(t,e,n){t.split(",").forEach((function(t){_t(t,e,n)})),wt(t,"clickable")}),"setClickEvent"),Ct=(0,s.K2)((function(t){S.forEach((function(e){e(t)}))}),"bindFunctions"),St={getConfig:(0,s.K2)((()=>(0,s.D7)().gantt),"getConfig"),clear:Y,setDateFormat:z,getDateFormat:V,enableInclusiveEndDates:N,endDatesAreInclusive:G,enableTopAxis:H,topAxisEnabled:R,setAxisFormat:I,getAxisFormat:W,setTickInterval:F,getTickInterval:O,setTodayMarker:P,getTodayMarker:B,setAccTitle:s.SV,getAccTitle:s.iN,setDiagramTitle:s.ke,getDiagramTitle:s.ab,setDisplayMode:j,getDisplayMode:U,setAccDescription:s.EI,getAccDescription:s.m7,addSection:tt,getSections:et,getTasks:nt,addTask:gt,findTaskById:bt,addTaskOrg:Tt,setIncludes:Z,getIncludes:X,setExcludes:q,getExcludes:Q,setClickEvent:$t,setLink:xt,getLinks:J,bindFunctions:Ct,parseDuration:dt,isInvalidDate:it,setWeekday:st,getWeekday:rt,setWeekend:at};function Kt(t,e,n){let i=!0;for(;i;)i=!1,n.forEach((function(n){const s=new RegExp("^\\s*"+n+"\\s*$");t[0].match(s)&&(e[n]=!0,t.shift(1),i=!0)}))}(0,s.K2)(Kt,"getTaskTags");var Et,Mt=(0,s.K2)((function(){s.Rm.debug("Something is calling, setConf, remove the call")}),"setConf"),At={monday:d.ABi,tuesday:d.PGu,wednesday:d.GuW,thursday:d.Mol,friday:d.TUC,saturday:d.rGn,sunday:d.YPH},Lt=(0,s.K2)(((t,e)=>{let n=[...t].map((()=>-1/0)),i=[...t].sort(((t,e)=>t.startTime-e.startTime||t.order-e.order)),s=0;for(const r of i)for(let t=0;t<n.length;t++)if(r.startTime>=n[t]){n[t]=r.endTime,r.order=t+e,t>s&&(s=t);break}return s}),"getMaxIntersections"),Yt={parser:h,db:St,renderer:{setConf:Mt,draw:(0,s.K2)((function(t,e,n,i){const r=(0,s.D7)().gantt,o=(0,s.D7)().securityLevel;let c;"sandbox"===o&&(c=(0,d.Ltv)("#i"+e));const l="sandbox"===o?(0,d.Ltv)(c.nodes()[0].contentDocument.body):(0,d.Ltv)("body"),u="sandbox"===o?c.nodes()[0].contentDocument:document,h=u.getElementById(e);void 0===(Et=h.parentElement.offsetWidth)&&(Et=1200),void 0!==r.useWidth&&(Et=r.useWidth);const f=i.db.getTasks();let y=[];for(const s of f)y.push(s.type);y=$(y);const k={};let m=2*r.topPadding;if("compact"===i.db.getDisplayMode()||"compact"===r.displayMode){const t={};for(const n of f)void 0===t[n.section]?t[n.section]=[n]:t[n.section].push(n);let e=0;for(const n of Object.keys(t)){const i=Lt(t[n],e)+1;e+=i,m+=i*(r.barHeight+r.barGap),k[n]=i}}else{m+=f.length*(r.barHeight+r.barGap);for(const t of y)k[t]=f.filter((e=>e.type===t)).length}h.setAttribute("viewBox","0 0 "+Et+" "+m);const p=l.select(`[id="${e}"]`),g=(0,d.w7C)().domain([(0,d.jkA)(f,(function(t){return t.startTime})),(0,d.T9B)(f,(function(t){return t.endTime}))]).rangeRound([0,Et-r.leftPadding-r.rightPadding]);function b(t,e){const n=t.startTime,i=e.startTime;let s=0;return n>i?s=1:n<i&&(s=-1),s}function T(t,e,n){const s=r.barHeight,a=s+r.barGap,o=r.topPadding,c=r.leftPadding,l=(0,d.m4Y)().domain([0,y.length]).range(["#00B9FA","#F95002"]).interpolate(d.bEH);x(a,o,c,e,n,t,i.db.getExcludes(),i.db.getIncludes()),w(c,o,e,n),v(t,a,o,c,s,l,e),_(a,o),D(c,o,e,n)}function v(t,n,a,o,c,l,u){const h=[...new Set(t.map((t=>t.order)))].map((e=>t.find((t=>t.order===e))));p.append("g").selectAll("rect").data(h).enter().append("rect").attr("x",0).attr("y",(function(t,e){return t.order*n+a-2})).attr("width",(function(){return u-r.rightPadding/2})).attr("height",n).attr("class",(function(t){for(const[e,n]of y.entries())if(t.type===n)return"section section"+e%r.numberSectionStyles;return"section section0"}));const f=p.append("g").selectAll("rect").data(t).enter(),k=i.db.getLinks();f.append("rect").attr("id",(function(t){return t.id})).attr("rx",3).attr("ry",3).attr("x",(function(t){return t.milestone?g(t.startTime)+o+.5*(g(t.endTime)-g(t.startTime))-.5*c:g(t.startTime)+o})).attr("y",(function(t,e){return t.order*n+a})).attr("width",(function(t){return t.milestone?c:g(t.renderEndTime||t.endTime)-g(t.startTime)})).attr("height",c).attr("transform-origin",(function(t,e){return e=t.order,(g(t.startTime)+o+.5*(g(t.endTime)-g(t.startTime))).toString()+"px "+(e*n+a+.5*c).toString()+"px"})).attr("class",(function(t){let e="";t.classes.length>0&&(e=t.classes.join(" "));let n=0;for(const[s,a]of y.entries())t.type===a&&(n=s%r.numberSectionStyles);let i="";return t.active?t.crit?i+=" activeCrit":i=" active":t.done?i=t.crit?" doneCrit":" done":t.crit&&(i+=" crit"),0===i.length&&(i=" task"),t.milestone&&(i=" milestone "+i),i+=n,i+=" "+e,"task"+i})),f.append("text").attr("id",(function(t){return t.id+"-text"})).text((function(t){return t.task})).attr("font-size",r.fontSize).attr("x",(function(t){let e=g(t.startTime),n=g(t.renderEndTime||t.endTime);t.milestone&&(e+=.5*(g(t.endTime)-g(t.startTime))-.5*c),t.milestone&&(n=e+c);const i=this.getBBox().width;return i>n-e?n+i+1.5*r.leftPadding>u?e+o-5:n+o+5:(n-e)/2+e+o})).attr("y",(function(t,e){return t.order*n+r.barHeight/2+(r.fontSize/2-2)+a})).attr("text-height",c).attr("class",(function(t){const e=g(t.startTime);let n=g(t.endTime);t.milestone&&(n=e+c);const i=this.getBBox().width;let s="";t.classes.length>0&&(s=t.classes.join(" "));let a=0;for(const[c,l]of y.entries())t.type===l&&(a=c%r.numberSectionStyles);let o="";return t.active&&(o=t.crit?"activeCritText"+a:"activeText"+a),t.done?o=t.crit?o+" doneCritText"+a:o+" doneText"+a:t.crit&&(o=o+" critText"+a),t.milestone&&(o+=" milestoneText"),i>n-e?n+i+1.5*r.leftPadding>u?s+" taskTextOutsideLeft taskTextOutside"+a+" "+o:s+" taskTextOutsideRight taskTextOutside"+a+" "+o+" width-"+i:s+" taskText taskText"+a+" "+o+" width-"+i}));if("sandbox"===(0,s.D7)().securityLevel){let t;t=(0,d.Ltv)("#i"+e);const n=t.nodes()[0].contentDocument;f.filter((function(t){return k.has(t.id)})).each((function(t){var e=n.querySelector("#"+t.id),i=n.querySelector("#"+t.id+"-text");const s=e.parentNode;var r=n.createElement("a");r.setAttribute("xlink:href",k.get(t.id)),r.setAttribute("target","_top"),s.appendChild(r),r.appendChild(e),r.appendChild(i)}))}}function x(t,e,n,o,c,l,d,u){if(0===d.length&&0===u.length)return;let h,f;for(const{startTime:i,endTime:s}of l)(void 0===h||i<h)&&(h=i),(void 0===f||s>f)&&(f=s);if(!h||!f)return;if(a(f).diff(a(h),"year")>5)return void s.Rm.warn("The difference between the min and max time is more than 5 years. This will cause performance issues. Skipping drawing exclude days.");const y=i.db.getDateFormat(),k=[];let m=null,b=a(h);for(;b.valueOf()<=f;)i.db.isInvalidDate(b,y,d,u)?m?m.end=b:m={start:b,end:b}:m&&(k.push(m),m=null),b=b.add(1,"d");p.append("g").selectAll("rect").data(k).enter().append("rect").attr("id",(function(t){return"exclude-"+t.start.format("YYYY-MM-DD")})).attr("x",(function(t){return g(t.start)+n})).attr("y",r.gridLineStartPadding).attr("width",(function(t){const e=t.end.add(1,"day");return g(e)-g(t.start)})).attr("height",c-e-r.gridLineStartPadding).attr("transform-origin",(function(e,i){return(g(e.start)+n+.5*(g(e.end)-g(e.start))).toString()+"px "+(i*t+.5*c).toString()+"px"})).attr("class","exclude-range")}function w(t,e,n,s){let a=(0,d.l78)(g).tickSize(-s+e+r.gridLineStartPadding).tickFormat((0,d.DCK)(i.db.getAxisFormat()||r.axisFormat||"%Y-%m-%d"));const o=/^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/.exec(i.db.getTickInterval()||r.tickInterval);if(null!==o){const t=o[1],e=o[2],n=i.db.getWeekday()||r.weekday;switch(e){case"millisecond":a.ticks(d.t6C.every(t));break;case"second":a.ticks(d.ucG.every(t));break;case"minute":a.ticks(d.wXd.every(t));break;case"hour":a.ticks(d.Agd.every(t));break;case"day":a.ticks(d.UAC.every(t));break;case"week":a.ticks(At[n].every(t));break;case"month":a.ticks(d.Ui6.every(t))}}if(p.append("g").attr("class","grid").attr("transform","translate("+t+", "+(s-50)+")").call(a).selectAll("text").style("text-anchor","middle").attr("fill","#000").attr("stroke","none").attr("font-size",10).attr("dy","1em"),i.db.topAxisEnabled()||r.topAxis){let n=(0,d.tlR)(g).tickSize(-s+e+r.gridLineStartPadding).tickFormat((0,d.DCK)(i.db.getAxisFormat()||r.axisFormat||"%Y-%m-%d"));if(null!==o){const t=o[1],e=o[2],s=i.db.getWeekday()||r.weekday;switch(e){case"millisecond":n.ticks(d.t6C.every(t));break;case"second":n.ticks(d.ucG.every(t));break;case"minute":n.ticks(d.wXd.every(t));break;case"hour":n.ticks(d.Agd.every(t));break;case"day":n.ticks(d.UAC.every(t));break;case"week":n.ticks(At[s].every(t));break;case"month":n.ticks(d.Ui6.every(t))}}p.append("g").attr("class","grid").attr("transform","translate("+t+", "+e+")").call(n).selectAll("text").style("text-anchor","middle").attr("fill","#000").attr("stroke","none").attr("font-size",10)}}function _(t,e){let n=0;const i=Object.keys(k).map((t=>[t,k[t]]));p.append("g").selectAll("text").data(i).enter().append((function(t){const e=t[0].split(s.Y2.lineBreakRegex),n=-(e.length-1)/2,i=u.createElementNS("http://www.w3.org/2000/svg","text");i.setAttribute("dy",n+"em");for(const[s,r]of e.entries()){const t=u.createElementNS("http://www.w3.org/2000/svg","tspan");t.setAttribute("alignment-baseline","central"),t.setAttribute("x","10"),s>0&&t.setAttribute("dy","1em"),t.textContent=r,i.appendChild(t)}return i})).attr("x",10).attr("y",(function(s,r){if(!(r>0))return s[1]*t/2+e;for(let a=0;a<r;a++)return n+=i[r-1][1],s[1]*t/2+n*t+e})).attr("font-size",r.sectionFontSize).attr("class",(function(t){for(const[e,n]of y.entries())if(t[0]===n)return"sectionTitle sectionTitle"+e%r.numberSectionStyles;return"sectionTitle"}))}function D(t,e,n,s){const a=i.db.getTodayMarker();if("off"===a)return;const o=p.append("g").attr("class","today"),c=new Date,l=o.append("line");l.attr("x1",g(c)+t).attr("x2",g(c)+t).attr("y1",r.titleTopMargin).attr("y2",s-r.titleTopMargin).attr("class","today"),""!==a&&l.attr("style",a.replace(/,/g,";"))}function $(t){const e={},n=[];for(let i=0,s=t.length;i<s;++i)Object.prototype.hasOwnProperty.call(e,t[i])||(e[t[i]]=!0,n.push(t[i]));return n}(0,s.K2)(b,"taskCompare"),f.sort(b),T(f,Et,m),(0,s.a$)(p,m,Et,r.useMaxWidth),p.append("text").text(i.db.getDiagramTitle()).attr("x",Et/2).attr("y",r.titleTopMargin).attr("class","titleText"),(0,s.K2)(T,"makeGantt"),(0,s.K2)(v,"drawRects"),(0,s.K2)(x,"drawExcludeDays"),(0,s.K2)(w,"makeGrid"),(0,s.K2)(_,"vertLabels"),(0,s.K2)(D,"drawToday"),(0,s.K2)($,"checkUnique")}),"draw")},styles:(0,s.K2)((t=>`\n .mermaid-main-font {\n font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif);\n }\n\n .exclude-range {\n fill: ${t.excludeBkgColor};\n }\n\n .section {\n stroke: none;\n opacity: 0.2;\n }\n\n .section0 {\n fill: ${t.sectionBkgColor};\n }\n\n .section2 {\n fill: ${t.sectionBkgColor2};\n }\n\n .section1,\n .section3 {\n fill: ${t.altSectionBkgColor};\n opacity: 0.2;\n }\n\n .sectionTitle0 {\n fill: ${t.titleColor};\n }\n\n .sectionTitle1 {\n fill: ${t.titleColor};\n }\n\n .sectionTitle2 {\n fill: ${t.titleColor};\n }\n\n .sectionTitle3 {\n fill: ${t.titleColor};\n }\n\n .sectionTitle {\n text-anchor: start;\n font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif);\n }\n\n\n /* Grid and axis */\n\n .grid .tick {\n stroke: ${t.gridColor};\n opacity: 0.8;\n shape-rendering: crispEdges;\n }\n\n .grid .tick text {\n font-family: ${t.fontFamily};\n fill: ${t.textColor};\n }\n\n .grid path {\n stroke-width: 0;\n }\n\n\n /* Today line */\n\n .today {\n fill: none;\n stroke: ${t.todayLineColor};\n stroke-width: 2px;\n }\n\n\n /* Task styling */\n\n /* Default task */\n\n .task {\n stroke-width: 2;\n }\n\n .taskText {\n text-anchor: middle;\n font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif);\n }\n\n .taskTextOutsideRight {\n fill: ${t.taskTextDarkColor};\n text-anchor: start;\n font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif);\n }\n\n .taskTextOutsideLeft {\n fill: ${t.taskTextDarkColor};\n text-anchor: end;\n }\n\n\n /* Special case clickable */\n\n .task.clickable {\n cursor: pointer;\n }\n\n .taskText.clickable {\n cursor: pointer;\n fill: ${t.taskTextClickableColor} !important;\n font-weight: bold;\n }\n\n .taskTextOutsideLeft.clickable {\n cursor: pointer;\n fill: ${t.taskTextClickableColor} !important;\n font-weight: bold;\n }\n\n .taskTextOutsideRight.clickable {\n cursor: pointer;\n fill: ${t.taskTextClickableColor} !important;\n font-weight: bold;\n }\n\n\n /* Specific task settings for the sections*/\n\n .taskText0,\n .taskText1,\n .taskText2,\n .taskText3 {\n fill: ${t.taskTextColor};\n }\n\n .task0,\n .task1,\n .task2,\n .task3 {\n fill: ${t.taskBkgColor};\n stroke: ${t.taskBorderColor};\n }\n\n .taskTextOutside0,\n .taskTextOutside2\n {\n fill: ${t.taskTextOutsideColor};\n }\n\n .taskTextOutside1,\n .taskTextOutside3 {\n fill: ${t.taskTextOutsideColor};\n }\n\n\n /* Active task */\n\n .active0,\n .active1,\n .active2,\n .active3 {\n fill: ${t.activeTaskBkgColor};\n stroke: ${t.activeTaskBorderColor};\n }\n\n .activeText0,\n .activeText1,\n .activeText2,\n .activeText3 {\n fill: ${t.taskTextDarkColor} !important;\n }\n\n\n /* Completed task */\n\n .done0,\n .done1,\n .done2,\n .done3 {\n stroke: ${t.doneTaskBorderColor};\n fill: ${t.doneTaskBkgColor};\n stroke-width: 2;\n }\n\n .doneText0,\n .doneText1,\n .doneText2,\n .doneText3 {\n fill: ${t.taskTextDarkColor} !important;\n }\n\n\n /* Tasks on the critical line */\n\n .crit0,\n .crit1,\n .crit2,\n .crit3 {\n stroke: ${t.critBorderColor};\n fill: ${t.critBkgColor};\n stroke-width: 2;\n }\n\n .activeCrit0,\n .activeCrit1,\n .activeCrit2,\n .activeCrit3 {\n stroke: ${t.critBorderColor};\n fill: ${t.activeTaskBkgColor};\n stroke-width: 2;\n }\n\n .doneCrit0,\n .doneCrit1,\n .doneCrit2,\n .doneCrit3 {\n stroke: ${t.critBorderColor};\n fill: ${t.doneTaskBkgColor};\n stroke-width: 2;\n cursor: pointer;\n shape-rendering: crispEdges;\n }\n\n .milestone {\n transform: rotate(45deg) scale(0.8,0.8);\n }\n\n .milestoneText {\n font-style: italic;\n }\n .doneCritText0,\n .doneCritText1,\n .doneCritText2,\n .doneCritText3 {\n fill: ${t.taskTextDarkColor} !important;\n }\n\n .activeCritText0,\n .activeCritText1,\n .activeCritText2,\n .activeCritText3 {\n fill: ${t.taskTextDarkColor} !important;\n }\n\n .titleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.titleColor||t.textColor};\n font-family: var(--mermaid-font-family, "trebuchet ms", verdana, arial, sans-serif);\n }\n`),"getStyles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6355.1ac98e17.js b/pr-preview/pr-1071/assets/js/6355.1ac98e17.js deleted file mode 100644 index 8baab9318c..0000000000 --- a/pr-preview/pr-1071/assets/js/6355.1ac98e17.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6355],{76355:(t,e,n)=>{n.d(e,{diagram:()=>D});var i=n(59874),s=n(1282),r=(n(64532),n(33115),n(10483),n(8159),n(77286)),o=n(10009),a=n(3219),c=n(78041),l=n(75263),h=function(){var t=(0,o.K2)((function(t,e,n,i){for(n=n||{},i=t.length;i--;n[t[i]]=e);return n}),"o"),e=[1,4],n=[1,13],i=[1,12],s=[1,15],r=[1,16],a=[1,20],c=[1,19],l=[6,7,8],h=[1,26],u=[1,24],g=[1,25],d=[6,7,11],p=[1,31],y=[6,7,11,24],f=[1,6,13,16,17,20,23],m=[1,35],_=[1,36],b=[1,6,7,11,13,16,17,20,23],k=[1,38],E={trace:(0,o.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,mindMap:4,spaceLines:5,SPACELINE:6,NL:7,KANBAN:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,node:14,shapeData:15,ICON:16,CLASS:17,nodeWithId:18,nodeWithoutId:19,NODE_DSTART:20,NODE_DESCR:21,NODE_DEND:22,NODE_ID:23,SHAPE_DATA:24,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"KANBAN",11:"EOF",13:"SPACELIST",16:"ICON",17:"CLASS",20:"NODE_DSTART",21:"NODE_DESCR",22:"NODE_DEND",23:"NODE_ID",24:"SHAPE_DATA"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,3],[12,2],[12,2],[12,2],[12,1],[12,2],[12,1],[12,1],[12,1],[12,1],[14,1],[14,1],[19,3],[18,1],[18,4],[15,2],[15,1]],performAction:(0,o.K2)((function(t,e,n,i,s,r,o){var a=r.length-1;switch(s){case 6:case 7:return i;case 8:i.getLogger().trace("Stop NL ");break;case 9:i.getLogger().trace("Stop EOF ");break;case 11:i.getLogger().trace("Stop NL2 ");break;case 12:i.getLogger().trace("Stop EOF2 ");break;case 15:i.getLogger().info("Node: ",r[a-1].id),i.addNode(r[a-2].length,r[a-1].id,r[a-1].descr,r[a-1].type,r[a]);break;case 16:i.getLogger().info("Node: ",r[a].id),i.addNode(r[a-1].length,r[a].id,r[a].descr,r[a].type);break;case 17:i.getLogger().trace("Icon: ",r[a]),i.decorateNode({icon:r[a]});break;case 18:case 23:i.decorateNode({class:r[a]});break;case 19:i.getLogger().trace("SPACELIST");break;case 20:i.getLogger().trace("Node: ",r[a-1].id),i.addNode(0,r[a-1].id,r[a-1].descr,r[a-1].type,r[a]);break;case 21:i.getLogger().trace("Node: ",r[a].id),i.addNode(0,r[a].id,r[a].descr,r[a].type);break;case 22:i.decorateNode({icon:r[a]});break;case 27:i.getLogger().trace("node found ..",r[a-2]),this.$={id:r[a-1],descr:r[a-1],type:i.getType(r[a-2],r[a])};break;case 28:this.$={id:r[a],descr:r[a],type:0};break;case 29:i.getLogger().trace("node found ..",r[a-3]),this.$={id:r[a-3],descr:r[a-1],type:i.getType(r[a-2],r[a])};break;case 30:this.$=r[a-1]+r[a];break;case 31:this.$=r[a]}}),"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:e},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:e},{6:n,7:[1,10],9:9,12:11,13:i,14:14,16:s,17:r,18:17,19:18,20:a,23:c},t(l,[2,3]),{1:[2,2]},t(l,[2,4]),t(l,[2,5]),{1:[2,6],6:n,12:21,13:i,14:14,16:s,17:r,18:17,19:18,20:a,23:c},{6:n,9:22,12:11,13:i,14:14,16:s,17:r,18:17,19:18,20:a,23:c},{6:h,7:u,10:23,11:g},t(d,[2,24],{18:17,19:18,14:27,16:[1,28],17:[1,29],20:a,23:c}),t(d,[2,19]),t(d,[2,21],{15:30,24:p}),t(d,[2,22]),t(d,[2,23]),t(y,[2,25]),t(y,[2,26]),t(y,[2,28],{20:[1,32]}),{21:[1,33]},{6:h,7:u,10:34,11:g},{1:[2,7],6:n,12:21,13:i,14:14,16:s,17:r,18:17,19:18,20:a,23:c},t(f,[2,14],{7:m,11:_}),t(b,[2,8]),t(b,[2,9]),t(b,[2,10]),t(d,[2,16],{15:37,24:p}),t(d,[2,17]),t(d,[2,18]),t(d,[2,20],{24:k}),t(y,[2,31]),{21:[1,39]},{22:[1,40]},t(f,[2,13],{7:m,11:_}),t(b,[2,11]),t(b,[2,12]),t(d,[2,15],{24:k}),t(y,[2,30]),{22:[1,41]},t(y,[2,27]),t(y,[2,29])],defaultActions:{2:[2,1],6:[2,2]},parseError:(0,o.K2)((function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)}),"parseError"),parse:(0,o.K2)((function(t){var e=this,n=[0],i=[],s=[null],r=[],a=this.table,c="",l=0,h=0,u=0,g=r.slice.call(arguments,1),d=Object.create(this.lexer),p={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(p.yy[y]=this.yy[y]);d.setInput(t,p.yy),p.yy.lexer=d,p.yy.parser=this,void 0===d.yylloc&&(d.yylloc={});var f=d.yylloc;r.push(f);var m=d.options&&d.options.ranges;function _(){var t;return"number"!=typeof(t=i.pop()||d.lex()||1)&&(t instanceof Array&&(t=(i=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof p.yy.parseError?this.parseError=p.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,o.K2)((function(t){n.length=n.length-2*t,s.length=s.length-t,r.length=r.length-t}),"popStack"),(0,o.K2)(_,"lex");for(var b,k,E,S,N,x,D,L,I,C={};;){if(E=n[n.length-1],this.defaultActions[E]?S=this.defaultActions[E]:(null==b&&(b=_()),S=a[E]&&a[E][b]),void 0===S||!S.length||!S[0]){var O="";for(x in I=[],a[E])this.terminals_[x]&&x>2&&I.push("'"+this.terminals_[x]+"'");O=d.showPosition?"Parse error on line "+(l+1)+":\n"+d.showPosition()+"\nExpecting "+I.join(", ")+", got '"+(this.terminals_[b]||b)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==b?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(O,{text:d.match,token:this.terminals_[b]||b,line:d.yylineno,loc:f,expected:I})}if(S[0]instanceof Array&&S.length>1)throw new Error("Parse Error: multiple actions possible at state: "+E+", token: "+b);switch(S[0]){case 1:n.push(b),s.push(d.yytext),r.push(d.yylloc),n.push(S[1]),b=null,k?(b=k,k=null):(h=d.yyleng,c=d.yytext,l=d.yylineno,f=d.yylloc,u>0&&u--);break;case 2:if(D=this.productions_[S[1]][1],C.$=s[s.length-D],C._$={first_line:r[r.length-(D||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(D||1)].first_column,last_column:r[r.length-1].last_column},m&&(C._$.range=[r[r.length-(D||1)].range[0],r[r.length-1].range[1]]),void 0!==(N=this.performAction.apply(C,[c,h,l,p.yy,S[1],s,r].concat(g))))return N;D&&(n=n.slice(0,-1*D*2),s=s.slice(0,-1*D),r=r.slice(0,-1*D)),n.push(this.productions_[S[1]][0]),s.push(C.$),r.push(C._$),L=a[n[n.length-2]][n[n.length-1]],n.push(L);break;case 3:return!0}}return!0}),"parse")},S=function(){return{EOF:1,parseError:(0,o.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,o.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,o.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,o.K2)((function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var i=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===i.length?this.yylloc.first_column:0)+i[i.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,o.K2)((function(){return this._more=!0,this}),"more"),reject:(0,o.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,o.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,o.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,o.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,o.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,o.K2)((function(t,e){var n,i,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),(i=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var r in s)this[r]=s[r];return!1}return!1}),"test_match"),next:(0,o.K2)((function(){if(this.done)return this.EOF;var t,e,n,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),r=0;r<s.length;r++)if((n=this._input.match(this.rules[s[r]]))&&(!e||n[0].length>e[0].length)){if(e=n,i=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,s[r])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,s[i]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,o.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,o.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,o.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,o.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,o.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,o.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,o.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,o.K2)((function(t,e,n,i){switch(n){case 0:return this.pushState("shapeData"),e.yytext="",24;case 1:return this.pushState("shapeDataStr"),24;case 2:return this.popState(),24;case 3:const n=/\n\s*/g;return e.yytext=e.yytext.replace(n,"<br/>"),24;case 4:return 24;case 5:case 10:case 29:case 32:this.popState();break;case 6:return t.getLogger().trace("Found comment",e.yytext),6;case 7:return 8;case 8:this.begin("CLASS");break;case 9:return this.popState(),17;case 11:t.getLogger().trace("Begin icon"),this.begin("ICON");break;case 12:return t.getLogger().trace("SPACELINE"),6;case 13:return 7;case 14:return 16;case 15:t.getLogger().trace("end icon"),this.popState();break;case 16:return t.getLogger().trace("Exploding node"),this.begin("NODE"),20;case 17:return t.getLogger().trace("Cloud"),this.begin("NODE"),20;case 18:return t.getLogger().trace("Explosion Bang"),this.begin("NODE"),20;case 19:return t.getLogger().trace("Cloud Bang"),this.begin("NODE"),20;case 20:case 21:case 22:case 23:return this.begin("NODE"),20;case 24:return 13;case 25:return 23;case 26:return 11;case 27:this.begin("NSTR2");break;case 28:return"NODE_DESCR";case 30:t.getLogger().trace("Starting NSTR"),this.begin("NSTR");break;case 31:return t.getLogger().trace("description:",e.yytext),"NODE_DESCR";case 33:return this.popState(),t.getLogger().trace("node end ))"),"NODE_DEND";case 34:return this.popState(),t.getLogger().trace("node end )"),"NODE_DEND";case 35:return this.popState(),t.getLogger().trace("node end ...",e.yytext),"NODE_DEND";case 36:case 39:case 40:return this.popState(),t.getLogger().trace("node end (("),"NODE_DEND";case 37:case 38:return this.popState(),t.getLogger().trace("node end (-"),"NODE_DEND";case 41:case 42:return t.getLogger().trace("Long description:",e.yytext),21}}),"anonymous"),rules:[/^(?:@\{)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^\"]+)/i,/^(?:[^}^"]+)/i,/^(?:\})/i,/^(?:\s*%%.*)/i,/^(?:kanban\b)/i,/^(?::::)/i,/^(?:.+)/i,/^(?:\n)/i,/^(?:::icon\()/i,/^(?:[\s]+[\n])/i,/^(?:[\n]+)/i,/^(?:[^\)]+)/i,/^(?:\))/i,/^(?:-\))/i,/^(?:\(-)/i,/^(?:\)\))/i,/^(?:\))/i,/^(?:\(\()/i,/^(?:\{\{)/i,/^(?:\()/i,/^(?:\[)/i,/^(?:[\s]+)/i,/^(?:[^\(\[\n\)\{\}@]+)/i,/^(?:$)/i,/^(?:["][`])/i,/^(?:[^`"]+)/i,/^(?:[`]["])/i,/^(?:["])/i,/^(?:[^"]+)/i,/^(?:["])/i,/^(?:[\)]\))/i,/^(?:[\)])/i,/^(?:[\]])/i,/^(?:\}\})/i,/^(?:\(-)/i,/^(?:-\))/i,/^(?:\(\()/i,/^(?:\()/i,/^(?:[^\)\]\(\}]+)/i,/^(?:.+(?!\(\())/i],conditions:{shapeDataEndBracket:{rules:[],inclusive:!1},shapeDataStr:{rules:[2,3],inclusive:!1},shapeData:{rules:[1,4,5],inclusive:!1},CLASS:{rules:[9,10],inclusive:!1},ICON:{rules:[14,15],inclusive:!1},NSTR2:{rules:[28,29],inclusive:!1},NSTR:{rules:[31,32],inclusive:!1},NODE:{rules:[27,30,33,34,35,36,37,38,39,40,41,42],inclusive:!1},INITIAL:{rules:[0,6,7,8,11,12,13,16,17,18,19,20,21,22,23,24,25,26],inclusive:!0}}}}();function N(){this.yy={}}return E.lexer=S,(0,o.K2)(N,"Parser"),N.prototype=E,E.Parser=N,new N}();h.parser=h;var u=h,g=[],d=[],p=0,y={},f=(0,o.K2)((()=>{g=[],d=[],p=0,y={}}),"clear"),m=(0,o.K2)((t=>{if(0===g.length)return null;const e=g[0].level;let n=null;for(let i=g.length-1;i>=0;i--)if(g[i].level!==e||n||(n=g[i]),g[i].level<e)throw new Error('Items without section detected, found section ("'+g[i].label+'")');return t===n?.level?null:n}),"getSection"),_=(0,o.K2)((function(){return d}),"getSections"),b=(0,o.K2)((function(){const t=[],e=_(),n=(0,o.D7)();for(const i of e){const e={id:i.id,label:(0,o.jZ)(i.label??"",n),isGroup:!0,ticket:i.ticket,shape:"kanbanSection",level:i.level,look:n.look};t.push(e);const s=g.filter((t=>t.parentId===i.id));for(const r of s){const e={id:r.id,parentId:i.id,label:(0,o.jZ)(r.label??"",n),isGroup:!1,ticket:r?.ticket,priority:r?.priority,assigned:r?.assigned,icon:r?.icon,shape:"kanbanItem",level:r.level,rx:5,ry:5,cssStyles:["text-align: left"]};t.push(e)}}return{nodes:t,edges:[],other:{},config:(0,o.D7)()}}),"getData"),k=(0,o.K2)(((t,e,n,s,r)=>{const a=(0,o.D7)();let c=a.mindmap?.padding??o.UI.mindmap.padding;switch(s){case E.ROUNDED_RECT:case E.RECT:case E.HEXAGON:c*=2}const l={id:(0,o.jZ)(e,a)||"kbn"+p++,level:t,label:(0,o.jZ)(n,a),width:a.mindmap?.maxNodeWidth??o.UI.mindmap.maxNodeWidth,padding:c,isGroup:!1};if(void 0!==r){let t;t=r.includes("\n")?r+"\n":"{\n"+r+"\n}";const e=(0,i.H)(t,{schema:i.r});if(e.shape&&(e.shape!==e.shape.toLowerCase()||e.shape.includes("_")))throw new Error(`No such shape: ${e.shape}. Shape names should be lowercase.`);e?.shape&&"kanbanItem"===e.shape&&(l.shape=e?.shape),e?.label&&(l.label=e?.label),e?.icon&&(l.icon=e?.icon.toString()),e?.assigned&&(l.assigned=e?.assigned.toString()),e?.ticket&&(l.ticket=e?.ticket.toString()),e?.priority&&(l.priority=e?.priority)}const h=m(t);h?l.parentId=h.id||"kbn"+p++:d.push(l),g.push(l)}),"addNode"),E={DEFAULT:0,NO_BORDER:0,ROUNDED_RECT:1,RECT:2,CIRCLE:3,CLOUD:4,BANG:5,HEXAGON:6},S={clear:f,addNode:k,getSections:_,getData:b,nodeType:E,getType:(0,o.K2)(((t,e)=>{switch(o.Rm.debug("In get type",t,e),t){case"[":return E.RECT;case"(":return")"===e?E.ROUNDED_RECT:E.CLOUD;case"((":return E.CIRCLE;case")":return E.CLOUD;case"))":return E.BANG;case"{{":return E.HEXAGON;default:return E.DEFAULT}}),"getType"),setElementForId:(0,o.K2)(((t,e)=>{y[t]=e}),"setElementForId"),decorateNode:(0,o.K2)((t=>{if(!t)return;const e=(0,o.D7)(),n=g[g.length-1];t.icon&&(n.icon=(0,o.jZ)(t.icon,e)),t.class&&(n.cssClasses=(0,o.jZ)(t.class,e))}),"decorateNode"),type2Str:(0,o.K2)((t=>{switch(t){case E.DEFAULT:return"no-border";case E.RECT:return"rect";case E.ROUNDED_RECT:return"rounded-rect";case E.CIRCLE:return"circle";case E.CLOUD:return"cloud";case E.BANG:return"bang";case E.HEXAGON:return"hexgon";default:return"no-border"}}),"type2Str"),getLogger:(0,o.K2)((()=>o.Rm),"getLogger"),getElementById:(0,o.K2)((t=>y[t]),"getElementById")},N={draw:(0,o.K2)((async(t,e,n,i)=>{o.Rm.debug("Rendering kanban diagram\n"+t);const a=i.db.getData(),c=(0,o.D7)();c.htmlLabels=!1;const l=(0,r.D)(e),h=l.append("g");h.attr("class","sections");const u=l.append("g");u.attr("class","items");const g=a.nodes.filter((t=>t.isGroup));let d=0;const p=[];let y=25;for(const r of g){const t=c?.kanban?.sectionWidth||200;d+=1,r.x=t*d+10*(d-1)/2,r.width=t,r.y=0,r.height=3*t,r.rx=5,r.ry=5,r.cssClasses=r.cssClasses+" section-"+d;const e=await(0,s.U)(h,r);y=Math.max(y,e?.labelBBox?.height),p.push(e)}let f=0;for(const r of g){const t=p[f];f+=1;const e=c?.kanban?.sectionWidth||200,n=3*-e/2+y;let i=n;const o=a.nodes.filter((t=>t.parentId===r.id));for(const a of o){if(a.isGroup)throw new Error("Groups within groups are not allowed in Kanban diagrams");a.x=r.x,a.width=e-15;const t=(await(0,s.on)(u,a,{config:c})).node().getBBox();a.y=i+t.height/2,await(0,s.U_)(a),i=a.y+t.height/2+5}const l=t.cluster.select("rect"),h=Math.max(i-n+30,50)+(y-25);l.attr("height",h)}(0,o.ot)(void 0,l,c.mindmap?.padding??o.UI.kanban.padding,c.mindmap?.useMaxWidth??o.UI.kanban.useMaxWidth)}),"draw")},x=(0,o.K2)((t=>{let e="";for(let i=0;i<t.THEME_COLOR_LIMIT;i++)t["lineColor"+i]=t["lineColor"+i]||t["cScaleInv"+i],(0,a.A)(t["lineColor"+i])?t["lineColor"+i]=(0,c.A)(t["lineColor"+i],20):t["lineColor"+i]=(0,l.A)(t["lineColor"+i],20);const n=(0,o.K2)(((e,n)=>t.darkMode?(0,l.A)(e,n):(0,c.A)(e,n)),"adjuster");for(let i=0;i<t.THEME_COLOR_LIMIT;i++){const s=""+(17-3*i);e+=`\n .section-${i-1} rect, .section-${i-1} path, .section-${i-1} circle, .section-${i-1} polygon, .section-${i-1} path {\n fill: ${n(t["cScale"+i],10)};\n stroke: ${n(t["cScale"+i],10)};\n\n }\n .section-${i-1} text {\n fill: ${t["cScaleLabel"+i]};\n }\n .node-icon-${i-1} {\n font-size: 40px;\n color: ${t["cScaleLabel"+i]};\n }\n .section-edge-${i-1}{\n stroke: ${t["cScale"+i]};\n }\n .edge-depth-${i-1}{\n stroke-width: ${s};\n }\n .section-${i-1} line {\n stroke: ${t["cScaleInv"+i]} ;\n stroke-width: 3;\n }\n\n .disabled, .disabled circle, .disabled text {\n fill: lightgray;\n }\n .disabled text {\n fill: #efefef;\n }\n\n .node rect,\n .node circle,\n .node ellipse,\n .node polygon,\n .node path {\n fill: ${t.background};\n stroke: ${t.nodeBorder};\n stroke-width: 1px;\n }\n\n .kanban-ticket-link {\n fill: ${t.background};\n stroke: ${t.nodeBorder};\n text-decoration: underline;\n }\n `}return e}),"genSections"),D={db:S,renderer:N,parser:u,styles:(0,o.K2)((t=>`\n .edge {\n stroke-width: 3;\n }\n ${x(t)}\n .section-root rect, .section-root path, .section-root circle, .section-root polygon {\n fill: ${t.git0};\n }\n .section-root text {\n fill: ${t.gitBranchLabel0};\n }\n .icon-container {\n height:100%;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .edge {\n fill: none;\n }\n .cluster-label, .label {\n color: ${t.textColor};\n fill: ${t.textColor};\n }\n .kanban-label {\n dy: 1em;\n alignment-baseline: middle;\n text-anchor: middle;\n dominant-baseline: middle;\n text-align: center;\n }\n`),"getStyles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6383.bf218c56.js b/pr-preview/pr-1071/assets/js/6383.bf218c56.js deleted file mode 100644 index 44648f873b..0000000000 --- a/pr-preview/pr-1071/assets/js/6383.bf218c56.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6383],{87799:function(t,e,i){var n;n=function(t){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var r=e[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.i=function(t){return t},i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=7)}([function(e,i){e.exports=t},function(t,e,i){"use strict";var n=i(0).FDLayoutConstants;function r(){}for(var o in n)r[o]=n[o];r.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,r.DEFAULT_RADIAL_SEPARATION=n.DEFAULT_EDGE_LENGTH,r.DEFAULT_COMPONENT_SEPERATION=60,r.TILE=!0,r.TILING_PADDING_VERTICAL=10,r.TILING_PADDING_HORIZONTAL=10,r.TREE_REDUCTION_ON_INCREMENTAL=!1,t.exports=r},function(t,e,i){"use strict";var n=i(0).FDLayoutEdge;function r(t,e,i){n.call(this,t,e,i)}for(var o in r.prototype=Object.create(n.prototype),n)r[o]=n[o];t.exports=r},function(t,e,i){"use strict";var n=i(0).LGraph;function r(t,e,i){n.call(this,t,e,i)}for(var o in r.prototype=Object.create(n.prototype),n)r[o]=n[o];t.exports=r},function(t,e,i){"use strict";var n=i(0).LGraphManager;function r(t){n.call(this,t)}for(var o in r.prototype=Object.create(n.prototype),n)r[o]=n[o];t.exports=r},function(t,e,i){"use strict";var n=i(0).FDLayoutNode,r=i(0).IMath;function o(t,e,i,r){n.call(this,t,e,i,r)}for(var s in o.prototype=Object.create(n.prototype),n)o[s]=n[s];o.prototype.move=function(){var t=this.graphManager.getLayout();this.displacementX=t.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY=t.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren,Math.abs(this.displacementX)>t.coolingFactor*t.maxNodeDisplacement&&(this.displacementX=t.coolingFactor*t.maxNodeDisplacement*r.sign(this.displacementX)),Math.abs(this.displacementY)>t.coolingFactor*t.maxNodeDisplacement&&(this.displacementY=t.coolingFactor*t.maxNodeDisplacement*r.sign(this.displacementY)),null==this.child||0==this.child.getNodes().length?this.moveBy(this.displacementX,this.displacementY):this.propogateDisplacementToChildren(this.displacementX,this.displacementY),t.totalDisplacement+=Math.abs(this.displacementX)+Math.abs(this.displacementY),this.springForceX=0,this.springForceY=0,this.repulsionForceX=0,this.repulsionForceY=0,this.gravitationForceX=0,this.gravitationForceY=0,this.displacementX=0,this.displacementY=0},o.prototype.propogateDisplacementToChildren=function(t,e){for(var i,n=this.getChild().getNodes(),r=0;r<n.length;r++)null==(i=n[r]).getChild()?(i.moveBy(t,e),i.displacementX+=t,i.displacementY+=e):i.propogateDisplacementToChildren(t,e)},o.prototype.setPred1=function(t){this.pred1=t},o.prototype.getPred1=function(){return pred1},o.prototype.getPred2=function(){return pred2},o.prototype.setNext=function(t){this.next=t},o.prototype.getNext=function(){return next},o.prototype.setProcessed=function(t){this.processed=t},o.prototype.isProcessed=function(){return processed},t.exports=o},function(t,e,i){"use strict";var n=i(0).FDLayout,r=i(4),o=i(3),s=i(5),a=i(2),h=i(1),l=i(0).FDLayoutConstants,c=i(0).LayoutConstants,g=i(0).Point,u=i(0).PointD,d=i(0).Layout,p=i(0).Integer,f=i(0).IGeometry,y=i(0).LGraph,E=i(0).Transform;function _(){n.call(this),this.toBeTiled={}}for(var m in _.prototype=Object.create(n.prototype),n)_[m]=n[m];_.prototype.newGraphManager=function(){var t=new r(this);return this.graphManager=t,t},_.prototype.newGraph=function(t){return new o(null,this.graphManager,t)},_.prototype.newNode=function(t){return new s(this.graphManager,t)},_.prototype.newEdge=function(t){return new a(null,null,t)},_.prototype.initParameters=function(){n.prototype.initParameters.call(this,arguments),this.isSubLayout||(h.DEFAULT_EDGE_LENGTH<10?this.idealEdgeLength=10:this.idealEdgeLength=h.DEFAULT_EDGE_LENGTH,this.useSmartIdealEdgeLengthCalculation=h.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.springConstant=l.DEFAULT_SPRING_STRENGTH,this.repulsionConstant=l.DEFAULT_REPULSION_STRENGTH,this.gravityConstant=l.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=l.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=l.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.prunedNodesAll=[],this.growTreeIterations=0,this.afterGrowthIterations=0,this.isTreeGrowing=!1,this.isGrowthFinished=!1,this.coolingCycle=0,this.maxCoolingCycle=this.maxIterations/l.CONVERGENCE_CHECK_PERIOD,this.finalTemperature=l.CONVERGENCE_CHECK_PERIOD/this.maxIterations,this.coolingAdjuster=1)},_.prototype.layout=function(){return c.DEFAULT_CREATE_BENDS_AS_NEEDED&&(this.createBendpoints(),this.graphManager.resetAllEdges()),this.level=0,this.classicLayout()},_.prototype.classicLayout=function(){if(this.nodesWithGravity=this.calculateNodesToApplyGravitationTo(),this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity),this.calcNoOfChildrenForAllNodes(),this.graphManager.calcLowestCommonAncestors(),this.graphManager.calcInclusionTreeDepths(),this.graphManager.getRoot().calcEstimatedSize(),this.calcIdealEdgeLengths(),this.incremental)h.TREE_REDUCTION_ON_INCREMENTAL&&(this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation(),e=new Set(this.getAllNodes()),i=this.nodesWithGravity.filter((function(t){return e.has(t)})),this.graphManager.setAllNodesToApplyGravitation(i));else{var t=this.getFlatForest();if(t.length>0)this.positionNodesRadially(t);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var e=new Set(this.getAllNodes()),i=this.nodesWithGravity.filter((function(t){return e.has(t)}));this.graphManager.setAllNodesToApplyGravitation(i),this.positionNodesRandomly()}}return this.initSpringEmbedder(),this.runSpringEmbedder(),!0},_.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished){if(!(this.prunedNodesAll.length>0))return!0;this.isTreeGrowing=!0}if(this.totalIterations%l.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged()){if(!(this.prunedNodesAll.length>0))return!0;this.isTreeGrowing=!0}this.coolingCycle++,0==this.layoutQuality?this.coolingAdjuster=this.coolingCycle:1==this.layoutQuality&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var t=new Set(this.getAllNodes()),e=this.nodesWithGravity.filter((function(e){return t.has(e)}));this.graphManager.setAllNodesToApplyGravitation(e),this.graphManager.updateBounds(),this.updateGrid(),this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var i=!this.isTreeGrowing&&!this.isGrowthFinished,n=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(i,n),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},_.prototype.getPositionsData=function(){for(var t=this.graphManager.getAllNodes(),e={},i=0;i<t.length;i++){var n=t[i].rect,r=t[i].id;e[r]={id:r,x:n.getCenterX(),y:n.getCenterY(),w:n.width,h:n.height}}return e},_.prototype.runSpringEmbedder=function(){this.initialAnimationPeriod=25,this.animationPeriod=this.initialAnimationPeriod;var t=!1;if("during"===l.ANIMATE)this.emit("layoutstarted");else{for(;!t;)t=this.tick();this.graphManager.updateBounds()}},_.prototype.calculateNodesToApplyGravitationTo=function(){var t,e,i=[],n=this.graphManager.getGraphs(),r=n.length;for(e=0;e<r;e++)(t=n[e]).updateConnected(),t.isConnected||(i=i.concat(t.getNodes()));return i},_.prototype.createBendpoints=function(){var t=[];t=t.concat(this.graphManager.getAllEdges());var e,i=new Set;for(e=0;e<t.length;e++){var n=t[e];if(!i.has(n)){var r=n.getSource(),o=n.getTarget();if(r==o)n.getBendpoints().push(new u),n.getBendpoints().push(new u),this.createDummyNodesForBendpoints(n),i.add(n);else{var s=[];if(s=(s=s.concat(r.getEdgeListToNode(o))).concat(o.getEdgeListToNode(r)),!i.has(s[0])){var a;if(s.length>1)for(a=0;a<s.length;a++){var h=s[a];h.getBendpoints().push(new u),this.createDummyNodesForBendpoints(h)}s.forEach((function(t){i.add(t)}))}}}if(i.size==t.length)break}},_.prototype.positionNodesRadially=function(t){for(var e=new g(0,0),i=Math.ceil(Math.sqrt(t.length)),n=0,r=0,o=0,s=new u(0,0),a=0;a<t.length;a++){a%i==0&&(o=0,r=n,0!=a&&(r+=h.DEFAULT_COMPONENT_SEPERATION),n=0);var l=t[a],p=d.findCenterOfTree(l);e.x=o,e.y=r,(s=_.radialLayout(l,p,e)).y>n&&(n=Math.floor(s.y)),o=Math.floor(s.x+h.DEFAULT_COMPONENT_SEPERATION)}this.transform(new u(c.WORLD_CENTER_X-s.x/2,c.WORLD_CENTER_Y-s.y/2))},_.radialLayout=function(t,e,i){var n=Math.max(this.maxDiagonalInTree(t),h.DEFAULT_RADIAL_SEPARATION);_.branchRadialLayout(e,null,0,359,0,n);var r=y.calculateBounds(t),o=new E;o.setDeviceOrgX(r.getMinX()),o.setDeviceOrgY(r.getMinY()),o.setWorldOrgX(i.x),o.setWorldOrgY(i.y);for(var s=0;s<t.length;s++)t[s].transform(o);var a=new u(r.getMaxX(),r.getMaxY());return o.inverseTransformPoint(a)},_.branchRadialLayout=function(t,e,i,n,r,o){var s=(n-i+1)/2;s<0&&(s+=180);var a=(s+i)%360*f.TWO_PI/360,h=(Math.cos(a),r*Math.cos(a)),l=r*Math.sin(a);t.setCenter(h,l);var c=[],g=(c=c.concat(t.getEdges())).length;null!=e&&g--;for(var u,d=0,p=c.length,y=t.getEdgesBetween(e);y.length>1;){var E=y[0];y.splice(0,1);var m=c.indexOf(E);m>=0&&c.splice(m,1),p--,g--}u=null!=e?(c.indexOf(y[0])+1)%p:0;for(var v=Math.abs(n-i)/g,N=u;d!=g;N=++N%p){var A=c[N].getOtherEnd(t);if(A!=e){var L=(i+d*v)%360,T=(L+v)%360;_.branchRadialLayout(A,t,L,T,r+o,o),d++}}},_.maxDiagonalInTree=function(t){for(var e=p.MIN_VALUE,i=0;i<t.length;i++){var n=t[i].getDiagonal();n>e&&(e=n)}return e},_.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},_.prototype.groupZeroDegreeMembers=function(){var t=this,e={};this.memberGroups={},this.idToDummyNode={};for(var i=[],n=this.graphManager.getAllNodes(),r=0;r<n.length;r++){var o=(a=n[r]).getParent();0!==this.getNodeDegreeWithChildren(a)||null!=o.id&&this.getToBeTiled(o)||i.push(a)}for(r=0;r<i.length;r++){var a,h=(a=i[r]).getParent().id;void 0===e[h]&&(e[h]=[]),e[h]=e[h].concat(a)}Object.keys(e).forEach((function(i){if(e[i].length>1){var n="DummyCompound_"+i;t.memberGroups[n]=e[i];var r=e[i][0].getParent(),o=new s(t.graphManager);o.id=n,o.paddingLeft=r.paddingLeft||0,o.paddingRight=r.paddingRight||0,o.paddingBottom=r.paddingBottom||0,o.paddingTop=r.paddingTop||0,t.idToDummyNode[n]=o;var a=t.getGraphManager().add(t.newGraph(),o),h=r.getChild();h.add(o);for(var l=0;l<e[i].length;l++){var c=e[i][l];h.remove(c),a.add(c)}}}))},_.prototype.clearCompounds=function(){var t={},e={};this.performDFSOnCompounds();for(var i=0;i<this.compoundOrder.length;i++)e[this.compoundOrder[i].id]=this.compoundOrder[i],t[this.compoundOrder[i].id]=[].concat(this.compoundOrder[i].getChild().getNodes()),this.graphManager.remove(this.compoundOrder[i].getChild()),this.compoundOrder[i].child=null;this.graphManager.resetAllNodes(),this.tileCompoundMembers(t,e)},_.prototype.clearZeroDegreeMembers=function(){var t=this,e=this.tiledZeroDegreePack=[];Object.keys(this.memberGroups).forEach((function(i){var n=t.idToDummyNode[i];e[i]=t.tileNodes(t.memberGroups[i],n.paddingLeft+n.paddingRight),n.rect.width=e[i].width,n.rect.height=e[i].height}))},_.prototype.repopulateCompounds=function(){for(var t=this.compoundOrder.length-1;t>=0;t--){var e=this.compoundOrder[t],i=e.id,n=e.paddingLeft,r=e.paddingTop;this.adjustLocations(this.tiledMemberPack[i],e.rect.x,e.rect.y,n,r)}},_.prototype.repopulateZeroDegreeMembers=function(){var t=this,e=this.tiledZeroDegreePack;Object.keys(e).forEach((function(i){var n=t.idToDummyNode[i],r=n.paddingLeft,o=n.paddingTop;t.adjustLocations(e[i],n.rect.x,n.rect.y,r,o)}))},_.prototype.getToBeTiled=function(t){var e=t.id;if(null!=this.toBeTiled[e])return this.toBeTiled[e];var i=t.getChild();if(null==i)return this.toBeTiled[e]=!1,!1;for(var n=i.getNodes(),r=0;r<n.length;r++){var o=n[r];if(this.getNodeDegree(o)>0)return this.toBeTiled[e]=!1,!1;if(null!=o.getChild()){if(!this.getToBeTiled(o))return this.toBeTiled[e]=!1,!1}else this.toBeTiled[o.id]=!1}return this.toBeTiled[e]=!0,!0},_.prototype.getNodeDegree=function(t){t.id;for(var e=t.getEdges(),i=0,n=0;n<e.length;n++){var r=e[n];r.getSource().id!==r.getTarget().id&&(i+=1)}return i},_.prototype.getNodeDegreeWithChildren=function(t){var e=this.getNodeDegree(t);if(null==t.getChild())return e;for(var i=t.getChild().getNodes(),n=0;n<i.length;n++){var r=i[n];e+=this.getNodeDegreeWithChildren(r)}return e},_.prototype.performDFSOnCompounds=function(){this.compoundOrder=[],this.fillCompexOrderByDFS(this.graphManager.getRoot().getNodes())},_.prototype.fillCompexOrderByDFS=function(t){for(var e=0;e<t.length;e++){var i=t[e];null!=i.getChild()&&this.fillCompexOrderByDFS(i.getChild().getNodes()),this.getToBeTiled(i)&&this.compoundOrder.push(i)}},_.prototype.adjustLocations=function(t,e,i,n,r){i+=r;for(var o=e+=n,s=0;s<t.rows.length;s++){var a=t.rows[s];e=o;for(var h=0,l=0;l<a.length;l++){var c=a[l];c.rect.x=e,c.rect.y=i,e+=c.rect.width+t.horizontalPadding,c.rect.height>h&&(h=c.rect.height)}i+=h+t.verticalPadding}},_.prototype.tileCompoundMembers=function(t,e){var i=this;this.tiledMemberPack=[],Object.keys(t).forEach((function(n){var r=e[n];i.tiledMemberPack[n]=i.tileNodes(t[n],r.paddingLeft+r.paddingRight),r.rect.width=i.tiledMemberPack[n].width,r.rect.height=i.tiledMemberPack[n].height}))},_.prototype.tileNodes=function(t,e){var i={rows:[],rowWidth:[],rowHeight:[],width:0,height:e,verticalPadding:h.TILING_PADDING_VERTICAL,horizontalPadding:h.TILING_PADDING_HORIZONTAL};t.sort((function(t,e){return t.rect.width*t.rect.height>e.rect.width*e.rect.height?-1:t.rect.width*t.rect.height<e.rect.width*e.rect.height?1:0}));for(var n=0;n<t.length;n++){var r=t[n];0==i.rows.length?this.insertNodeToRow(i,r,0,e):this.canAddHorizontal(i,r.rect.width,r.rect.height)?this.insertNodeToRow(i,r,this.getShortestRowIndex(i),e):this.insertNodeToRow(i,r,i.rows.length,e),this.shiftToLastRow(i)}return i},_.prototype.insertNodeToRow=function(t,e,i,n){var r=n;i==t.rows.length&&(t.rows.push([]),t.rowWidth.push(r),t.rowHeight.push(0));var o=t.rowWidth[i]+e.rect.width;t.rows[i].length>0&&(o+=t.horizontalPadding),t.rowWidth[i]=o,t.width<o&&(t.width=o);var s=e.rect.height;i>0&&(s+=t.verticalPadding);var a=0;s>t.rowHeight[i]&&(a=t.rowHeight[i],t.rowHeight[i]=s,a=t.rowHeight[i]-a),t.height+=a,t.rows[i].push(e)},_.prototype.getShortestRowIndex=function(t){for(var e=-1,i=Number.MAX_VALUE,n=0;n<t.rows.length;n++)t.rowWidth[n]<i&&(e=n,i=t.rowWidth[n]);return e},_.prototype.getLongestRowIndex=function(t){for(var e=-1,i=Number.MIN_VALUE,n=0;n<t.rows.length;n++)t.rowWidth[n]>i&&(e=n,i=t.rowWidth[n]);return e},_.prototype.canAddHorizontal=function(t,e,i){var n=this.getShortestRowIndex(t);if(n<0)return!0;var r=t.rowWidth[n];if(r+t.horizontalPadding+e<=t.width)return!0;var o,s,a=0;return t.rowHeight[n]<i&&n>0&&(a=i+t.verticalPadding-t.rowHeight[n]),o=t.width-r>=e+t.horizontalPadding?(t.height+a)/(r+e+t.horizontalPadding):(t.height+a)/t.width,a=i+t.verticalPadding,(s=t.width<e?(t.height+a)/e:(t.height+a)/t.width)<1&&(s=1/s),o<1&&(o=1/o),o<s},_.prototype.shiftToLastRow=function(t){var e=this.getLongestRowIndex(t),i=t.rowWidth.length-1,n=t.rows[e],r=n[n.length-1],o=r.width+t.horizontalPadding;if(t.width-t.rowWidth[i]>o&&e!=i){n.splice(-1,1),t.rows[i].push(r),t.rowWidth[e]=t.rowWidth[e]-o,t.rowWidth[i]=t.rowWidth[i]+o,t.width=t.rowWidth[instance.getLongestRowIndex(t)];for(var s=Number.MIN_VALUE,a=0;a<n.length;a++)n[a].height>s&&(s=n[a].height);e>0&&(s+=t.verticalPadding);var h=t.rowHeight[e]+t.rowHeight[i];t.rowHeight[e]=s,t.rowHeight[i]<r.height+t.verticalPadding&&(t.rowHeight[i]=r.height+t.verticalPadding);var l=t.rowHeight[e]+t.rowHeight[i];t.height+=l-h,this.shiftToLastRow(t)}},_.prototype.tilingPreLayout=function(){h.TILE&&(this.groupZeroDegreeMembers(),this.clearCompounds(),this.clearZeroDegreeMembers())},_.prototype.tilingPostLayout=function(){h.TILE&&(this.repopulateZeroDegreeMembers(),this.repopulateCompounds())},_.prototype.reduceTrees=function(){for(var t,e=[],i=!0;i;){var n=this.graphManager.getAllNodes(),r=[];i=!1;for(var o=0;o<n.length;o++)1!=(t=n[o]).getEdges().length||t.getEdges()[0].isInterGraph||null!=t.getChild()||(r.push([t,t.getEdges()[0],t.getOwner()]),i=!0);if(1==i){for(var s=[],a=0;a<r.length;a++)1==r[a][0].getEdges().length&&(s.push(r[a]),r[a][0].getOwner().remove(r[a][0]));e.push(s),this.graphManager.resetAllNodes(),this.graphManager.resetAllEdges()}}this.prunedNodesAll=e},_.prototype.growTree=function(t){for(var e,i=t[t.length-1],n=0;n<i.length;n++)e=i[n],this.findPlaceforPrunedNode(e),e[2].add(e[0]),e[2].add(e[1],e[1].source,e[1].target);t.splice(t.length-1,1),this.graphManager.resetAllNodes(),this.graphManager.resetAllEdges()},_.prototype.findPlaceforPrunedNode=function(t){var e,i,n=t[0],r=(i=n==t[1].source?t[1].target:t[1].source).startX,o=i.finishX,s=i.startY,a=i.finishY,h=[0,0,0,0];if(s>0)for(var c=r;c<=o;c++)h[0]+=this.grid[c][s-1].length+this.grid[c][s].length-1;if(o<this.grid.length-1)for(c=s;c<=a;c++)h[1]+=this.grid[o+1][c].length+this.grid[o][c].length-1;if(a<this.grid[0].length-1)for(c=r;c<=o;c++)h[2]+=this.grid[c][a+1].length+this.grid[c][a].length-1;if(r>0)for(c=s;c<=a;c++)h[3]+=this.grid[r-1][c].length+this.grid[r][c].length-1;for(var g,u,d=p.MAX_VALUE,f=0;f<h.length;f++)h[f]<d?(d=h[f],g=1,u=f):h[f]==d&&g++;if(3==g&&0==d)0==h[0]&&0==h[1]&&0==h[2]?e=1:0==h[0]&&0==h[1]&&0==h[3]?e=0:0==h[0]&&0==h[2]&&0==h[3]?e=3:0==h[1]&&0==h[2]&&0==h[3]&&(e=2);else if(2==g&&0==d){var y=Math.floor(2*Math.random());e=0==h[0]&&0==h[1]?0==y?0:1:0==h[0]&&0==h[2]?0==y?0:2:0==h[0]&&0==h[3]?0==y?0:3:0==h[1]&&0==h[2]?0==y?1:2:0==h[1]&&0==h[3]?0==y?1:3:0==y?2:3}else e=4==g&&0==d?y=Math.floor(4*Math.random()):u;0==e?n.setCenter(i.getCenterX(),i.getCenterY()-i.getHeight()/2-l.DEFAULT_EDGE_LENGTH-n.getHeight()/2):1==e?n.setCenter(i.getCenterX()+i.getWidth()/2+l.DEFAULT_EDGE_LENGTH+n.getWidth()/2,i.getCenterY()):2==e?n.setCenter(i.getCenterX(),i.getCenterY()+i.getHeight()/2+l.DEFAULT_EDGE_LENGTH+n.getHeight()/2):n.setCenter(i.getCenterX()-i.getWidth()/2-l.DEFAULT_EDGE_LENGTH-n.getWidth()/2,i.getCenterY())},t.exports=_},function(t,e,i){"use strict";var n={};n.layoutBase=i(0),n.CoSEConstants=i(1),n.CoSEEdge=i(2),n.CoSEGraph=i(3),n.CoSEGraphManager=i(4),n.CoSELayout=i(6),n.CoSENode=i(5),t.exports=n}])},t.exports=n(i(23143))},43457:function(t,e,i){var n;n=function(t){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var r=e[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.i=function(t){return t},i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=1)}([function(e,i){e.exports=t},function(t,e,i){"use strict";var n=i(0).layoutBase.LayoutConstants,r=i(0).layoutBase.FDLayoutConstants,o=i(0).CoSEConstants,s=i(0).CoSELayout,a=i(0).CoSENode,h=i(0).layoutBase.PointD,l=i(0).layoutBase.DimensionD,c={ready:function(){},stop:function(){},quality:"default",nodeDimensionsIncludeLabels:!1,refresh:30,fit:!0,padding:10,randomize:!0,nodeRepulsion:4500,idealEdgeLength:50,edgeElasticity:.45,nestingFactor:.1,gravity:.25,numIter:2500,tile:!0,animate:"end",animationDuration:500,tilingPaddingVertical:10,tilingPaddingHorizontal:10,gravityRangeCompound:1.5,gravityCompound:1,gravityRange:3.8,initialEnergyOnIncremental:.5};function g(t){this.options=function(t,e){var i={};for(var n in t)i[n]=t[n];for(var n in e)i[n]=e[n];return i}(c,t),u(this.options)}var u=function(t){null!=t.nodeRepulsion&&(o.DEFAULT_REPULSION_STRENGTH=r.DEFAULT_REPULSION_STRENGTH=t.nodeRepulsion),null!=t.idealEdgeLength&&(o.DEFAULT_EDGE_LENGTH=r.DEFAULT_EDGE_LENGTH=t.idealEdgeLength),null!=t.edgeElasticity&&(o.DEFAULT_SPRING_STRENGTH=r.DEFAULT_SPRING_STRENGTH=t.edgeElasticity),null!=t.nestingFactor&&(o.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=r.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=t.nestingFactor),null!=t.gravity&&(o.DEFAULT_GRAVITY_STRENGTH=r.DEFAULT_GRAVITY_STRENGTH=t.gravity),null!=t.numIter&&(o.MAX_ITERATIONS=r.MAX_ITERATIONS=t.numIter),null!=t.gravityRange&&(o.DEFAULT_GRAVITY_RANGE_FACTOR=r.DEFAULT_GRAVITY_RANGE_FACTOR=t.gravityRange),null!=t.gravityCompound&&(o.DEFAULT_COMPOUND_GRAVITY_STRENGTH=r.DEFAULT_COMPOUND_GRAVITY_STRENGTH=t.gravityCompound),null!=t.gravityRangeCompound&&(o.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=r.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=t.gravityRangeCompound),null!=t.initialEnergyOnIncremental&&(o.DEFAULT_COOLING_FACTOR_INCREMENTAL=r.DEFAULT_COOLING_FACTOR_INCREMENTAL=t.initialEnergyOnIncremental),"draft"==t.quality?n.QUALITY=0:"proof"==t.quality?n.QUALITY=2:n.QUALITY=1,o.NODE_DIMENSIONS_INCLUDE_LABELS=r.NODE_DIMENSIONS_INCLUDE_LABELS=n.NODE_DIMENSIONS_INCLUDE_LABELS=t.nodeDimensionsIncludeLabels,o.DEFAULT_INCREMENTAL=r.DEFAULT_INCREMENTAL=n.DEFAULT_INCREMENTAL=!t.randomize,o.ANIMATE=r.ANIMATE=n.ANIMATE=t.animate,o.TILE=t.tile,o.TILING_PADDING_VERTICAL="function"==typeof t.tilingPaddingVertical?t.tilingPaddingVertical.call():t.tilingPaddingVertical,o.TILING_PADDING_HORIZONTAL="function"==typeof t.tilingPaddingHorizontal?t.tilingPaddingHorizontal.call():t.tilingPaddingHorizontal};g.prototype.run=function(){var t,e,i=this.options,n=(this.idToLNode={},this.layout=new s),r=this;r.stopped=!1,this.cy=this.options.cy,this.cy.trigger({type:"layoutstart",layout:this});var o=n.newGraphManager();this.gm=o;var a=this.options.eles.nodes(),h=this.options.eles.edges();this.root=o.addRoot(),this.processChildrenList(this.root,this.getTopMostNodes(a),n);for(var l=0;l<h.length;l++){var c=h[l],g=this.idToLNode[c.data("source")],u=this.idToLNode[c.data("target")];g!==u&&0==g.getEdgesBetween(u).length&&(o.add(n.newEdge(),g,u).id=c.id())}var d=function(t,e){"number"==typeof t&&(t=e);var i=t.data("id"),n=r.idToLNode[i];return{x:n.getRect().getCenterX(),y:n.getRect().getCenterY()}},p=function o(){for(var s,a=function(){i.fit&&i.cy.fit(i.eles,i.padding),t||(t=!0,r.cy.one("layoutready",i.ready),r.cy.trigger({type:"layoutready",layout:r}))},h=r.options.refresh,l=0;l<h&&!s;l++)s=r.stopped||r.layout.tick();if(s)return n.checkLayoutSuccess()&&!n.isSubLayout&&n.doPostLayout(),n.tilingPostLayout&&n.tilingPostLayout(),n.isLayoutFinished=!0,r.options.eles.nodes().positions(d),a(),r.cy.one("layoutstop",r.options.stop),r.cy.trigger({type:"layoutstop",layout:r}),e&&cancelAnimationFrame(e),void(t=!1);var c=r.layout.getPositionsData();i.eles.nodes().positions((function(t,e){if("number"==typeof t&&(t=e),!t.isParent()){for(var i=t.id(),n=c[i],r=t;null==n&&(n=c[r.data("parent")]||c["DummyCompound_"+r.data("parent")],c[i]=n,null!=(r=r.parent()[0])););return null!=n?{x:n.x,y:n.y}:{x:t.position("x"),y:t.position("y")}}})),a(),e=requestAnimationFrame(o)};return n.addListener("layoutstarted",(function(){"during"===r.options.animate&&(e=requestAnimationFrame(p))})),n.runLayout(),"during"!==this.options.animate&&(r.options.eles.nodes().not(":parent").layoutPositions(r,r.options,d),t=!1),this},g.prototype.getTopMostNodes=function(t){for(var e={},i=0;i<t.length;i++)e[t[i].id()]=!0;var n=t.filter((function(t,i){"number"==typeof t&&(t=i);for(var n=t.parent()[0];null!=n;){if(e[n.id()])return!1;n=n.parent()[0]}return!0}));return n},g.prototype.processChildrenList=function(t,e,i){for(var n=e.length,r=0;r<n;r++){var o,s,c=e[r],g=c.children(),u=c.layoutDimensions({nodeDimensionsIncludeLabels:this.options.nodeDimensionsIncludeLabels});if((o=null!=c.outerWidth()&&null!=c.outerHeight()?t.add(new a(i.graphManager,new h(c.position("x")-u.w/2,c.position("y")-u.h/2),new l(parseFloat(u.w),parseFloat(u.h)))):t.add(new a(this.graphManager))).id=c.data("id"),o.paddingLeft=parseInt(c.css("padding")),o.paddingTop=parseInt(c.css("padding")),o.paddingRight=parseInt(c.css("padding")),o.paddingBottom=parseInt(c.css("padding")),this.options.nodeDimensionsIncludeLabels&&c.isParent()){var d=c.boundingBox({includeLabels:!0,includeNodes:!1}).w,p=c.boundingBox({includeLabels:!0,includeNodes:!1}).h,f=c.css("text-halign");o.labelWidth=d,o.labelHeight=p,o.labelPos=f}this.idToLNode[c.data("id")]=o,isNaN(o.rect.x)&&(o.rect.x=0),isNaN(o.rect.y)&&(o.rect.y=0),null!=g&&g.length>0&&(s=i.getGraphManager().add(i.newGraph(),o),this.processChildrenList(s,g,i))}},g.prototype.stop=function(){return this.stopped=!0,this};var d=function(t){t("layout","cose-bilkent",g)};"undefined"!=typeof cytoscape&&d(cytoscape),t.exports=d}])},t.exports=n(i(87799))},23143:function(t){var e;e=function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var r=e[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.i=function(t){return t},i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=26)}([function(t,e,i){"use strict";function n(){}n.QUALITY=1,n.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,n.DEFAULT_INCREMENTAL=!1,n.DEFAULT_ANIMATION_ON_LAYOUT=!0,n.DEFAULT_ANIMATION_DURING_LAYOUT=!1,n.DEFAULT_ANIMATION_PERIOD=50,n.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,n.DEFAULT_GRAPH_MARGIN=15,n.NODE_DIMENSIONS_INCLUDE_LABELS=!1,n.SIMPLE_NODE_SIZE=40,n.SIMPLE_NODE_HALF_SIZE=n.SIMPLE_NODE_SIZE/2,n.EMPTY_COMPOUND_NODE_SIZE=40,n.MIN_EDGE_LENGTH=1,n.WORLD_BOUNDARY=1e6,n.INITIAL_WORLD_BOUNDARY=n.WORLD_BOUNDARY/1e3,n.WORLD_CENTER_X=1200,n.WORLD_CENTER_Y=900,t.exports=n},function(t,e,i){"use strict";var n=i(2),r=i(8),o=i(9);function s(t,e,i){n.call(this,i),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=i,this.bendpoints=[],this.source=t,this.target=e}for(var a in s.prototype=Object.create(n.prototype),n)s[a]=n[a];s.prototype.getSource=function(){return this.source},s.prototype.getTarget=function(){return this.target},s.prototype.isInterGraph=function(){return this.isInterGraph},s.prototype.getLength=function(){return this.length},s.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},s.prototype.getBendpoints=function(){return this.bendpoints},s.prototype.getLca=function(){return this.lca},s.prototype.getSourceInLca=function(){return this.sourceInLca},s.prototype.getTargetInLca=function(){return this.targetInLca},s.prototype.getOtherEnd=function(t){if(this.source===t)return this.target;if(this.target===t)return this.source;throw"Node is not incident with this edge"},s.prototype.getOtherEndInGraph=function(t,e){for(var i=this.getOtherEnd(t),n=e.getGraphManager().getRoot();;){if(i.getOwner()==e)return i;if(i.getOwner()==n)break;i=i.getOwner().getParent()}return null},s.prototype.updateLength=function(){var t=new Array(4);this.isOverlapingSourceAndTarget=r.getIntersection(this.target.getRect(),this.source.getRect(),t),this.isOverlapingSourceAndTarget||(this.lengthX=t[0]-t[2],this.lengthY=t[1]-t[3],Math.abs(this.lengthX)<1&&(this.lengthX=o.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=o.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},s.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=o.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=o.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},t.exports=s},function(t,e,i){"use strict";t.exports=function(t){this.vGraphObject=t}},function(t,e,i){"use strict";var n=i(2),r=i(10),o=i(13),s=i(0),a=i(16),h=i(4);function l(t,e,i,s){null==i&&null==s&&(s=e),n.call(this,s),null!=t.graphManager&&(t=t.graphManager),this.estimatedSize=r.MIN_VALUE,this.inclusionTreeDepth=r.MAX_VALUE,this.vGraphObject=s,this.edges=[],this.graphManager=t,this.rect=null!=i&&null!=e?new o(e.x,e.y,i.width,i.height):new o}for(var c in l.prototype=Object.create(n.prototype),n)l[c]=n[c];l.prototype.getEdges=function(){return this.edges},l.prototype.getChild=function(){return this.child},l.prototype.getOwner=function(){return this.owner},l.prototype.getWidth=function(){return this.rect.width},l.prototype.setWidth=function(t){this.rect.width=t},l.prototype.getHeight=function(){return this.rect.height},l.prototype.setHeight=function(t){this.rect.height=t},l.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},l.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},l.prototype.getCenter=function(){return new h(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},l.prototype.getLocation=function(){return new h(this.rect.x,this.rect.y)},l.prototype.getRect=function(){return this.rect},l.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},l.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},l.prototype.setRect=function(t,e){this.rect.x=t.x,this.rect.y=t.y,this.rect.width=e.width,this.rect.height=e.height},l.prototype.setCenter=function(t,e){this.rect.x=t-this.rect.width/2,this.rect.y=e-this.rect.height/2},l.prototype.setLocation=function(t,e){this.rect.x=t,this.rect.y=e},l.prototype.moveBy=function(t,e){this.rect.x+=t,this.rect.y+=e},l.prototype.getEdgeListToNode=function(t){var e=[],i=this;return i.edges.forEach((function(n){if(n.target==t){if(n.source!=i)throw"Incorrect edge source!";e.push(n)}})),e},l.prototype.getEdgesBetween=function(t){var e=[],i=this;return i.edges.forEach((function(n){if(n.source!=i&&n.target!=i)throw"Incorrect edge source and/or target";n.target!=t&&n.source!=t||e.push(n)})),e},l.prototype.getNeighborsList=function(){var t=new Set,e=this;return e.edges.forEach((function(i){if(i.source==e)t.add(i.target);else{if(i.target!=e)throw"Incorrect incidency!";t.add(i.source)}})),t},l.prototype.withChildren=function(){var t=new Set;if(t.add(this),null!=this.child)for(var e=this.child.getNodes(),i=0;i<e.length;i++)e[i].withChildren().forEach((function(e){t.add(e)}));return t},l.prototype.getNoOfChildren=function(){var t=0;if(null==this.child)t=1;else for(var e=this.child.getNodes(),i=0;i<e.length;i++)t+=e[i].getNoOfChildren();return 0==t&&(t=1),t},l.prototype.getEstimatedSize=function(){if(this.estimatedSize==r.MIN_VALUE)throw"assert failed";return this.estimatedSize},l.prototype.calcEstimatedSize=function(){return null==this.child?this.estimatedSize=(this.rect.width+this.rect.height)/2:(this.estimatedSize=this.child.calcEstimatedSize(),this.rect.width=this.estimatedSize,this.rect.height=this.estimatedSize,this.estimatedSize)},l.prototype.scatter=function(){var t,e,i=-s.INITIAL_WORLD_BOUNDARY,n=s.INITIAL_WORLD_BOUNDARY;t=s.WORLD_CENTER_X+a.nextDouble()*(n-i)+i;var r=-s.INITIAL_WORLD_BOUNDARY,o=s.INITIAL_WORLD_BOUNDARY;e=s.WORLD_CENTER_Y+a.nextDouble()*(o-r)+r,this.rect.x=t,this.rect.y=e},l.prototype.updateBounds=function(){if(null==this.getChild())throw"assert failed";if(0!=this.getChild().getNodes().length){var t=this.getChild();if(t.updateBounds(!0),this.rect.x=t.getLeft(),this.rect.y=t.getTop(),this.setWidth(t.getRight()-t.getLeft()),this.setHeight(t.getBottom()-t.getTop()),s.NODE_DIMENSIONS_INCLUDE_LABELS){var e=t.getRight()-t.getLeft(),i=t.getBottom()-t.getTop();this.labelWidth>e&&(this.rect.x-=(this.labelWidth-e)/2,this.setWidth(this.labelWidth)),this.labelHeight>i&&("center"==this.labelPos?this.rect.y-=(this.labelHeight-i)/2:"top"==this.labelPos&&(this.rect.y-=this.labelHeight-i),this.setHeight(this.labelHeight))}}},l.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==r.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},l.prototype.transform=function(t){var e=this.rect.x;e>s.WORLD_BOUNDARY?e=s.WORLD_BOUNDARY:e<-s.WORLD_BOUNDARY&&(e=-s.WORLD_BOUNDARY);var i=this.rect.y;i>s.WORLD_BOUNDARY?i=s.WORLD_BOUNDARY:i<-s.WORLD_BOUNDARY&&(i=-s.WORLD_BOUNDARY);var n=new h(e,i),r=t.inverseTransformPoint(n);this.setLocation(r.x,r.y)},l.prototype.getLeft=function(){return this.rect.x},l.prototype.getRight=function(){return this.rect.x+this.rect.width},l.prototype.getTop=function(){return this.rect.y},l.prototype.getBottom=function(){return this.rect.y+this.rect.height},l.prototype.getParent=function(){return null==this.owner?null:this.owner.getParent()},t.exports=l},function(t,e,i){"use strict";function n(t,e){null==t&&null==e?(this.x=0,this.y=0):(this.x=t,this.y=e)}n.prototype.getX=function(){return this.x},n.prototype.getY=function(){return this.y},n.prototype.setX=function(t){this.x=t},n.prototype.setY=function(t){this.y=t},n.prototype.getDifference=function(t){return new DimensionD(this.x-t.x,this.y-t.y)},n.prototype.getCopy=function(){return new n(this.x,this.y)},n.prototype.translate=function(t){return this.x+=t.width,this.y+=t.height,this},t.exports=n},function(t,e,i){"use strict";var n=i(2),r=i(10),o=i(0),s=i(6),a=i(3),h=i(1),l=i(13),c=i(12),g=i(11);function u(t,e,i){n.call(this,i),this.estimatedSize=r.MIN_VALUE,this.margin=o.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=t,null!=e&&e instanceof s?this.graphManager=e:null!=e&&e instanceof Layout&&(this.graphManager=e.graphManager)}for(var d in u.prototype=Object.create(n.prototype),n)u[d]=n[d];u.prototype.getNodes=function(){return this.nodes},u.prototype.getEdges=function(){return this.edges},u.prototype.getGraphManager=function(){return this.graphManager},u.prototype.getParent=function(){return this.parent},u.prototype.getLeft=function(){return this.left},u.prototype.getRight=function(){return this.right},u.prototype.getTop=function(){return this.top},u.prototype.getBottom=function(){return this.bottom},u.prototype.isConnected=function(){return this.isConnected},u.prototype.add=function(t,e,i){if(null==e&&null==i){var n=t;if(null==this.graphManager)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(n)>-1)throw"Node already in graph!";return n.owner=this,this.getNodes().push(n),n}var r=t;if(!(this.getNodes().indexOf(e)>-1&&this.getNodes().indexOf(i)>-1))throw"Source or target not in graph!";if(e.owner!=i.owner||e.owner!=this)throw"Both owners must be this graph!";return e.owner!=i.owner?null:(r.source=e,r.target=i,r.isInterGraph=!1,this.getEdges().push(r),e.edges.push(r),i!=e&&i.edges.push(r),r)},u.prototype.remove=function(t){var e=t;if(t instanceof a){if(null==e)throw"Node is null!";if(null==e.owner||e.owner!=this)throw"Owner graph is invalid!";if(null==this.graphManager)throw"Owner graph manager is invalid!";for(var i=e.edges.slice(),n=i.length,r=0;r<n;r++)(o=i[r]).isInterGraph?this.graphManager.remove(o):o.source.owner.remove(o);if(-1==(s=this.nodes.indexOf(e)))throw"Node not in owner node list!";this.nodes.splice(s,1)}else if(t instanceof h){var o;if(null==(o=t))throw"Edge is null!";if(null==o.source||null==o.target)throw"Source and/or target is null!";if(null==o.source.owner||null==o.target.owner||o.source.owner!=this||o.target.owner!=this)throw"Source and/or target owner is invalid!";var s,l=o.source.edges.indexOf(o),c=o.target.edges.indexOf(o);if(!(l>-1&&c>-1))throw"Source and/or target doesn't know this edge!";if(o.source.edges.splice(l,1),o.target!=o.source&&o.target.edges.splice(c,1),-1==(s=o.source.owner.getEdges().indexOf(o)))throw"Not in owner's edge list!";o.source.owner.getEdges().splice(s,1)}},u.prototype.updateLeftTop=function(){for(var t,e,i,n=r.MAX_VALUE,o=r.MAX_VALUE,s=this.getNodes(),a=s.length,h=0;h<a;h++){var l=s[h];n>(t=l.getTop())&&(n=t),o>(e=l.getLeft())&&(o=e)}return n==r.MAX_VALUE?null:(i=null!=s[0].getParent().paddingLeft?s[0].getParent().paddingLeft:this.margin,this.left=o-i,this.top=n-i,new c(this.left,this.top))},u.prototype.updateBounds=function(t){for(var e,i,n,o,s,a=r.MAX_VALUE,h=-r.MAX_VALUE,c=r.MAX_VALUE,g=-r.MAX_VALUE,u=this.nodes,d=u.length,p=0;p<d;p++){var f=u[p];t&&null!=f.child&&f.updateBounds(),a>(e=f.getLeft())&&(a=e),h<(i=f.getRight())&&(h=i),c>(n=f.getTop())&&(c=n),g<(o=f.getBottom())&&(g=o)}var y=new l(a,c,h-a,g-c);a==r.MAX_VALUE&&(this.left=this.parent.getLeft(),this.right=this.parent.getRight(),this.top=this.parent.getTop(),this.bottom=this.parent.getBottom()),s=null!=u[0].getParent().paddingLeft?u[0].getParent().paddingLeft:this.margin,this.left=y.x-s,this.right=y.x+y.width+s,this.top=y.y-s,this.bottom=y.y+y.height+s},u.calculateBounds=function(t){for(var e,i,n,o,s=r.MAX_VALUE,a=-r.MAX_VALUE,h=r.MAX_VALUE,c=-r.MAX_VALUE,g=t.length,u=0;u<g;u++){var d=t[u];s>(e=d.getLeft())&&(s=e),a<(i=d.getRight())&&(a=i),h>(n=d.getTop())&&(h=n),c<(o=d.getBottom())&&(c=o)}return new l(s,h,a-s,c-h)},u.prototype.getInclusionTreeDepth=function(){return this==this.graphManager.getRoot()?1:this.parent.getInclusionTreeDepth()},u.prototype.getEstimatedSize=function(){if(this.estimatedSize==r.MIN_VALUE)throw"assert failed";return this.estimatedSize},u.prototype.calcEstimatedSize=function(){for(var t=0,e=this.nodes,i=e.length,n=0;n<i;n++)t+=e[n].calcEstimatedSize();return this.estimatedSize=0==t?o.EMPTY_COMPOUND_NODE_SIZE:t/Math.sqrt(this.nodes.length),this.estimatedSize},u.prototype.updateConnected=function(){var t=this;if(0!=this.nodes.length){var e,i,n=new g,r=new Set,o=this.nodes[0];for(o.withChildren().forEach((function(t){n.push(t),r.add(t)}));0!==n.length;)for(var s=(e=(o=n.shift()).getEdges()).length,a=0;a<s;a++)null==(i=e[a].getOtherEndInGraph(o,this))||r.has(i)||i.withChildren().forEach((function(t){n.push(t),r.add(t)}));if(this.isConnected=!1,r.size>=this.nodes.length){var h=0;r.forEach((function(e){e.owner==t&&h++})),h==this.nodes.length&&(this.isConnected=!0)}}else this.isConnected=!0},t.exports=u},function(t,e,i){"use strict";var n,r=i(1);function o(t){n=i(5),this.layout=t,this.graphs=[],this.edges=[]}o.prototype.addRoot=function(){var t=this.layout.newGraph(),e=this.layout.newNode(null),i=this.add(t,e);return this.setRootGraph(i),this.rootGraph},o.prototype.add=function(t,e,i,n,r){if(null==i&&null==n&&null==r){if(null==t)throw"Graph is null!";if(null==e)throw"Parent node is null!";if(this.graphs.indexOf(t)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(t),null!=t.parent)throw"Already has a parent!";if(null!=e.child)throw"Already has a child!";return t.parent=e,e.child=t,t}r=i,i=t;var o=(n=e).getOwner(),s=r.getOwner();if(null==o||o.getGraphManager()!=this)throw"Source not in this graph mgr!";if(null==s||s.getGraphManager()!=this)throw"Target not in this graph mgr!";if(o==s)return i.isInterGraph=!1,o.add(i,n,r);if(i.isInterGraph=!0,i.source=n,i.target=r,this.edges.indexOf(i)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(i),null==i.source||null==i.target)throw"Edge source and/or target is null!";if(-1!=i.source.edges.indexOf(i)||-1!=i.target.edges.indexOf(i))throw"Edge already in source and/or target incidency list!";return i.source.edges.push(i),i.target.edges.push(i),i},o.prototype.remove=function(t){if(t instanceof n){var e=t;if(e.getGraphManager()!=this)throw"Graph not in this graph mgr";if(e!=this.rootGraph&&(null==e.parent||e.parent.graphManager!=this))throw"Invalid parent node!";for(var i,o=[],s=(o=o.concat(e.getEdges())).length,a=0;a<s;a++)i=o[a],e.remove(i);var h,l=[];for(s=(l=l.concat(e.getNodes())).length,a=0;a<s;a++)h=l[a],e.remove(h);e==this.rootGraph&&this.setRootGraph(null);var c=this.graphs.indexOf(e);this.graphs.splice(c,1),e.parent=null}else if(t instanceof r){if(null==(i=t))throw"Edge is null!";if(!i.isInterGraph)throw"Not an inter-graph edge!";if(null==i.source||null==i.target)throw"Source and/or target is null!";if(-1==i.source.edges.indexOf(i)||-1==i.target.edges.indexOf(i))throw"Source and/or target doesn't know this edge!";if(c=i.source.edges.indexOf(i),i.source.edges.splice(c,1),c=i.target.edges.indexOf(i),i.target.edges.splice(c,1),null==i.source.owner||null==i.source.owner.getGraphManager())throw"Edge owner graph or owner graph manager is null!";if(-1==i.source.owner.getGraphManager().edges.indexOf(i))throw"Not in owner graph manager's edge list!";c=i.source.owner.getGraphManager().edges.indexOf(i),i.source.owner.getGraphManager().edges.splice(c,1)}},o.prototype.updateBounds=function(){this.rootGraph.updateBounds(!0)},o.prototype.getGraphs=function(){return this.graphs},o.prototype.getAllNodes=function(){if(null==this.allNodes){for(var t=[],e=this.getGraphs(),i=e.length,n=0;n<i;n++)t=t.concat(e[n].getNodes());this.allNodes=t}return this.allNodes},o.prototype.resetAllNodes=function(){this.allNodes=null},o.prototype.resetAllEdges=function(){this.allEdges=null},o.prototype.resetAllNodesToApplyGravitation=function(){this.allNodesToApplyGravitation=null},o.prototype.getAllEdges=function(){if(null==this.allEdges){for(var t=[],e=this.getGraphs(),i=(e.length,0);i<e.length;i++)t=t.concat(e[i].getEdges());t=t.concat(this.edges),this.allEdges=t}return this.allEdges},o.prototype.getAllNodesToApplyGravitation=function(){return this.allNodesToApplyGravitation},o.prototype.setAllNodesToApplyGravitation=function(t){if(null!=this.allNodesToApplyGravitation)throw"assert failed";this.allNodesToApplyGravitation=t},o.prototype.getRoot=function(){return this.rootGraph},o.prototype.setRootGraph=function(t){if(t.getGraphManager()!=this)throw"Root not in this graph mgr!";this.rootGraph=t,null==t.parent&&(t.parent=this.layout.newNode("Root node"))},o.prototype.getLayout=function(){return this.layout},o.prototype.isOneAncestorOfOther=function(t,e){if(null==t||null==e)throw"assert failed";if(t==e)return!0;for(var i,n=t.getOwner();null!=(i=n.getParent());){if(i==e)return!0;if(null==(n=i.getOwner()))break}for(n=e.getOwner();null!=(i=n.getParent());){if(i==t)return!0;if(null==(n=i.getOwner()))break}return!1},o.prototype.calcLowestCommonAncestors=function(){for(var t,e,i,n,r,o=this.getAllEdges(),s=o.length,a=0;a<s;a++)if(e=(t=o[a]).source,i=t.target,t.lca=null,t.sourceInLca=e,t.targetInLca=i,e!=i){for(n=e.getOwner();null==t.lca;){for(t.targetInLca=i,r=i.getOwner();null==t.lca;){if(r==n){t.lca=r;break}if(r==this.rootGraph)break;if(null!=t.lca)throw"assert failed";t.targetInLca=r.getParent(),r=t.targetInLca.getOwner()}if(n==this.rootGraph)break;null==t.lca&&(t.sourceInLca=n.getParent(),n=t.sourceInLca.getOwner())}if(null==t.lca)throw"assert failed"}else t.lca=e.getOwner()},o.prototype.calcLowestCommonAncestor=function(t,e){if(t==e)return t.getOwner();for(var i=t.getOwner();null!=i;){for(var n=e.getOwner();null!=n;){if(n==i)return n;n=n.getParent().getOwner()}i=i.getParent().getOwner()}return i},o.prototype.calcInclusionTreeDepths=function(t,e){var i;null==t&&null==e&&(t=this.rootGraph,e=1);for(var n=t.getNodes(),r=n.length,o=0;o<r;o++)(i=n[o]).inclusionTreeDepth=e,null!=i.child&&this.calcInclusionTreeDepths(i.child,e+1)},o.prototype.includesInvalidEdge=function(){for(var t,e=this.edges.length,i=0;i<e;i++)if(t=this.edges[i],this.isOneAncestorOfOther(t.source,t.target))return!0;return!1},t.exports=o},function(t,e,i){"use strict";var n=i(0);function r(){}for(var o in n)r[o]=n[o];r.MAX_ITERATIONS=2500,r.DEFAULT_EDGE_LENGTH=50,r.DEFAULT_SPRING_STRENGTH=.45,r.DEFAULT_REPULSION_STRENGTH=4500,r.DEFAULT_GRAVITY_STRENGTH=.4,r.DEFAULT_COMPOUND_GRAVITY_STRENGTH=1,r.DEFAULT_GRAVITY_RANGE_FACTOR=3.8,r.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=1.5,r.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION=!0,r.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION=!0,r.DEFAULT_COOLING_FACTOR_INCREMENTAL=.3,r.COOLING_ADAPTATION_FACTOR=.33,r.ADAPTATION_LOWER_NODE_LIMIT=1e3,r.ADAPTATION_UPPER_NODE_LIMIT=5e3,r.MAX_NODE_DISPLACEMENT_INCREMENTAL=100,r.MAX_NODE_DISPLACEMENT=3*r.MAX_NODE_DISPLACEMENT_INCREMENTAL,r.MIN_REPULSION_DIST=r.DEFAULT_EDGE_LENGTH/10,r.CONVERGENCE_CHECK_PERIOD=100,r.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=.1,r.MIN_EDGE_LENGTH=1,r.GRID_CALCULATION_CHECK_PERIOD=10,t.exports=r},function(t,e,i){"use strict";var n=i(12);function r(){}r.calcSeparationAmount=function(t,e,i,n){if(!t.intersects(e))throw"assert failed";var r=new Array(2);this.decideDirectionsForOverlappingNodes(t,e,r),i[0]=Math.min(t.getRight(),e.getRight())-Math.max(t.x,e.x),i[1]=Math.min(t.getBottom(),e.getBottom())-Math.max(t.y,e.y),t.getX()<=e.getX()&&t.getRight()>=e.getRight()?i[0]+=Math.min(e.getX()-t.getX(),t.getRight()-e.getRight()):e.getX()<=t.getX()&&e.getRight()>=t.getRight()&&(i[0]+=Math.min(t.getX()-e.getX(),e.getRight()-t.getRight())),t.getY()<=e.getY()&&t.getBottom()>=e.getBottom()?i[1]+=Math.min(e.getY()-t.getY(),t.getBottom()-e.getBottom()):e.getY()<=t.getY()&&e.getBottom()>=t.getBottom()&&(i[1]+=Math.min(t.getY()-e.getY(),e.getBottom()-t.getBottom()));var o=Math.abs((e.getCenterY()-t.getCenterY())/(e.getCenterX()-t.getCenterX()));e.getCenterY()===t.getCenterY()&&e.getCenterX()===t.getCenterX()&&(o=1);var s=o*i[0],a=i[1]/o;i[0]<a?a=i[0]:s=i[1],i[0]=-1*r[0]*(a/2+n),i[1]=-1*r[1]*(s/2+n)},r.decideDirectionsForOverlappingNodes=function(t,e,i){t.getCenterX()<e.getCenterX()?i[0]=-1:i[0]=1,t.getCenterY()<e.getCenterY()?i[1]=-1:i[1]=1},r.getIntersection2=function(t,e,i){var n=t.getCenterX(),r=t.getCenterY(),o=e.getCenterX(),s=e.getCenterY();if(t.intersects(e))return i[0]=n,i[1]=r,i[2]=o,i[3]=s,!0;var a=t.getX(),h=t.getY(),l=t.getRight(),c=t.getX(),g=t.getBottom(),u=t.getRight(),d=t.getWidthHalf(),p=t.getHeightHalf(),f=e.getX(),y=e.getY(),E=e.getRight(),_=e.getX(),m=e.getBottom(),v=e.getRight(),N=e.getWidthHalf(),A=e.getHeightHalf(),L=!1,T=!1;if(n===o){if(r>s)return i[0]=n,i[1]=h,i[2]=o,i[3]=m,!1;if(r<s)return i[0]=n,i[1]=g,i[2]=o,i[3]=y,!1}else if(r===s){if(n>o)return i[0]=a,i[1]=r,i[2]=E,i[3]=s,!1;if(n<o)return i[0]=l,i[1]=r,i[2]=f,i[3]=s,!1}else{var O=t.height/t.width,D=e.height/e.width,I=(s-r)/(o-n),w=void 0,R=void 0,C=void 0,M=void 0,x=void 0,G=void 0;if(-O===I?n>o?(i[0]=c,i[1]=g,L=!0):(i[0]=l,i[1]=h,L=!0):O===I&&(n>o?(i[0]=a,i[1]=h,L=!0):(i[0]=u,i[1]=g,L=!0)),-D===I?o>n?(i[2]=_,i[3]=m,T=!0):(i[2]=E,i[3]=y,T=!0):D===I&&(o>n?(i[2]=f,i[3]=y,T=!0):(i[2]=v,i[3]=m,T=!0)),L&&T)return!1;if(n>o?r>s?(w=this.getCardinalDirection(O,I,4),R=this.getCardinalDirection(D,I,2)):(w=this.getCardinalDirection(-O,I,3),R=this.getCardinalDirection(-D,I,1)):r>s?(w=this.getCardinalDirection(-O,I,1),R=this.getCardinalDirection(-D,I,3)):(w=this.getCardinalDirection(O,I,2),R=this.getCardinalDirection(D,I,4)),!L)switch(w){case 1:M=h,C=n+-p/I,i[0]=C,i[1]=M;break;case 2:C=u,M=r+d*I,i[0]=C,i[1]=M;break;case 3:M=g,C=n+p/I,i[0]=C,i[1]=M;break;case 4:C=c,M=r+-d*I,i[0]=C,i[1]=M}if(!T)switch(R){case 1:G=y,x=o+-A/I,i[2]=x,i[3]=G;break;case 2:x=v,G=s+N*I,i[2]=x,i[3]=G;break;case 3:G=m,x=o+A/I,i[2]=x,i[3]=G;break;case 4:x=_,G=s+-N*I,i[2]=x,i[3]=G}}return!1},r.getCardinalDirection=function(t,e,i){return t>e?i:1+i%4},r.getIntersection=function(t,e,i,r){if(null==r)return this.getIntersection2(t,e,i);var o,s,a,h,l,c,g,u=t.x,d=t.y,p=e.x,f=e.y,y=i.x,E=i.y,_=r.x,m=r.y;return 0==(g=(o=f-d)*(h=y-_)-(s=m-E)*(a=u-p))?null:new n((a*(c=_*E-y*m)-h*(l=p*d-u*f))/g,(s*l-o*c)/g)},r.angleOfVector=function(t,e,i,n){var r=void 0;return t!==i?(r=Math.atan((n-e)/(i-t)),i<t?r+=Math.PI:n<e&&(r+=this.TWO_PI)):r=n<e?this.ONE_AND_HALF_PI:this.HALF_PI,r},r.doIntersect=function(t,e,i,n){var r=t.x,o=t.y,s=e.x,a=e.y,h=i.x,l=i.y,c=n.x,g=n.y,u=(s-r)*(g-l)-(c-h)*(a-o);if(0===u)return!1;var d=((g-l)*(c-r)+(h-c)*(g-o))/u,p=((o-a)*(c-r)+(s-r)*(g-o))/u;return 0<d&&d<1&&0<p&&p<1},r.HALF_PI=.5*Math.PI,r.ONE_AND_HALF_PI=1.5*Math.PI,r.TWO_PI=2*Math.PI,r.THREE_PI=3*Math.PI,t.exports=r},function(t,e,i){"use strict";function n(){}n.sign=function(t){return t>0?1:t<0?-1:0},n.floor=function(t){return t<0?Math.ceil(t):Math.floor(t)},n.ceil=function(t){return t<0?Math.floor(t):Math.ceil(t)},t.exports=n},function(t,e,i){"use strict";function n(){}n.MAX_VALUE=2147483647,n.MIN_VALUE=-2147483648,t.exports=n},function(t,e,i){"use strict";var n=function(){function t(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,i,n){return i&&t(e.prototype,i),n&&t(e,n),e}}(),r=function(t){return{value:t,next:null,prev:null}},o=function(t,e,i,n){return null!==t?t.next=e:n.head=e,null!==i?i.prev=e:n.tail=e,e.prev=t,e.next=i,n.length++,e},s=function(t,e){var i=t.prev,n=t.next;return null!==i?i.next=n:e.head=n,null!==n?n.prev=i:e.tail=i,t.prev=t.next=null,e.length--,t},a=function(){function t(e){var i=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.length=0,this.head=null,this.tail=null,null!=e&&e.forEach((function(t){return i.push(t)}))}return n(t,[{key:"size",value:function(){return this.length}},{key:"insertBefore",value:function(t,e){return o(e.prev,r(t),e,this)}},{key:"insertAfter",value:function(t,e){return o(e,r(t),e.next,this)}},{key:"insertNodeBefore",value:function(t,e){return o(e.prev,t,e,this)}},{key:"insertNodeAfter",value:function(t,e){return o(e,t,e.next,this)}},{key:"push",value:function(t){return o(this.tail,r(t),null,this)}},{key:"unshift",value:function(t){return o(null,r(t),this.head,this)}},{key:"remove",value:function(t){return s(t,this)}},{key:"pop",value:function(){return s(this.tail,this).value}},{key:"popNode",value:function(){return s(this.tail,this)}},{key:"shift",value:function(){return s(this.head,this).value}},{key:"shiftNode",value:function(){return s(this.head,this)}},{key:"get_object_at",value:function(t){if(t<=this.length()){for(var e=1,i=this.head;e<t;)i=i.next,e++;return i.value}}},{key:"set_object_at",value:function(t,e){if(t<=this.length()){for(var i=1,n=this.head;i<t;)n=n.next,i++;n.value=e}}}]),t}();t.exports=a},function(t,e,i){"use strict";function n(t,e,i){this.x=null,this.y=null,null==t&&null==e&&null==i?(this.x=0,this.y=0):"number"==typeof t&&"number"==typeof e&&null==i?(this.x=t,this.y=e):"Point"==t.constructor.name&&null==e&&null==i&&(i=t,this.x=i.x,this.y=i.y)}n.prototype.getX=function(){return this.x},n.prototype.getY=function(){return this.y},n.prototype.getLocation=function(){return new n(this.x,this.y)},n.prototype.setLocation=function(t,e,i){"Point"==t.constructor.name&&null==e&&null==i?(i=t,this.setLocation(i.x,i.y)):"number"==typeof t&&"number"==typeof e&&null==i&&(parseInt(t)==t&&parseInt(e)==e?this.move(t,e):(this.x=Math.floor(t+.5),this.y=Math.floor(e+.5)))},n.prototype.move=function(t,e){this.x=t,this.y=e},n.prototype.translate=function(t,e){this.x+=t,this.y+=e},n.prototype.equals=function(t){if("Point"==t.constructor.name){var e=t;return this.x==e.x&&this.y==e.y}return this==t},n.prototype.toString=function(){return(new n).constructor.name+"[x="+this.x+",y="+this.y+"]"},t.exports=n},function(t,e,i){"use strict";function n(t,e,i,n){this.x=0,this.y=0,this.width=0,this.height=0,null!=t&&null!=e&&null!=i&&null!=n&&(this.x=t,this.y=e,this.width=i,this.height=n)}n.prototype.getX=function(){return this.x},n.prototype.setX=function(t){this.x=t},n.prototype.getY=function(){return this.y},n.prototype.setY=function(t){this.y=t},n.prototype.getWidth=function(){return this.width},n.prototype.setWidth=function(t){this.width=t},n.prototype.getHeight=function(){return this.height},n.prototype.setHeight=function(t){this.height=t},n.prototype.getRight=function(){return this.x+this.width},n.prototype.getBottom=function(){return this.y+this.height},n.prototype.intersects=function(t){return!(this.getRight()<t.x||this.getBottom()<t.y||t.getRight()<this.x||t.getBottom()<this.y)},n.prototype.getCenterX=function(){return this.x+this.width/2},n.prototype.getMinX=function(){return this.getX()},n.prototype.getMaxX=function(){return this.getX()+this.width},n.prototype.getCenterY=function(){return this.y+this.height/2},n.prototype.getMinY=function(){return this.getY()},n.prototype.getMaxY=function(){return this.getY()+this.height},n.prototype.getWidthHalf=function(){return this.width/2},n.prototype.getHeightHalf=function(){return this.height/2},t.exports=n},function(t,e,i){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};function r(){}r.lastID=0,r.createID=function(t){return r.isPrimitive(t)?t:(null!=t.uniqueID||(t.uniqueID=r.getString(),r.lastID++),t.uniqueID)},r.getString=function(t){return null==t&&(t=r.lastID),"Object#"+t},r.isPrimitive=function(t){var e=void 0===t?"undefined":n(t);return null==t||"object"!=e&&"function"!=e},t.exports=r},function(t,e,i){"use strict";function n(t){if(Array.isArray(t)){for(var e=0,i=Array(t.length);e<t.length;e++)i[e]=t[e];return i}return Array.from(t)}var r=i(0),o=i(6),s=i(3),a=i(1),h=i(5),l=i(4),c=i(17),g=i(27);function u(t){g.call(this),this.layoutQuality=r.QUALITY,this.createBendsAsNeeded=r.DEFAULT_CREATE_BENDS_AS_NEEDED,this.incremental=r.DEFAULT_INCREMENTAL,this.animationOnLayout=r.DEFAULT_ANIMATION_ON_LAYOUT,this.animationDuringLayout=r.DEFAULT_ANIMATION_DURING_LAYOUT,this.animationPeriod=r.DEFAULT_ANIMATION_PERIOD,this.uniformLeafNodeSizes=r.DEFAULT_UNIFORM_LEAF_NODE_SIZES,this.edgeToDummyNodes=new Map,this.graphManager=new o(this),this.isLayoutFinished=!1,this.isSubLayout=!1,this.isRemoteUse=!1,null!=t&&(this.isRemoteUse=t)}u.RANDOM_SEED=1,u.prototype=Object.create(g.prototype),u.prototype.getGraphManager=function(){return this.graphManager},u.prototype.getAllNodes=function(){return this.graphManager.getAllNodes()},u.prototype.getAllEdges=function(){return this.graphManager.getAllEdges()},u.prototype.getAllNodesToApplyGravitation=function(){return this.graphManager.getAllNodesToApplyGravitation()},u.prototype.newGraphManager=function(){var t=new o(this);return this.graphManager=t,t},u.prototype.newGraph=function(t){return new h(null,this.graphManager,t)},u.prototype.newNode=function(t){return new s(this.graphManager,t)},u.prototype.newEdge=function(t){return new a(null,null,t)},u.prototype.checkLayoutSuccess=function(){return null==this.graphManager.getRoot()||0==this.graphManager.getRoot().getNodes().length||this.graphManager.includesInvalidEdge()},u.prototype.runLayout=function(){var t;return this.isLayoutFinished=!1,this.tilingPreLayout&&this.tilingPreLayout(),this.initParameters(),t=!this.checkLayoutSuccess()&&this.layout(),"during"!==r.ANIMATE&&(t&&(this.isSubLayout||this.doPostLayout()),this.tilingPostLayout&&this.tilingPostLayout(),this.isLayoutFinished=!0,t)},u.prototype.doPostLayout=function(){this.incremental||this.transform(),this.update()},u.prototype.update2=function(){if(this.createBendsAsNeeded&&(this.createBendpointsFromDummyNodes(),this.graphManager.resetAllEdges()),!this.isRemoteUse){for(var t=this.graphManager.getAllEdges(),e=0;e<t.length;e++)t[e];var i=this.graphManager.getRoot().getNodes();for(e=0;e<i.length;e++)i[e];this.update(this.graphManager.getRoot())}},u.prototype.update=function(t){if(null==t)this.update2();else if(t instanceof s){var e=t;if(null!=e.getChild())for(var i=e.getChild().getNodes(),n=0;n<i.length;n++)update(i[n]);null!=e.vGraphObject&&e.vGraphObject.update(e)}else if(t instanceof a){var r=t;null!=r.vGraphObject&&r.vGraphObject.update(r)}else if(t instanceof h){var o=t;null!=o.vGraphObject&&o.vGraphObject.update(o)}},u.prototype.initParameters=function(){this.isSubLayout||(this.layoutQuality=r.QUALITY,this.animationDuringLayout=r.DEFAULT_ANIMATION_DURING_LAYOUT,this.animationPeriod=r.DEFAULT_ANIMATION_PERIOD,this.animationOnLayout=r.DEFAULT_ANIMATION_ON_LAYOUT,this.incremental=r.DEFAULT_INCREMENTAL,this.createBendsAsNeeded=r.DEFAULT_CREATE_BENDS_AS_NEEDED,this.uniformLeafNodeSizes=r.DEFAULT_UNIFORM_LEAF_NODE_SIZES),this.animationDuringLayout&&(this.animationOnLayout=!1)},u.prototype.transform=function(t){if(null==t)this.transform(new l(0,0));else{var e=new c,i=this.graphManager.getRoot().updateLeftTop();if(null!=i){e.setWorldOrgX(t.x),e.setWorldOrgY(t.y),e.setDeviceOrgX(i.x),e.setDeviceOrgY(i.y);for(var n=this.getAllNodes(),r=0;r<n.length;r++)n[r].transform(e)}}},u.prototype.positionNodesRandomly=function(t){if(null==t)this.positionNodesRandomly(this.getGraphManager().getRoot()),this.getGraphManager().getRoot().updateBounds(!0);else for(var e,i,n=t.getNodes(),r=0;r<n.length;r++)null==(i=(e=n[r]).getChild())||0==i.getNodes().length?e.scatter():(this.positionNodesRandomly(i),e.updateBounds())},u.prototype.getFlatForest=function(){for(var t=[],e=!0,i=this.graphManager.getRoot().getNodes(),r=!0,o=0;o<i.length;o++)null!=i[o].getChild()&&(r=!1);if(!r)return t;var s=new Set,a=[],h=new Map,l=[];for(l=l.concat(i);l.length>0&&e;){for(a.push(l[0]);a.length>0&&e;){var c=a[0];a.splice(0,1),s.add(c);var g=c.getEdges();for(o=0;o<g.length;o++){var u=g[o].getOtherEnd(c);if(h.get(c)!=u){if(s.has(u)){e=!1;break}a.push(u),h.set(u,c)}}}if(e){var d=[].concat(n(s));for(t.push(d),o=0;o<d.length;o++){var p=d[o],f=l.indexOf(p);f>-1&&l.splice(f,1)}s=new Set,h=new Map}else t=[]}return t},u.prototype.createDummyNodesForBendpoints=function(t){for(var e=[],i=t.source,n=this.graphManager.calcLowestCommonAncestor(t.source,t.target),r=0;r<t.bendpoints.length;r++){var o=this.newNode(null);o.setRect(new Point(0,0),new Dimension(1,1)),n.add(o);var s=this.newEdge(null);this.graphManager.add(s,i,o),e.add(o),i=o}return s=this.newEdge(null),this.graphManager.add(s,i,t.target),this.edgeToDummyNodes.set(t,e),t.isInterGraph()?this.graphManager.remove(t):n.remove(t),e},u.prototype.createBendpointsFromDummyNodes=function(){var t=[];t=t.concat(this.graphManager.getAllEdges()),t=[].concat(n(this.edgeToDummyNodes.keys())).concat(t);for(var e=0;e<t.length;e++){var i=t[e];if(i.bendpoints.length>0){for(var r=this.edgeToDummyNodes.get(i),o=0;o<r.length;o++){var s=r[o],a=new l(s.getCenterX(),s.getCenterY()),h=i.bendpoints.get(o);h.x=a.x,h.y=a.y,s.getOwner().remove(s)}this.graphManager.add(i,i.source,i.target)}}},u.transform=function(t,e,i,n){if(null!=i&&null!=n){var r=e;return t<=50?r-=(e-e/i)/50*(50-t):r+=(e*n-e)/50*(t-50),r}var o,s;return t<=50?(o=9*e/500,s=e/10):(o=9*e/50,s=-8*e),o*t+s},u.findCenterOfTree=function(t){var e=[];e=e.concat(t);var i=[],n=new Map,r=!1,o=null;1!=e.length&&2!=e.length||(r=!0,o=e[0]);for(var s=0;s<e.length;s++){var a=(c=e[s]).getNeighborsList().size;n.set(c,c.getNeighborsList().size),1==a&&i.push(c)}var h=[];for(h=h.concat(i);!r;){var l=[];for(l=l.concat(h),h=[],s=0;s<e.length;s++){var c=e[s],g=e.indexOf(c);g>=0&&e.splice(g,1),c.getNeighborsList().forEach((function(t){if(i.indexOf(t)<0){var e=n.get(t)-1;1==e&&h.push(t),n.set(t,e)}}))}i=i.concat(h),1!=e.length&&2!=e.length||(r=!0,o=e[0])}return o},u.prototype.setGraphManager=function(t){this.graphManager=t},t.exports=u},function(t,e,i){"use strict";function n(){}n.seed=1,n.x=0,n.nextDouble=function(){return n.x=1e4*Math.sin(n.seed++),n.x-Math.floor(n.x)},t.exports=n},function(t,e,i){"use strict";var n=i(4);function r(t,e){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}r.prototype.getWorldOrgX=function(){return this.lworldOrgX},r.prototype.setWorldOrgX=function(t){this.lworldOrgX=t},r.prototype.getWorldOrgY=function(){return this.lworldOrgY},r.prototype.setWorldOrgY=function(t){this.lworldOrgY=t},r.prototype.getWorldExtX=function(){return this.lworldExtX},r.prototype.setWorldExtX=function(t){this.lworldExtX=t},r.prototype.getWorldExtY=function(){return this.lworldExtY},r.prototype.setWorldExtY=function(t){this.lworldExtY=t},r.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},r.prototype.setDeviceOrgX=function(t){this.ldeviceOrgX=t},r.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},r.prototype.setDeviceOrgY=function(t){this.ldeviceOrgY=t},r.prototype.getDeviceExtX=function(){return this.ldeviceExtX},r.prototype.setDeviceExtX=function(t){this.ldeviceExtX=t},r.prototype.getDeviceExtY=function(){return this.ldeviceExtY},r.prototype.setDeviceExtY=function(t){this.ldeviceExtY=t},r.prototype.transformX=function(t){var e=0,i=this.lworldExtX;return 0!=i&&(e=this.ldeviceOrgX+(t-this.lworldOrgX)*this.ldeviceExtX/i),e},r.prototype.transformY=function(t){var e=0,i=this.lworldExtY;return 0!=i&&(e=this.ldeviceOrgY+(t-this.lworldOrgY)*this.ldeviceExtY/i),e},r.prototype.inverseTransformX=function(t){var e=0,i=this.ldeviceExtX;return 0!=i&&(e=this.lworldOrgX+(t-this.ldeviceOrgX)*this.lworldExtX/i),e},r.prototype.inverseTransformY=function(t){var e=0,i=this.ldeviceExtY;return 0!=i&&(e=this.lworldOrgY+(t-this.ldeviceOrgY)*this.lworldExtY/i),e},r.prototype.inverseTransformPoint=function(t){return new n(this.inverseTransformX(t.x),this.inverseTransformY(t.y))},t.exports=r},function(t,e,i){"use strict";var n=i(15),r=i(7),o=i(0),s=i(8),a=i(9);function h(){n.call(this),this.useSmartIdealEdgeLengthCalculation=r.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.idealEdgeLength=r.DEFAULT_EDGE_LENGTH,this.springConstant=r.DEFAULT_SPRING_STRENGTH,this.repulsionConstant=r.DEFAULT_REPULSION_STRENGTH,this.gravityConstant=r.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=r.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=r.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=r.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.displacementThresholdPerNode=3*r.DEFAULT_EDGE_LENGTH/100,this.coolingFactor=r.DEFAULT_COOLING_FACTOR_INCREMENTAL,this.initialCoolingFactor=r.DEFAULT_COOLING_FACTOR_INCREMENTAL,this.totalDisplacement=0,this.oldTotalDisplacement=0,this.maxIterations=r.MAX_ITERATIONS}for(var l in h.prototype=Object.create(n.prototype),n)h[l]=n[l];h.prototype.initParameters=function(){n.prototype.initParameters.call(this,arguments),this.totalIterations=0,this.notAnimatedIterations=0,this.useFRGridVariant=r.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION,this.grid=[]},h.prototype.calcIdealEdgeLengths=function(){for(var t,e,i,n,s,a,h=this.getGraphManager().getAllEdges(),l=0;l<h.length;l++)(t=h[l]).idealLength=this.idealEdgeLength,t.isInterGraph&&(i=t.getSource(),n=t.getTarget(),s=t.getSourceInLca().getEstimatedSize(),a=t.getTargetInLca().getEstimatedSize(),this.useSmartIdealEdgeLengthCalculation&&(t.idealLength+=s+a-2*o.SIMPLE_NODE_SIZE),e=t.getLca().getInclusionTreeDepth(),t.idealLength+=r.DEFAULT_EDGE_LENGTH*r.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR*(i.getInclusionTreeDepth()+n.getInclusionTreeDepth()-2*e))},h.prototype.initSpringEmbedder=function(){var t=this.getAllNodes().length;this.incremental?(t>r.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*r.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(t-r.ADAPTATION_LOWER_NODE_LIMIT)/(r.ADAPTATION_UPPER_NODE_LIMIT-r.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-r.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=r.MAX_NODE_DISPLACEMENT_INCREMENTAL):(t>r.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(r.COOLING_ADAPTATION_FACTOR,1-(t-r.ADAPTATION_LOWER_NODE_LIMIT)/(r.ADAPTATION_UPPER_NODE_LIMIT-r.ADAPTATION_LOWER_NODE_LIMIT)*(1-r.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=r.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(5*this.getAllNodes().length,this.maxIterations),this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},h.prototype.calcSpringForces=function(){for(var t,e=this.getAllEdges(),i=0;i<e.length;i++)t=e[i],this.calcSpringForce(t,t.idealLength)},h.prototype.calcRepulsionForces=function(){var t,e,i,n,o,s=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],a=arguments.length>1&&void 0!==arguments[1]&&arguments[1],h=this.getAllNodes();if(this.useFRGridVariant)for(this.totalIterations%r.GRID_CALCULATION_CHECK_PERIOD==1&&s&&this.updateGrid(),o=new Set,t=0;t<h.length;t++)i=h[t],this.calculateRepulsionForceOfANode(i,o,s,a),o.add(i);else for(t=0;t<h.length;t++)for(i=h[t],e=t+1;e<h.length;e++)n=h[e],i.getOwner()==n.getOwner()&&this.calcRepulsionForce(i,n)},h.prototype.calcGravitationalForces=function(){for(var t,e=this.getAllNodesToApplyGravitation(),i=0;i<e.length;i++)t=e[i],this.calcGravitationalForce(t)},h.prototype.moveNodes=function(){for(var t=this.getAllNodes(),e=0;e<t.length;e++)t[e].move()},h.prototype.calcSpringForce=function(t,e){var i,n,r,o,s=t.getSource(),a=t.getTarget();if(this.uniformLeafNodeSizes&&null==s.getChild()&&null==a.getChild())t.updateLengthSimple();else if(t.updateLength(),t.isOverlapingSourceAndTarget)return;0!=(i=t.getLength())&&(r=(n=this.springConstant*(i-e))*(t.lengthX/i),o=n*(t.lengthY/i),s.springForceX+=r,s.springForceY+=o,a.springForceX-=r,a.springForceY-=o)},h.prototype.calcRepulsionForce=function(t,e){var i,n,o,h,l,c,g,u=t.getRect(),d=e.getRect(),p=new Array(2),f=new Array(4);if(u.intersects(d)){s.calcSeparationAmount(u,d,p,r.DEFAULT_EDGE_LENGTH/2),c=2*p[0],g=2*p[1];var y=t.noOfChildren*e.noOfChildren/(t.noOfChildren+e.noOfChildren);t.repulsionForceX-=y*c,t.repulsionForceY-=y*g,e.repulsionForceX+=y*c,e.repulsionForceY+=y*g}else this.uniformLeafNodeSizes&&null==t.getChild()&&null==e.getChild()?(i=d.getCenterX()-u.getCenterX(),n=d.getCenterY()-u.getCenterY()):(s.getIntersection(u,d,f),i=f[2]-f[0],n=f[3]-f[1]),Math.abs(i)<r.MIN_REPULSION_DIST&&(i=a.sign(i)*r.MIN_REPULSION_DIST),Math.abs(n)<r.MIN_REPULSION_DIST&&(n=a.sign(n)*r.MIN_REPULSION_DIST),o=i*i+n*n,h=Math.sqrt(o),c=(l=this.repulsionConstant*t.noOfChildren*e.noOfChildren/o)*i/h,g=l*n/h,t.repulsionForceX-=c,t.repulsionForceY-=g,e.repulsionForceX+=c,e.repulsionForceY+=g},h.prototype.calcGravitationalForce=function(t){var e,i,n,r,o,s,a,h;i=((e=t.getOwner()).getRight()+e.getLeft())/2,n=(e.getTop()+e.getBottom())/2,r=t.getCenterX()-i,o=t.getCenterY()-n,s=Math.abs(r)+t.getWidth()/2,a=Math.abs(o)+t.getHeight()/2,t.getOwner()==this.graphManager.getRoot()?(s>(h=e.getEstimatedSize()*this.gravityRangeFactor)||a>h)&&(t.gravitationForceX=-this.gravityConstant*r,t.gravitationForceY=-this.gravityConstant*o):(s>(h=e.getEstimatedSize()*this.compoundGravityRangeFactor)||a>h)&&(t.gravitationForceX=-this.gravityConstant*r*this.compoundGravityConstant,t.gravitationForceY=-this.gravityConstant*o*this.compoundGravityConstant)},h.prototype.isConverged=function(){var t,e=!1;return this.totalIterations>this.maxIterations/3&&(e=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),t=this.totalDisplacement<this.totalDisplacementThreshold,this.oldTotalDisplacement=this.totalDisplacement,t||e},h.prototype.animate=function(){this.animationDuringLayout&&!this.isSubLayout&&(this.notAnimatedIterations==this.animationPeriod?(this.update(),this.notAnimatedIterations=0):this.notAnimatedIterations++)},h.prototype.calcNoOfChildrenForAllNodes=function(){for(var t,e=this.graphManager.getAllNodes(),i=0;i<e.length;i++)(t=e[i]).noOfChildren=t.getNoOfChildren()},h.prototype.calcGrid=function(t){var e,i;e=parseInt(Math.ceil((t.getRight()-t.getLeft())/this.repulsionRange)),i=parseInt(Math.ceil((t.getBottom()-t.getTop())/this.repulsionRange));for(var n=new Array(e),r=0;r<e;r++)n[r]=new Array(i);for(r=0;r<e;r++)for(var o=0;o<i;o++)n[r][o]=new Array;return n},h.prototype.addNodeToGrid=function(t,e,i){var n,r,o,s;n=parseInt(Math.floor((t.getRect().x-e)/this.repulsionRange)),r=parseInt(Math.floor((t.getRect().width+t.getRect().x-e)/this.repulsionRange)),o=parseInt(Math.floor((t.getRect().y-i)/this.repulsionRange)),s=parseInt(Math.floor((t.getRect().height+t.getRect().y-i)/this.repulsionRange));for(var a=n;a<=r;a++)for(var h=o;h<=s;h++)this.grid[a][h].push(t),t.setGridCoordinates(n,r,o,s)},h.prototype.updateGrid=function(){var t,e,i=this.getAllNodes();for(this.grid=this.calcGrid(this.graphManager.getRoot()),t=0;t<i.length;t++)e=i[t],this.addNodeToGrid(e,this.graphManager.getRoot().getLeft(),this.graphManager.getRoot().getTop())},h.prototype.calculateRepulsionForceOfANode=function(t,e,i,n){if(this.totalIterations%r.GRID_CALCULATION_CHECK_PERIOD==1&&i||n){var o,s=new Set;t.surrounding=new Array;for(var a=this.grid,h=t.startX-1;h<t.finishX+2;h++)for(var l=t.startY-1;l<t.finishY+2;l++)if(!(h<0||l<0||h>=a.length||l>=a[0].length))for(var c=0;c<a[h][l].length;c++)if(o=a[h][l][c],t.getOwner()==o.getOwner()&&t!=o&&!e.has(o)&&!s.has(o)){var g=Math.abs(t.getCenterX()-o.getCenterX())-(t.getWidth()/2+o.getWidth()/2),u=Math.abs(t.getCenterY()-o.getCenterY())-(t.getHeight()/2+o.getHeight()/2);g<=this.repulsionRange&&u<=this.repulsionRange&&s.add(o)}t.surrounding=[].concat(function(t){if(Array.isArray(t)){for(var e=0,i=Array(t.length);e<t.length;e++)i[e]=t[e];return i}return Array.from(t)}(s))}for(h=0;h<t.surrounding.length;h++)this.calcRepulsionForce(t,t.surrounding[h])},h.prototype.calcRepulsionRange=function(){return 0},t.exports=h},function(t,e,i){"use strict";var n=i(1),r=i(7);function o(t,e,i){n.call(this,t,e,i),this.idealLength=r.DEFAULT_EDGE_LENGTH}for(var s in o.prototype=Object.create(n.prototype),n)o[s]=n[s];t.exports=o},function(t,e,i){"use strict";var n=i(3);function r(t,e,i,r){n.call(this,t,e,i,r),this.springForceX=0,this.springForceY=0,this.repulsionForceX=0,this.repulsionForceY=0,this.gravitationForceX=0,this.gravitationForceY=0,this.displacementX=0,this.displacementY=0,this.startX=0,this.finishX=0,this.startY=0,this.finishY=0,this.surrounding=[]}for(var o in r.prototype=Object.create(n.prototype),n)r[o]=n[o];r.prototype.setGridCoordinates=function(t,e,i,n){this.startX=t,this.finishX=e,this.startY=i,this.finishY=n},t.exports=r},function(t,e,i){"use strict";function n(t,e){this.width=0,this.height=0,null!==t&&null!==e&&(this.height=e,this.width=t)}n.prototype.getWidth=function(){return this.width},n.prototype.setWidth=function(t){this.width=t},n.prototype.getHeight=function(){return this.height},n.prototype.setHeight=function(t){this.height=t},t.exports=n},function(t,e,i){"use strict";var n=i(14);function r(){this.map={},this.keys=[]}r.prototype.put=function(t,e){var i=n.createID(t);this.contains(i)||(this.map[i]=e,this.keys.push(t))},r.prototype.contains=function(t){return n.createID(t),null!=this.map[t]},r.prototype.get=function(t){var e=n.createID(t);return this.map[e]},r.prototype.keySet=function(){return this.keys},t.exports=r},function(t,e,i){"use strict";var n=i(14);function r(){this.set={}}r.prototype.add=function(t){var e=n.createID(t);this.contains(e)||(this.set[e]=t)},r.prototype.remove=function(t){delete this.set[n.createID(t)]},r.prototype.clear=function(){this.set={}},r.prototype.contains=function(t){return this.set[n.createID(t)]==t},r.prototype.isEmpty=function(){return 0===this.size()},r.prototype.size=function(){return Object.keys(this.set).length},r.prototype.addAllTo=function(t){for(var e=Object.keys(this.set),i=e.length,n=0;n<i;n++)t.push(this.set[e[n]])},r.prototype.size=function(){return Object.keys(this.set).length},r.prototype.addAll=function(t){for(var e=t.length,i=0;i<e;i++){var n=t[i];this.add(n)}},t.exports=r},function(t,e,i){"use strict";var n=function(){function t(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,i,n){return i&&t(e.prototype,i),n&&t(e,n),e}}(),r=i(11),o=function(){function t(e,i){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),null===i&&void 0===i||(this.compareFunction=this._defaultCompareFunction);var n=void 0;n=e instanceof r?e.size():e.length,this._quicksort(e,0,n-1)}return n(t,[{key:"_quicksort",value:function(t,e,i){if(e<i){var n=this._partition(t,e,i);this._quicksort(t,e,n),this._quicksort(t,n+1,i)}}},{key:"_partition",value:function(t,e,i){for(var n=this._get(t,e),r=e,o=i;;){for(;this.compareFunction(n,this._get(t,o));)o--;for(;this.compareFunction(this._get(t,r),n);)r++;if(!(r<o))return o;this._swap(t,r,o),r++,o--}}},{key:"_get",value:function(t,e){return t instanceof r?t.get_object_at(e):t[e]}},{key:"_set",value:function(t,e,i){t instanceof r?t.set_object_at(e,i):t[e]=i}},{key:"_swap",value:function(t,e,i){var n=this._get(t,e);this._set(t,e,this._get(t,i)),this._set(t,i,n)}},{key:"_defaultCompareFunction",value:function(t,e){return e>t}}]),t}();t.exports=o},function(t,e,i){"use strict";var n=function(){function t(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,i,n){return i&&t(e.prototype,i),n&&t(e,n),e}}(),r=function(){function t(e,i){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:-1,o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.sequence1=e,this.sequence2=i,this.match_score=n,this.mismatch_penalty=r,this.gap_penalty=o,this.iMax=e.length+1,this.jMax=i.length+1,this.grid=new Array(this.iMax);for(var s=0;s<this.iMax;s++){this.grid[s]=new Array(this.jMax);for(var a=0;a<this.jMax;a++)this.grid[s][a]=0}this.tracebackGrid=new Array(this.iMax);for(var h=0;h<this.iMax;h++){this.tracebackGrid[h]=new Array(this.jMax);for(var l=0;l<this.jMax;l++)this.tracebackGrid[h][l]=[null,null,null]}this.alignments=[],this.score=-1,this.computeGrids()}return n(t,[{key:"getScore",value:function(){return this.score}},{key:"getAlignments",value:function(){return this.alignments}},{key:"computeGrids",value:function(){for(var t=1;t<this.jMax;t++)this.grid[0][t]=this.grid[0][t-1]+this.gap_penalty,this.tracebackGrid[0][t]=[!1,!1,!0];for(var e=1;e<this.iMax;e++)this.grid[e][0]=this.grid[e-1][0]+this.gap_penalty,this.tracebackGrid[e][0]=[!1,!0,!1];for(var i=1;i<this.iMax;i++)for(var n=1;n<this.jMax;n++){var r=[this.sequence1[i-1]===this.sequence2[n-1]?this.grid[i-1][n-1]+this.match_score:this.grid[i-1][n-1]+this.mismatch_penalty,this.grid[i-1][n]+this.gap_penalty,this.grid[i][n-1]+this.gap_penalty],o=this.arrayAllMaxIndexes(r);this.grid[i][n]=r[o[0]],this.tracebackGrid[i][n]=[o.includes(0),o.includes(1),o.includes(2)]}this.score=this.grid[this.iMax-1][this.jMax-1]}},{key:"alignmentTraceback",value:function(){var t=[];for(t.push({pos:[this.sequence1.length,this.sequence2.length],seq1:"",seq2:""});t[0];){var e=t[0],i=this.tracebackGrid[e.pos[0]][e.pos[1]];i[0]&&t.push({pos:[e.pos[0]-1,e.pos[1]-1],seq1:this.sequence1[e.pos[0]-1]+e.seq1,seq2:this.sequence2[e.pos[1]-1]+e.seq2}),i[1]&&t.push({pos:[e.pos[0]-1,e.pos[1]],seq1:this.sequence1[e.pos[0]-1]+e.seq1,seq2:"-"+e.seq2}),i[2]&&t.push({pos:[e.pos[0],e.pos[1]-1],seq1:"-"+e.seq1,seq2:this.sequence2[e.pos[1]-1]+e.seq2}),0===e.pos[0]&&0===e.pos[1]&&this.alignments.push({sequence1:e.seq1,sequence2:e.seq2}),t.shift()}return this.alignments}},{key:"getAllIndexes",value:function(t,e){for(var i=[],n=-1;-1!==(n=t.indexOf(e,n+1));)i.push(n);return i}},{key:"arrayAllMaxIndexes",value:function(t){return this.getAllIndexes(t,Math.max.apply(null,t))}}]),t}();t.exports=r},function(t,e,i){"use strict";var n=function(){};n.FDLayout=i(18),n.FDLayoutConstants=i(7),n.FDLayoutEdge=i(19),n.FDLayoutNode=i(20),n.DimensionD=i(21),n.HashMap=i(22),n.HashSet=i(23),n.IGeometry=i(8),n.IMath=i(9),n.Integer=i(10),n.Point=i(12),n.PointD=i(4),n.RandomSeed=i(16),n.RectangleD=i(13),n.Transform=i(17),n.UniqueIDGeneretor=i(14),n.Quicksort=i(24),n.LinkedList=i(11),n.LGraphObject=i(2),n.LGraph=i(5),n.LEdge=i(1),n.LGraphManager=i(6),n.LNode=i(3),n.Layout=i(15),n.LayoutConstants=i(0),n.NeedlemanWunsch=i(25),t.exports=n},function(t,e,i){"use strict";function n(){this.listeners=[]}var r=n.prototype;r.addListener=function(t,e){this.listeners.push({event:t,callback:e})},r.removeListener=function(t,e){for(var i=this.listeners.length;i>=0;i--){var n=this.listeners[i];n.event===t&&n.callback===e&&this.listeners.splice(i,1)}},r.emit=function(t,e){for(var i=0;i<this.listeners.length;i++){var n=this.listeners[i];t===n.event&&n.callback(e)}},t.exports=n}])},t.exports=e()},96383:(t,e,i)=>{"use strict";i.d(e,{diagram:()=>X});var n=i(10483),r=i(8159),o=i(77286),s=i(10009),a=i(90165),h=i(43457),l=i(20007),c=i(3219),g=i(78041),u=i(75263),d=function(){var t=(0,s.K2)((function(t,e,i,n){for(i=i||{},n=t.length;n--;i[t[n]]=e);return i}),"o"),e=[1,4],i=[1,13],n=[1,12],r=[1,15],o=[1,16],a=[1,20],h=[1,19],l=[6,7,8],c=[1,26],g=[1,24],u=[1,25],d=[6,7,11],p=[1,6,13,15,16,19,22],f=[1,33],y=[1,34],E=[1,6,7,11,13,15,16,19,22],_={trace:(0,s.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,mindMap:4,spaceLines:5,SPACELINE:6,NL:7,MINDMAP:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,node:14,ICON:15,CLASS:16,nodeWithId:17,nodeWithoutId:18,NODE_DSTART:19,NODE_DESCR:20,NODE_DEND:21,NODE_ID:22,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"MINDMAP",11:"EOF",13:"SPACELIST",15:"ICON",16:"CLASS",19:"NODE_DSTART",20:"NODE_DESCR",21:"NODE_DEND",22:"NODE_ID"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,2],[12,2],[12,2],[12,1],[12,1],[12,1],[12,1],[12,1],[14,1],[14,1],[18,3],[17,1],[17,4]],performAction:(0,s.K2)((function(t,e,i,n,r,o,s){var a=o.length-1;switch(r){case 6:case 7:return n;case 8:n.getLogger().trace("Stop NL ");break;case 9:n.getLogger().trace("Stop EOF ");break;case 11:n.getLogger().trace("Stop NL2 ");break;case 12:n.getLogger().trace("Stop EOF2 ");break;case 15:n.getLogger().info("Node: ",o[a].id),n.addNode(o[a-1].length,o[a].id,o[a].descr,o[a].type);break;case 16:n.getLogger().trace("Icon: ",o[a]),n.decorateNode({icon:o[a]});break;case 17:case 21:n.decorateNode({class:o[a]});break;case 18:n.getLogger().trace("SPACELIST");break;case 19:n.getLogger().trace("Node: ",o[a].id),n.addNode(0,o[a].id,o[a].descr,o[a].type);break;case 20:n.decorateNode({icon:o[a]});break;case 25:n.getLogger().trace("node found ..",o[a-2]),this.$={id:o[a-1],descr:o[a-1],type:n.getType(o[a-2],o[a])};break;case 26:this.$={id:o[a],descr:o[a],type:n.nodeType.DEFAULT};break;case 27:n.getLogger().trace("node found ..",o[a-3]),this.$={id:o[a-3],descr:o[a-1],type:n.getType(o[a-2],o[a])}}}),"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:e},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:e},{6:i,7:[1,10],9:9,12:11,13:n,14:14,15:r,16:o,17:17,18:18,19:a,22:h},t(l,[2,3]),{1:[2,2]},t(l,[2,4]),t(l,[2,5]),{1:[2,6],6:i,12:21,13:n,14:14,15:r,16:o,17:17,18:18,19:a,22:h},{6:i,9:22,12:11,13:n,14:14,15:r,16:o,17:17,18:18,19:a,22:h},{6:c,7:g,10:23,11:u},t(d,[2,22],{17:17,18:18,14:27,15:[1,28],16:[1,29],19:a,22:h}),t(d,[2,18]),t(d,[2,19]),t(d,[2,20]),t(d,[2,21]),t(d,[2,23]),t(d,[2,24]),t(d,[2,26],{19:[1,30]}),{20:[1,31]},{6:c,7:g,10:32,11:u},{1:[2,7],6:i,12:21,13:n,14:14,15:r,16:o,17:17,18:18,19:a,22:h},t(p,[2,14],{7:f,11:y}),t(E,[2,8]),t(E,[2,9]),t(E,[2,10]),t(d,[2,15]),t(d,[2,16]),t(d,[2,17]),{20:[1,35]},{21:[1,36]},t(p,[2,13],{7:f,11:y}),t(E,[2,11]),t(E,[2,12]),{21:[1,37]},t(d,[2,25]),t(d,[2,27])],defaultActions:{2:[2,1],6:[2,2]},parseError:(0,s.K2)((function(t,e){if(!e.recoverable){var i=new Error(t);throw i.hash=e,i}this.trace(t)}),"parseError"),parse:(0,s.K2)((function(t){var e=this,i=[0],n=[],r=[null],o=[],a=this.table,h="",l=0,c=0,g=0,u=o.slice.call(arguments,1),d=Object.create(this.lexer),p={yy:{}};for(var f in this.yy)Object.prototype.hasOwnProperty.call(this.yy,f)&&(p.yy[f]=this.yy[f]);d.setInput(t,p.yy),p.yy.lexer=d,p.yy.parser=this,void 0===d.yylloc&&(d.yylloc={});var y=d.yylloc;o.push(y);var E=d.options&&d.options.ranges;function _(){var t;return"number"!=typeof(t=n.pop()||d.lex()||1)&&(t instanceof Array&&(t=(n=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof p.yy.parseError?this.parseError=p.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,s.K2)((function(t){i.length=i.length-2*t,r.length=r.length-t,o.length=o.length-t}),"popStack"),(0,s.K2)(_,"lex");for(var m,v,N,A,L,T,O,D,I,w={};;){if(N=i[i.length-1],this.defaultActions[N]?A=this.defaultActions[N]:(null==m&&(m=_()),A=a[N]&&a[N][m]),void 0===A||!A.length||!A[0]){var R="";for(T in I=[],a[N])this.terminals_[T]&&T>2&&I.push("'"+this.terminals_[T]+"'");R=d.showPosition?"Parse error on line "+(l+1)+":\n"+d.showPosition()+"\nExpecting "+I.join(", ")+", got '"+(this.terminals_[m]||m)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==m?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(R,{text:d.match,token:this.terminals_[m]||m,line:d.yylineno,loc:y,expected:I})}if(A[0]instanceof Array&&A.length>1)throw new Error("Parse Error: multiple actions possible at state: "+N+", token: "+m);switch(A[0]){case 1:i.push(m),r.push(d.yytext),o.push(d.yylloc),i.push(A[1]),m=null,v?(m=v,v=null):(c=d.yyleng,h=d.yytext,l=d.yylineno,y=d.yylloc,g>0&&g--);break;case 2:if(O=this.productions_[A[1]][1],w.$=r[r.length-O],w._$={first_line:o[o.length-(O||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(O||1)].first_column,last_column:o[o.length-1].last_column},E&&(w._$.range=[o[o.length-(O||1)].range[0],o[o.length-1].range[1]]),void 0!==(L=this.performAction.apply(w,[h,c,l,p.yy,A[1],r,o].concat(u))))return L;O&&(i=i.slice(0,-1*O*2),r=r.slice(0,-1*O),o=o.slice(0,-1*O)),i.push(this.productions_[A[1]][0]),r.push(w.$),o.push(w._$),D=a[i[i.length-2]][i[i.length-1]],i.push(D);break;case 3:return!0}}return!0}),"parse")},m=function(){return{EOF:1,parseError:(0,s.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,s.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,s.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,s.K2)((function(t){var e=t.length,i=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),i.length-1&&(this.yylineno-=i.length-1);var r=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:i?(i.length===n.length?this.yylloc.first_column:0)+n[n.length-i.length].length-i[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[r[0],r[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,s.K2)((function(){return this._more=!0,this}),"more"),reject:(0,s.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,s.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,s.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,s.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,s.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,s.K2)((function(t,e){var i,n,r;if(this.options.backtrack_lexer&&(r={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(r.yylloc.range=this.yylloc.range.slice(0))),(n=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=n.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-n[n.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],i=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var o in r)this[o]=r[o];return!1}return!1}),"test_match"),next:(0,s.K2)((function(){if(this.done)return this.EOF;var t,e,i,n;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var r=this._currentRules(),o=0;o<r.length;o++)if((i=this._input.match(this.rules[r[o]]))&&(!e||i[0].length>e[0].length)){if(e=i,n=o,this.options.backtrack_lexer){if(!1!==(t=this.test_match(i,r[o])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,r[n]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,s.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,s.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,s.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,s.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,s.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,s.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,s.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,s.K2)((function(t,e,i,n){switch(i){case 0:return t.getLogger().trace("Found comment",e.yytext),6;case 1:return 8;case 2:this.begin("CLASS");break;case 3:return this.popState(),16;case 4:case 23:case 26:this.popState();break;case 5:t.getLogger().trace("Begin icon"),this.begin("ICON");break;case 6:return t.getLogger().trace("SPACELINE"),6;case 7:return 7;case 8:return 15;case 9:t.getLogger().trace("end icon"),this.popState();break;case 10:return t.getLogger().trace("Exploding node"),this.begin("NODE"),19;case 11:return t.getLogger().trace("Cloud"),this.begin("NODE"),19;case 12:return t.getLogger().trace("Explosion Bang"),this.begin("NODE"),19;case 13:return t.getLogger().trace("Cloud Bang"),this.begin("NODE"),19;case 14:case 15:case 16:case 17:return this.begin("NODE"),19;case 18:return 13;case 19:return 22;case 20:return 11;case 21:this.begin("NSTR2");break;case 22:return"NODE_DESCR";case 24:t.getLogger().trace("Starting NSTR"),this.begin("NSTR");break;case 25:return t.getLogger().trace("description:",e.yytext),"NODE_DESCR";case 27:return this.popState(),t.getLogger().trace("node end ))"),"NODE_DEND";case 28:return this.popState(),t.getLogger().trace("node end )"),"NODE_DEND";case 29:return this.popState(),t.getLogger().trace("node end ...",e.yytext),"NODE_DEND";case 30:case 33:case 34:return this.popState(),t.getLogger().trace("node end (("),"NODE_DEND";case 31:case 32:return this.popState(),t.getLogger().trace("node end (-"),"NODE_DEND";case 35:case 36:return t.getLogger().trace("Long description:",e.yytext),20}}),"anonymous"),rules:[/^(?:\s*%%.*)/i,/^(?:mindmap\b)/i,/^(?::::)/i,/^(?:.+)/i,/^(?:\n)/i,/^(?:::icon\()/i,/^(?:[\s]+[\n])/i,/^(?:[\n]+)/i,/^(?:[^\)]+)/i,/^(?:\))/i,/^(?:-\))/i,/^(?:\(-)/i,/^(?:\)\))/i,/^(?:\))/i,/^(?:\(\()/i,/^(?:\{\{)/i,/^(?:\()/i,/^(?:\[)/i,/^(?:[\s]+)/i,/^(?:[^\(\[\n\)\{\}]+)/i,/^(?:$)/i,/^(?:["][`])/i,/^(?:[^`"]+)/i,/^(?:[`]["])/i,/^(?:["])/i,/^(?:[^"]+)/i,/^(?:["])/i,/^(?:[\)]\))/i,/^(?:[\)])/i,/^(?:[\]])/i,/^(?:\}\})/i,/^(?:\(-)/i,/^(?:-\))/i,/^(?:\(\()/i,/^(?:\()/i,/^(?:[^\)\]\(\}]+)/i,/^(?:.+(?!\(\())/i],conditions:{CLASS:{rules:[3,4],inclusive:!1},ICON:{rules:[8,9],inclusive:!1},NSTR2:{rules:[22,23],inclusive:!1},NSTR:{rules:[25,26],inclusive:!1},NODE:{rules:[21,24,27,28,29,30,31,32,33,34,35,36],inclusive:!1},INITIAL:{rules:[0,1,2,5,6,7,10,11,12,13,14,15,16,17,18,19,20],inclusive:!0}}}}();function v(){this.yy={}}return _.lexer=m,(0,s.K2)(v,"Parser"),v.prototype=_,_.Parser=v,new v}();d.parser=d;var p=d,f=[],y=0,E={},_=(0,s.K2)((()=>{f=[],y=0,E={}}),"clear"),m=(0,s.K2)((function(t){for(let e=f.length-1;e>=0;e--)if(f[e].level<t)return f[e];return null}),"getParent"),v=(0,s.K2)((()=>f.length>0?f[0]:null),"getMindmap"),N=(0,s.K2)(((t,e,i,n)=>{s.Rm.info("addNode",t,e,i,n);const r=(0,s.D7)();let o=r.mindmap?.padding??s.UI.mindmap.padding;switch(n){case A.ROUNDED_RECT:case A.RECT:case A.HEXAGON:o*=2}const a={id:y++,nodeId:(0,s.jZ)(e,r),level:t,descr:(0,s.jZ)(i,r),type:n,children:[],width:r.mindmap?.maxNodeWidth??s.UI.mindmap.maxNodeWidth,padding:o},h=m(t);if(h)h.children.push(a),f.push(a);else{if(0!==f.length)throw new Error('There can be only one root. No parent could be found for ("'+a.descr+'")');f.push(a)}}),"addNode"),A={DEFAULT:0,NO_BORDER:0,ROUNDED_RECT:1,RECT:2,CIRCLE:3,CLOUD:4,BANG:5,HEXAGON:6},L={clear:_,addNode:N,getMindmap:v,nodeType:A,getType:(0,s.K2)(((t,e)=>{switch(s.Rm.debug("In get type",t,e),t){case"[":return A.RECT;case"(":return")"===e?A.ROUNDED_RECT:A.CLOUD;case"((":return A.CIRCLE;case")":return A.CLOUD;case"))":return A.BANG;case"{{":return A.HEXAGON;default:return A.DEFAULT}}),"getType"),setElementForId:(0,s.K2)(((t,e)=>{E[t]=e}),"setElementForId"),decorateNode:(0,s.K2)((t=>{if(!t)return;const e=(0,s.D7)(),i=f[f.length-1];t.icon&&(i.icon=(0,s.jZ)(t.icon,e)),t.class&&(i.class=(0,s.jZ)(t.class,e))}),"decorateNode"),type2Str:(0,s.K2)((t=>{switch(t){case A.DEFAULT:return"no-border";case A.RECT:return"rect";case A.ROUNDED_RECT:return"rounded-rect";case A.CIRCLE:return"circle";case A.CLOUD:return"cloud";case A.BANG:return"bang";case A.HEXAGON:return"hexgon";default:return"no-border"}}),"type2Str"),getLogger:(0,s.K2)((()=>s.Rm),"getLogger"),getElementById:(0,s.K2)((t=>E[t]),"getElementById")},T=(0,s.K2)((function(t,e,i,n){e.append("path").attr("id","node-"+i.id).attr("class","node-bkg node-"+t.type2Str(i.type)).attr("d",`M0 ${i.height-5} v${10-i.height} q0,-5 5,-5 h${i.width-10} q5,0 5,5 v${i.height-5} H0 Z`),e.append("line").attr("class","node-line-"+n).attr("x1",0).attr("y1",i.height).attr("x2",i.width).attr("y2",i.height)}),"defaultBkg"),O=(0,s.K2)((function(t,e,i){e.append("rect").attr("id","node-"+i.id).attr("class","node-bkg node-"+t.type2Str(i.type)).attr("height",i.height).attr("width",i.width)}),"rectBkg"),D=(0,s.K2)((function(t,e,i){const n=i.width,r=i.height,o=.15*n,s=.25*n,a=.35*n,h=.2*n;e.append("path").attr("id","node-"+i.id).attr("class","node-bkg node-"+t.type2Str(i.type)).attr("d",`M0 0 a${o},${o} 0 0,1 ${.25*n},${-1*n*.1}\n a${a},${a} 1 0,1 ${.4*n},${-1*n*.1}\n a${s},${s} 1 0,1 ${.35*n},${1*n*.2}\n\n a${o},${o} 1 0,1 ${.15*n},${1*r*.35}\n a${h},${h} 1 0,1 ${-1*n*.15},${1*r*.65}\n\n a${s},${o} 1 0,1 ${-1*n*.25},${.15*n}\n a${a},${a} 1 0,1 ${-1*n*.5},0\n a${o},${o} 1 0,1 ${-1*n*.25},${-1*n*.15}\n\n a${o},${o} 1 0,1 ${-1*n*.1},${-1*r*.35}\n a${h},${h} 1 0,1 ${.1*n},${-1*r*.65}\n\n H0 V0 Z`)}),"cloudBkg"),I=(0,s.K2)((function(t,e,i){const n=i.width,r=i.height,o=.15*n;e.append("path").attr("id","node-"+i.id).attr("class","node-bkg node-"+t.type2Str(i.type)).attr("d",`M0 0 a${o},${o} 1 0,0 ${.25*n},${-1*r*.1}\n a${o},${o} 1 0,0 ${.25*n},0\n a${o},${o} 1 0,0 ${.25*n},0\n a${o},${o} 1 0,0 ${.25*n},${1*r*.1}\n\n a${o},${o} 1 0,0 ${.15*n},${1*r*.33}\n a${.8*o},${.8*o} 1 0,0 0,${1*r*.34}\n a${o},${o} 1 0,0 ${-1*n*.15},${1*r*.33}\n\n a${o},${o} 1 0,0 ${-1*n*.25},${.15*r}\n a${o},${o} 1 0,0 ${-1*n*.25},0\n a${o},${o} 1 0,0 ${-1*n*.25},0\n a${o},${o} 1 0,0 ${-1*n*.25},${-1*r*.15}\n\n a${o},${o} 1 0,0 ${-1*n*.1},${-1*r*.33}\n a${.8*o},${.8*o} 1 0,0 0,${-1*r*.34}\n a${o},${o} 1 0,0 ${.1*n},${-1*r*.33}\n\n H0 V0 Z`)}),"bangBkg"),w=(0,s.K2)((function(t,e,i){e.append("circle").attr("id","node-"+i.id).attr("class","node-bkg node-"+t.type2Str(i.type)).attr("r",i.width/2)}),"circleBkg");function R(t,e,i,n,r){return t.insert("polygon",":first-child").attr("points",n.map((function(t){return t.x+","+t.y})).join(" ")).attr("transform","translate("+(r.width-e)/2+", "+i+")")}(0,s.K2)(R,"insertPolygonShape");var C=(0,s.K2)((function(t,e,i){const n=i.height,r=n/4,o=i.width-i.padding+2*r;R(e,o,n,[{x:r,y:0},{x:o-r,y:0},{x:o,y:-n/2},{x:o-r,y:-n},{x:r,y:-n},{x:0,y:-n/2}],i)}),"hexagonBkg"),M=(0,s.K2)((function(t,e,i){e.append("rect").attr("id","node-"+i.id).attr("class","node-bkg node-"+t.type2Str(i.type)).attr("height",i.height).attr("rx",i.padding).attr("ry",i.padding).attr("width",i.width)}),"roundedRectBkg"),x=(0,s.K2)((async function(t,e,i,o,s){const a=s.htmlLabels,h=o%11,l=e.append("g");i.section=h;let c="section-"+h;h<0&&(c+=" section-root"),l.attr("class",(i.class?i.class+" ":"")+"mindmap-node "+c);const g=l.append("g"),u=l.append("g"),d=i.descr.replace(/(<br\/*>)/g,"\n");await(0,n.GZ)(u,d,{useHtmlLabels:a,width:i.width,classes:"mindmap-node-label"},s),a||u.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle");const p=u.node().getBBox(),[f]=(0,r.I5)(s.fontSize);if(i.height=p.height+1.1*f*.5+i.padding,i.width=p.width+2*i.padding,i.icon)if(i.type===t.nodeType.CIRCLE){i.height+=50,i.width+=50;l.append("foreignObject").attr("height","50px").attr("width",i.width).attr("style","text-align: center;").append("div").attr("class","icon-container").append("i").attr("class","node-icon-"+h+" "+i.icon),u.attr("transform","translate("+i.width/2+", "+(i.height/2-1.5*i.padding)+")")}else{i.width+=50;const t=i.height;i.height=Math.max(t,60);const e=Math.abs(i.height-t);l.append("foreignObject").attr("width","60px").attr("height",i.height).attr("style","text-align: center;margin-top:"+e/2+"px;").append("div").attr("class","icon-container").append("i").attr("class","node-icon-"+h+" "+i.icon),u.attr("transform","translate("+(25+i.width/2)+", "+(e/2+i.padding/2)+")")}else if(a){const t=(i.width-p.width)/2,e=(i.height-p.height)/2;u.attr("transform","translate("+t+", "+e+")")}else{const t=i.width/2,e=i.padding/2;u.attr("transform","translate("+t+", "+e+")")}switch(i.type){case t.nodeType.DEFAULT:T(t,g,i,h);break;case t.nodeType.ROUNDED_RECT:M(t,g,i,h);break;case t.nodeType.RECT:O(t,g,i,h);break;case t.nodeType.CIRCLE:g.attr("transform","translate("+i.width/2+", "+ +i.height/2+")"),w(t,g,i,h);break;case t.nodeType.CLOUD:D(t,g,i,h);break;case t.nodeType.BANG:I(t,g,i,h);break;case t.nodeType.HEXAGON:C(t,g,i,h)}return t.setElementForId(i.id,l),i.height}),"drawNode"),G=(0,s.K2)((function(t,e){const i=t.getElementById(e.id),n=e.x||0,r=e.y||0;i.attr("transform","translate("+n+","+r+")")}),"positionNode");async function S(t,e,i,n,r){await x(t,e,i,n,r),i.children&&await Promise.all(i.children.map(((i,o)=>S(t,e,i,n<0?o:n,r))))}function b(t,e){e.edges().map(((e,i)=>{const n=e.data();if(e[0]._private.bodyBounds){const r=e[0]._private.rscratch;s.Rm.trace("Edge: ",i,n),t.insert("path").attr("d",`M ${r.startX},${r.startY} L ${r.midX},${r.midY} L${r.endX},${r.endY} `).attr("class","edge section-edge-"+n.section+" edge-depth-"+n.depth)}}))}function F(t,e,i,n){e.add({group:"nodes",data:{id:t.id.toString(),labelText:t.descr,height:t.height,width:t.width,level:n,nodeId:t.id,padding:t.padding,type:t.type},position:{x:t.x,y:t.y}}),t.children&&t.children.forEach((r=>{F(r,e,i,n+1),e.add({group:"edges",data:{id:`${t.id}_${r.id}`,source:t.id,target:r.id,depth:n,section:r.section}})}))}function P(t,e){return new Promise((i=>{const n=(0,l.Ltv)("body").append("div").attr("id","cy").attr("style","display:none"),r=(0,a.A)({container:document.getElementById("cy"),style:[{selector:"edge",style:{"curve-style":"bezier"}}]});n.remove(),F(t,r,e,0),r.nodes().forEach((function(t){t.layoutDimensions=()=>{const e=t.data();return{w:e.width,h:e.height}}})),r.layout({name:"cose-bilkent",quality:"proof",styleEnabled:!1,animate:!1}).run(),r.ready((t=>{s.Rm.info("Ready",t),i(r)}))}))}function U(t,e){e.nodes().map(((e,i)=>{const n=e.data();n.x=e.position().x,n.y=e.position().y,G(t,n);const r=t.getElementById(n.nodeId);s.Rm.info("Id:",i,"Position: (",e.position().x,", ",e.position().y,")",n),r.attr("transform",`translate(${e.position().x-n.width/2}, ${e.position().y-n.height/2})`),r.attr("attr",`apa-${i})`)}))}a.A.use(h),(0,s.K2)(S,"drawNodes"),(0,s.K2)(b,"drawEdges"),(0,s.K2)(F,"addNodes"),(0,s.K2)(P,"layoutMindmap"),(0,s.K2)(U,"positionNodes");var Y={draw:(0,s.K2)((async(t,e,i,n)=>{s.Rm.debug("Rendering mindmap diagram\n"+t);const r=n.db,a=r.getMindmap();if(!a)return;const h=(0,s.D7)();h.htmlLabels=!1;const l=(0,o.D)(e),c=l.append("g");c.attr("class","mindmap-edges");const g=l.append("g");g.attr("class","mindmap-nodes"),await S(r,g,a,-1,h);const u=await P(a,h);b(c,u),U(r,u),(0,s.ot)(void 0,l,h.mindmap?.padding??s.UI.mindmap.padding,h.mindmap?.useMaxWidth??s.UI.mindmap.useMaxWidth)}),"draw")},k=(0,s.K2)((t=>{let e="";for(let i=0;i<t.THEME_COLOR_LIMIT;i++)t["lineColor"+i]=t["lineColor"+i]||t["cScaleInv"+i],(0,c.A)(t["lineColor"+i])?t["lineColor"+i]=(0,g.A)(t["lineColor"+i],20):t["lineColor"+i]=(0,u.A)(t["lineColor"+i],20);for(let i=0;i<t.THEME_COLOR_LIMIT;i++){const n=""+(17-3*i);e+=`\n .section-${i-1} rect, .section-${i-1} path, .section-${i-1} circle, .section-${i-1} polygon, .section-${i-1} path {\n fill: ${t["cScale"+i]};\n }\n .section-${i-1} text {\n fill: ${t["cScaleLabel"+i]};\n }\n .node-icon-${i-1} {\n font-size: 40px;\n color: ${t["cScaleLabel"+i]};\n }\n .section-edge-${i-1}{\n stroke: ${t["cScale"+i]};\n }\n .edge-depth-${i-1}{\n stroke-width: ${n};\n }\n .section-${i-1} line {\n stroke: ${t["cScaleInv"+i]} ;\n stroke-width: 3;\n }\n\n .disabled, .disabled circle, .disabled text {\n fill: lightgray;\n }\n .disabled text {\n fill: #efefef;\n }\n `}return e}),"genSections"),X={db:L,renderer:Y,parser:p,styles:(0,s.K2)((t=>`\n .edge {\n stroke-width: 3;\n }\n ${k(t)}\n .section-root rect, .section-root path, .section-root circle, .section-root polygon {\n fill: ${t.git0};\n }\n .section-root text {\n fill: ${t.gitBranchLabel0};\n }\n .icon-container {\n height:100%;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .edge {\n fill: none;\n }\n .mindmap-node-label {\n dy: 1em;\n alignment-baseline: middle;\n text-anchor: middle;\n dominant-baseline: middle;\n text-align: center;\n }\n`),"getStyles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/640cb024.1beeaa31.js b/pr-preview/pr-1071/assets/js/640cb024.1beeaa31.js deleted file mode 100644 index bebf4dee39..0000000000 --- a/pr-preview/pr-1071/assets/js/640cb024.1beeaa31.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7682],{8381:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/docs/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/next/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/basics/security-benefits.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/next/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/next/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(67976).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(82766).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},82766:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},67976:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/642ed902.b6b3e13d.js b/pr-preview/pr-1071/assets/js/642ed902.b6b3e13d.js deleted file mode 100644 index 2c1a8abe1c..0000000000 --- a/pr-preview/pr-1071/assets/js/642ed902.b6b3e13d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5541],{48162:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/docs/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/next/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/architecture/attestation.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/next/components/service-mesh"},"next":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/next/architecture/secrets"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(82050).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(53787).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nThe hypervisor adds the hash of the policy to the attestation report via the HOSTDATA (on AMD SEV-SNP) or MRCONFIGID (Intel TDX) fields.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,r.jsx)(t.code,{children:"MRCONFIGID"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(43486).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP or Intel TDX to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},43486:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},53787:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},82050:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6452.9f5d0a8d.js b/pr-preview/pr-1071/assets/js/6452.9f5d0a8d.js deleted file mode 100644 index 40647f87a7..0000000000 --- a/pr-preview/pr-1071/assets/js/6452.9f5d0a8d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6452],{6452:(c,e,s)=>{s.d(e,{createPacketServices:()=>t.$});var t=s(71609);s(19369)}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6478b99f.02d4423b.js b/pr-preview/pr-1071/assets/js/6478b99f.02d4423b.js deleted file mode 100644 index b4cb71c598..0000000000 --- a/pr-preview/pr-1071/assets/js/6478b99f.02d4423b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3506],{56468:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"known-limitations","title":"Known Limitations","description":"As Contrast is currently in an early development stage, it\'s built on several projects that are also under active development.","source":"@site/versioned_docs/version-0.6/known-limitations.md","sourceDirName":".","slug":"/known-limitations","permalink":"/contrast/pr-preview/pr-1071/0.6/known-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/known-limitations.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates"},"next":{"title":"About","permalink":"/contrast/pr-preview/pr-1071/0.6/about/"}}');var s=t(74848),r=t(28453);const o={},a="Known Limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes Features",id:"kubernetes-features",level:2},{value:"Runtime Policies",id:"runtime-policies",level:2},{value:"Tooling Integration",id:"tooling-integration",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"known-limitations",children:"Known Limitations"})}),"\n",(0,s.jsx)(n.p,{children:"As Contrast is currently in an early development stage, it's built on several projects that are also under active development.\nThis section outlines the most significant known limitations, providing stakeholders with clear expectations and understanding of the current state."}),"\n",(0,s.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Platform Support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,s.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes Features"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Persistent Volumes"}),": Not currently supported within Confidential Containers."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Port-Forwarding"}),": This feature ",(0,s.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,s.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Resource Limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"runtime-policies",children:"Runtime Policies"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,s.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,s.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Volume integrity checks"}),": While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ",(0,s.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,s.jsx)(n.h2,{id:"tooling-integration",children:"Tooling Integration"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"CLI Availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var i=t(96540);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/64d58a39.313bf37c.js b/pr-preview/pr-1071/assets/js/64d58a39.313bf37c.js deleted file mode 100644 index 008df91350..0000000000 --- a/pr-preview/pr-1071/assets/js/64d58a39.313bf37c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2005],{4463:(t,e,r)=>{r.r(e),r.d(e,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>s,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/attestation/coordinator","title":"coordinator","description":"","source":"@site/versioned_docs/version-0.5/architecture/attestation/coordinator.md","sourceDirName":"architecture/attestation","slug":"/architecture/attestation/coordinator","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/attestation/coordinator.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Manifest","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest"},"next":{"title":"Certificates and Identities","permalink":"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities"}}');var o=r(74848),i=r(28453);const s={},a=void 0,c={},d=[];function u(t){return(0,o.jsx)(o.Fragment,{})}function p(t={}){const{wrapper:e}={...(0,i.R)(),...t.components};return e?(0,o.jsx)(e,{...t,children:(0,o.jsx)(u,{...t})}):u()}},28453:(t,e,r)=>{r.d(e,{R:()=>s,x:()=>a});var n=r(96540);const o={},i=n.createContext(o);function s(t){const e=n.useContext(i);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:s(t.components),n.createElement(i.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6507182a.4e32c5ba.js b/pr-preview/pr-1071/assets/js/6507182a.4e32c5ba.js deleted file mode 100644 index 0691157f0b..0000000000 --- a/pr-preview/pr-1071/assets/js/6507182a.4e32c5ba.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9079],{90915:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"architecture/security-considerations","title":"Security Considerations","description":"Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits).","source":"@site/versioned_docs/version-1.1/architecture/security-considerations.md","sourceDirName":"architecture","slug":"/architecture/security-considerations","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/architecture/security-considerations.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/certificates"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/observability"}}');var r=n(74848),s=n(28453);const o={},a="Security Considerations",c={},d=[{value:"General recommendations",id:"general-recommendations",level:2},{value:"Authentication",id:"authentication",level:3},{value:"Encryption",id:"encryption",level:3},{value:"Contrast security guarantees",id:"contrast-security-guarantees",level:2},{value:"Limitations inherent to policy checking",id:"limitations-inherent-to-policy-checking",level:3},{value:"Logs",id:"logs",level:3}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"security-considerations",children:"Security Considerations"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast ensures application integrity and provides secure means of communication and bootstrapping (see ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",children:"security benefits"}),").\nHowever, care must be taken when interacting with the outside of Contrast's confidential environment.\nThis page presents some tips for writing secure applications and outlines the trust boundaries app developers need to know."]}),"\n",(0,r.jsx)(t.h2,{id:"general-recommendations",children:"General recommendations"}),"\n",(0,r.jsx)(t.h3,{id:"authentication",children:"Authentication"}),"\n",(0,r.jsx)(t.p,{children:"The application receives credentials from the Contrast Coordinator during initialization.\nThis allows to authenticate towards peers and to verify credentials received from peers.\nThe application should use the certificate bundle to authenticate incoming requests and be wary of unauthenticated requests or requests with a different root of trust (for example the internet PKI)."}),"\n",(0,r.jsx)(t.p,{children:"The recommendation to authenticate not only applies to network traffic, but also to volumes, GPUs and other devices.\nGenerally speaking, all information provided by the world outside the confidential VM should be treated with due scepticism, especially if it's not authenticated.\nCommon cases where Kubernetes apps interact with external services include DNS, Kubernetes API clients and cloud storage endpoints."}),"\n",(0,r.jsx)(t.h3,{id:"encryption",children:"Encryption"}),"\n",(0,r.jsx)(t.p,{children:"Any external persistence should be encrypted with an authenticated cipher.\nThis recommendation applies to block devices or filesystems mounted into the container, but also to cloud blob storage or external databases."}),"\n",(0,r.jsx)(t.h2,{id:"contrast-security-guarantees",children:"Contrast security guarantees"}),"\n",(0,r.jsx)(t.p,{children:"If an application authenticates with a certificate signed by the Contrast Mesh CA of a given manifest, Contrast provides the following guarantees:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"The container images used by the app are the images specified in the resource definitions."}),"\n",(0,r.jsx)(t.li,{children:"The command line arguments of containers are exactly the arguments specified in the resource definitions."}),"\n",(0,r.jsx)(t.li,{children:"All environment variables are either specified in resource definitions, in the container image manifest or in a settings file for the Contrast CLI."}),"\n",(0,r.jsx)(t.li,{children:"The containers run in a confidential VM that matches the reference values in the manifest."}),"\n",(0,r.jsx)(t.li,{children:"The containers' root filesystems are mounted in encrypted memory."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"limitations-inherent-to-policy-checking",children:"Limitations inherent to policy checking"}),"\n",(0,r.jsx)(t.p,{children:"Workload policies serve as workload identities.\nFrom the perspective of the Contrast Coordinator, all workloads that authenticate with the same policy are equal.\nThus, it's not possible to disambiguate, for example, pods spawned from a deployment or to limit the amount of certificates issued per policy."}),"\n",(0,r.jsxs)(t.p,{children:["Container image references from Kubernetes resource definitions are taken into account when generating the policy.\nA mutable reference may lead to policy failures or unverified image content, depending on the Contrast runtime.\nReliability and security can only be ensured with a full image reference, including digest.\nThe ",(0,r.jsxs)(t.a,{href:"https://docs.docker.com/reference/cli/docker/image/pull/#pull-an-image-by-digest-immutable-identifier",children:[(0,r.jsx)(t.code,{children:"docker pull"})," documentation"]})," explains pinned image references in detail."]}),"\n",(0,r.jsxs)(t.p,{children:["Policies can only verify what can be inferred at generation time.\nSome attributes of Kubernetes pods can't be predicted and thus can't be verified.\nParticularly the ",(0,r.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/downward-api/",children:"downward API"})," contains many fields that are dynamic or depend on the host environment, rendering it unsafe for process environment or arguments.\nThe same goes for ",(0,r.jsx)(t.code,{children:"ConfigMap"})," and ",(0,r.jsx)(t.code,{children:"Secret"})," resources, which can also be used to populate container fields.\nIf the application requires such external information, it should be injected as a mount point and carefully inspected before use."]}),"\n",(0,r.jsx)(t.p,{children:"Another type of dynamic content are persistent volumes.\nAny volumes mounted to the pod need to be scrutinized, and sensitive data must not be written to unprotected volumes.\nIdeally, a volume is mounted as a raw block device and authenticated encryption is added within the confidential container."}),"\n",(0,r.jsx)(t.h3,{id:"logs",children:"Logs"}),"\n",(0,r.jsx)(t.p,{children:"By default, container logs are visible to the host.\nSensitive information shouldn't be logged."}),"\n",(0,r.jsxs)(t.p,{children:["As of right now, hiding logs isn't natively supported.\nIf ",(0,r.jsx)(t.code,{children:"ReadStreamRequest"})," is denied in the policy, the Kata Agent stops reading the logs.\nThis causes the pipes used for standard out and standard error to fill up and potentially deadlock the container.\nIf absolutely required, standard out and standard error should be manually redirected to ",(0,r.jsx)(t.code,{children:"/dev/null"})," inside the container."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const r={},s=i.createContext(r);function o(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/68be920e.df678bfa.js b/pr-preview/pr-1071/assets/js/68be920e.df678bfa.js deleted file mode 100644 index d3ff19f74c..0000000000 --- a/pr-preview/pr-1071/assets/js/68be920e.df678bfa.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7294],{11080:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/versioned_docs/version-1.1/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/architecture/observability.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Security considerations","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/1.1/features-limitations"}}');var s=r(74848),i=r(28453);const o={},c="Observability",a={},d=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function h(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator exports gRPC metrics under the prefix ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_"}),".\nThese metrics are labeled with the gRPC service name and method name.\nMetrics of interest include ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handled_total"}),", which counts\nthe number of requests by return code, and\n",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handling_seconds_bucket"}),", which produces a histogram of",(0,s.jsx)(t.br,{}),"\n","request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["The gRPC service ",(0,s.jsx)(t.code,{children:"userapi.UserAPI"})," records metrics for the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"meshapi.MeshAPI"})," service records metrics for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"}),", which\ngets called by the ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/overview#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures_total"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6903d0da.63bafa91.js b/pr-preview/pr-1071/assets/js/6903d0da.63bafa91.js deleted file mode 100644 index 7ee6765d92..0000000000 --- a/pr-preview/pr-1071/assets/js/6903d0da.63bafa91.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[594],{43980:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product Features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-0.5/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/basics/features.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits"},"next":{"title":"Getting started","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/"}}');var r=n(74848),i=n(28453);const o={},a="Product Features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product Features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes Compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight Installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"../architecture",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote Attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service Mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/69ec948c.cd29b28f.js b/pr-preview/pr-1071/assets/js/69ec948c.cd29b28f.js deleted file mode 100644 index 3fa425fce1..0000000000 --- a/pr-preview/pr-1071/assets/js/69ec948c.cd29b28f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3712],{75778:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-0.5/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/0.5/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/deployment.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto"},"next":{"title":"Architecture","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/"}}');var r=n(74848),s=n(28453);const a={},i="Workload deployment",c={},l=[{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,s.R)(),...e.components},{TabItem:n,Tabs:o}=t;return n||p("TabItem",!0),o||p("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,r.jsx)(t.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,r.jsxs)(t.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup",children:"setup guide"})," on how to set it up."]}),"\n",(0,r.jsx)(t.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsx)(t.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml\n"})}),"\n",(0,r.jsx)(t.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,r.jsx)(t.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,r.jsxs)(o,{groupId:"yaml-source",children:[(0,r.jsx)(n,{value:"kustomize",label:"kustomize",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,r.jsx)(n,{value:"helm",label:"helm",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,r.jsx)(n,{value:"copy",label:"copy",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,r.jsxs)(t.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,r.jsx)(t.code,{children:"runtimeClassName: kata-cc-isolation"})," to the pod spec (pod definition or template).\nIn addition, add the Contrast Initializer as ",(0,r.jsx)(t.code,{children:"initContainers"})," to these workloads and configure the\nworkload to use the certificates written to a ",(0,r.jsx)(t.code,{children:"volumeMount"})," named ",(0,r.jsx)(t.code,{children:"tls-certs"}),"."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n runtimeClassName: kata-cc-isolation\n initContainers:\n - name: initializer\n image: "ghcr.io/edgelesssys/contrast/initializer:latest"\n env:\n - name: COORDINATOR_HOST\n value: coordinator\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n volumes:\n - name: tls-certs\n emptyDir: {}\n'})}),"\n",(0,r.jsx)(t.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(t.p,{children:["Run the ",(0,r.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as annotations to your\ndeployment files. A ",(0,r.jsx)(t.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate resources/\n"})}),"\n",(0,r.jsx)(t.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,r.jsx)(t.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,r.jsx)(t.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,r.jsx)(t.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,r.jsxs)(t.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,r.jsx)(t.a,{href:"https://github.com/edgelesssys/contrast/blob/main/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,r.jsx)(t.code,{children:"kubectl port-forward"}),"."]}),(0,r.jsxs)(t.p,{children:["Upstream tracking issue: ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,r.jsx)(t.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(t.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,r.jsx)(t.p,{children:"After this step, the Coordinator will start issuing TLS certs to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,r.jsx)(t.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,r.jsxs)(t.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,r.jsx)(t.code,{children:"verify"})," command."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsxs)(t.p,{children:["The CLI will attest the Coordinator using embedded reference values. The CLI will write the service mesh\nroot certificate and the history of manifests into the ",(0,r.jsx)(t.code,{children:"verify/"})," directory. In addition, the policies referenced\nin the manifest are also written to the directory."]}),"\n",(0,r.jsx)(t.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,r.jsxs)(t.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,r.jsx)(t.code,{children:"mesh-root.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\ntimeout 30s bash -c 'until kubectl get service/${MY_SERVICE} --output=jsonpath='{.status.loadBalancer}' | grep \"ingress\"; do sleep 2 ; done'\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,r.jsxs)(t.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,r.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh root certificate with throw the following error:"}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-root.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,r.jsxs)(t.p,{children:["Using ",(0,r.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,r.jsx)(t.code,{children:"mesh-root.pem"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-root.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function p(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>i});var o=n(96540);const r={},s=o.createContext(r);function a(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6a46f748.77a9fc8b.js b/pr-preview/pr-1071/assets/js/6a46f748.77a9fc8b.js deleted file mode 100644 index acdc3c6020..0000000000 --- a/pr-preview/pr-1071/assets/js/6a46f748.77a9fc8b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6240],{42508:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/versioned_docs/version-0.8/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/architecture/observability.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/certificates"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/0.8/features-limitations"}}');var s=r(74848),i=r(28453);const o={},c="Observability",a={},d=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function h(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator exports gRPC metrics under the prefix ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_"}),".\nThese metrics are labeled with the gRPC service name and method name.\nMetrics of interest include ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handled_total"}),", which counts\nthe number of requests by return code, and\n",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handling_seconds_bucket"}),", which produces a histogram of",(0,s.jsx)(t.br,{}),"\n","request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["The gRPC service ",(0,s.jsx)(t.code,{children:"userapi.UserAPI"})," records metrics for the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"meshapi.MeshAPI"})," service records metrics for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"}),", which\ngets called by the ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/6fc50b39.418b1af9.js b/pr-preview/pr-1071/assets/js/6fc50b39.418b1af9.js deleted file mode 100644 index e5d761cfda..0000000000 --- a/pr-preview/pr-1071/assets/js/6fc50b39.418b1af9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4213],{3669:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-0.8/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/0.8/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/getting-started/install.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/features"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup"}}');var r=s(74848),a=s(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v0.8.1/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,s)=>{s.d(e,{R:()=>o,x:()=>i});var n=s(96540);const r={},a=n.createContext(r);function o(t){const e=n.useContext(a);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),n.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7306.9fd39ca5.js b/pr-preview/pr-1071/assets/js/7306.9fd39ca5.js deleted file mode 100644 index 014f9ca66d..0000000000 --- a/pr-preview/pr-1071/assets/js/7306.9fd39ca5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7306],{17306:(t,e,r)=>{r.d(e,{diagram:()=>W});var a=r(8159),i=r(10009),n=r(697),s=r(20007),o=r(62334);const c=[];for(let U=0;U<256;++U)c.push((U+256).toString(16).slice(1));function l(t,e=0){return c[t[e+0]]+c[t[e+1]]+c[t[e+2]]+c[t[e+3]]+"-"+c[t[e+4]]+c[t[e+5]]+"-"+c[t[e+6]]+c[t[e+7]]+"-"+c[t[e+8]]+c[t[e+9]]+"-"+c[t[e+10]]+c[t[e+11]]+c[t[e+12]]+c[t[e+13]]+c[t[e+14]]+c[t[e+15]]}const h=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;const d=function(t){return"string"==typeof t&&h.test(t)};const u=function(t){if(!d(t))throw TypeError("Invalid UUID");let e;const r=new Uint8Array(16);return r[0]=(e=parseInt(t.slice(0,8),16))>>>24,r[1]=e>>>16&255,r[2]=e>>>8&255,r[3]=255&e,r[4]=(e=parseInt(t.slice(9,13),16))>>>8,r[5]=255&e,r[6]=(e=parseInt(t.slice(14,18),16))>>>8,r[7]=255&e,r[8]=(e=parseInt(t.slice(19,23),16))>>>8,r[9]=255&e,r[10]=(e=parseInt(t.slice(24,36),16))/1099511627776&255,r[11]=e/4294967296&255,r[12]=e>>>24&255,r[13]=e>>>16&255,r[14]=e>>>8&255,r[15]=255&e,r};function y(t,e,r,a){switch(t){case 0:return e&r^~e&a;case 1:case 3:return e^r^a;case 2:return e&r^e&a^r&a}}function p(t,e){return t<<e|t>>>32-e}const _=function(t,e,r){function a(t,a,i,n){var s;if("string"==typeof t&&(t=function(t){t=unescape(encodeURIComponent(t));const e=[];for(let r=0;r<t.length;++r)e.push(t.charCodeAt(r));return e}(t)),"string"==typeof a&&(a=u(a)),16!==(null===(s=a)||void 0===s?void 0:s.length))throw TypeError("Namespace must be array-like (16 iterable integer values, 0-255)");let o=new Uint8Array(16+t.length);if(o.set(a),o.set(t,a.length),o=r(o),o[6]=15&o[6]|e,o[8]=63&o[8]|128,i){n=n||0;for(let t=0;t<16;++t)i[n+t]=o[t];return i}return l(o)}try{a.name=t}catch(i){}return a.DNS="6ba7b810-9dad-11d1-80b4-00c04fd430c8",a.URL="6ba7b811-9dad-11d1-80b4-00c04fd430c8",a}("v5",80,(function(t){const e=[1518500249,1859775393,2400959708,3395469782],r=[1732584193,4023233417,2562383102,271733878,3285377520];if("string"==typeof t){const e=unescape(encodeURIComponent(t));t=[];for(let r=0;r<e.length;++r)t.push(e.charCodeAt(r))}else Array.isArray(t)||(t=Array.prototype.slice.call(t));t.push(128);const a=t.length/4+2,i=Math.ceil(a/16),n=new Array(i);for(let s=0;s<i;++s){const e=new Uint32Array(16);for(let r=0;r<16;++r)e[r]=t[64*s+4*r]<<24|t[64*s+4*r+1]<<16|t[64*s+4*r+2]<<8|t[64*s+4*r+3];n[s]=e}n[i-1][14]=8*(t.length-1)/Math.pow(2,32),n[i-1][14]=Math.floor(n[i-1][14]),n[i-1][15]=8*(t.length-1)&4294967295;for(let s=0;s<i;++s){const t=new Uint32Array(80);for(let e=0;e<16;++e)t[e]=n[s][e];for(let e=16;e<80;++e)t[e]=p(t[e-3]^t[e-8]^t[e-14]^t[e-16],1);let a=r[0],i=r[1],o=r[2],c=r[3],l=r[4];for(let r=0;r<80;++r){const n=Math.floor(r/20),s=p(a,5)+y(n,i,o,c)+l+e[n]+t[r]>>>0;l=c,c=o,o=p(i,30)>>>0,i=a,a=s}r[0]=r[0]+a>>>0,r[1]=r[1]+i>>>0,r[2]=r[2]+o>>>0,r[3]=r[3]+c>>>0,r[4]=r[4]+l>>>0}return[r[0]>>24&255,r[0]>>16&255,r[0]>>8&255,255&r[0],r[1]>>24&255,r[1]>>16&255,r[1]>>8&255,255&r[1],r[2]>>24&255,r[2]>>16&255,r[2]>>8&255,255&r[2],r[3]>>24&255,r[3]>>16&255,r[3]>>8&255,255&r[3],r[4]>>24&255,r[4]>>16&255,r[4]>>8&255,255&r[4]]}));var f=function(){var t=(0,i.K2)((function(t,e,r,a){for(r=r||{},a=t.length;a--;r[t[a]]=e);return r}),"o"),e=[6,8,10,20,22,24,26,27,28],r=[1,10],a=[1,11],n=[1,12],s=[1,13],o=[1,14],c=[1,15],l=[1,21],h=[1,22],d=[1,23],u=[1,24],y=[1,25],p=[6,8,10,13,15,18,19,20,22,24,26,27,28,41,42,43,44,45],_=[1,34],f=[27,28,46,47],E=[41,42,43,44,45],g=[17,34],m=[1,54],O=[1,53],k=[17,34,36,38],b={trace:(0,i.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,entityName:11,relSpec:12,":":13,role:14,BLOCK_START:15,attributes:16,BLOCK_STOP:17,SQS:18,SQE:19,title:20,title_value:21,acc_title:22,acc_title_value:23,acc_descr:24,acc_descr_value:25,acc_descr_multiline_value:26,ALPHANUM:27,ENTITY_NAME:28,attribute:29,attributeType:30,attributeName:31,attributeKeyTypeList:32,attributeComment:33,ATTRIBUTE_WORD:34,attributeKeyType:35,COMMA:36,ATTRIBUTE_KEY:37,COMMENT:38,cardinality:39,relType:40,ZERO_OR_ONE:41,ZERO_OR_MORE:42,ONE_OR_MORE:43,ONLY_ONE:44,MD_PARENT:45,NON_IDENTIFYING:46,IDENTIFYING:47,WORD:48,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",8:"SPACE",10:"NEWLINE",13:":",15:"BLOCK_START",17:"BLOCK_STOP",18:"SQS",19:"SQE",20:"title",21:"title_value",22:"acc_title",23:"acc_title_value",24:"acc_descr",25:"acc_descr_value",26:"acc_descr_multiline_value",27:"ALPHANUM",28:"ENTITY_NAME",34:"ATTRIBUTE_WORD",36:"COMMA",37:"ATTRIBUTE_KEY",38:"COMMENT",41:"ZERO_OR_ONE",42:"ZERO_OR_MORE",43:"ONE_OR_MORE",44:"ONLY_ONE",45:"MD_PARENT",46:"NON_IDENTIFYING",47:"IDENTIFYING",48:"WORD"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,5],[9,4],[9,3],[9,1],[9,7],[9,6],[9,4],[9,2],[9,2],[9,2],[9,1],[11,1],[11,1],[16,1],[16,2],[29,2],[29,3],[29,3],[29,4],[30,1],[31,1],[32,1],[32,3],[35,1],[33,1],[12,3],[39,1],[39,1],[39,1],[39,1],[39,1],[40,1],[40,1],[14,1],[14,1],[14,1]],performAction:(0,i.K2)((function(t,e,r,a,i,n,s){var o=n.length-1;switch(i){case 1:break;case 2:case 6:case 7:this.$=[];break;case 3:n[o-1].push(n[o]),this.$=n[o-1];break;case 4:case 5:case 19:case 43:case 27:case 28:case 31:this.$=n[o];break;case 8:a.addEntity(n[o-4]),a.addEntity(n[o-2]),a.addRelationship(n[o-4],n[o],n[o-2],n[o-3]);break;case 9:a.addEntity(n[o-3]),a.addAttributes(n[o-3],n[o-1]);break;case 10:a.addEntity(n[o-2]);break;case 11:a.addEntity(n[o]);break;case 12:a.addEntity(n[o-6],n[o-4]),a.addAttributes(n[o-6],n[o-1]);break;case 13:a.addEntity(n[o-5],n[o-3]);break;case 14:a.addEntity(n[o-3],n[o-1]);break;case 15:case 16:this.$=n[o].trim(),a.setAccTitle(this.$);break;case 17:case 18:this.$=n[o].trim(),a.setAccDescription(this.$);break;case 20:case 41:case 42:case 32:this.$=n[o].replace(/"/g,"");break;case 21:case 29:this.$=[n[o]];break;case 22:n[o].push(n[o-1]),this.$=n[o];break;case 23:this.$={attributeType:n[o-1],attributeName:n[o]};break;case 24:this.$={attributeType:n[o-2],attributeName:n[o-1],attributeKeyTypeList:n[o]};break;case 25:this.$={attributeType:n[o-2],attributeName:n[o-1],attributeComment:n[o]};break;case 26:this.$={attributeType:n[o-3],attributeName:n[o-2],attributeKeyTypeList:n[o-1],attributeComment:n[o]};break;case 30:n[o-2].push(n[o]),this.$=n[o-2];break;case 33:this.$={cardA:n[o],relType:n[o-1],cardB:n[o-2]};break;case 34:this.$=a.Cardinality.ZERO_OR_ONE;break;case 35:this.$=a.Cardinality.ZERO_OR_MORE;break;case 36:this.$=a.Cardinality.ONE_OR_MORE;break;case 37:this.$=a.Cardinality.ONLY_ONE;break;case 38:this.$=a.Cardinality.MD_PARENT;break;case 39:this.$=a.Identification.NON_IDENTIFYING;break;case 40:this.$=a.Identification.IDENTIFYING}}),"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:9,20:r,22:a,24:n,26:s,27:o,28:c},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:16,11:9,20:r,22:a,24:n,26:s,27:o,28:c},t(e,[2,5]),t(e,[2,6]),t(e,[2,11],{12:17,39:20,15:[1,18],18:[1,19],41:l,42:h,43:d,44:u,45:y}),{21:[1,26]},{23:[1,27]},{25:[1,28]},t(e,[2,18]),t(p,[2,19]),t(p,[2,20]),t(e,[2,4]),{11:29,27:o,28:c},{16:30,17:[1,31],29:32,30:33,34:_},{11:35,27:o,28:c},{40:36,46:[1,37],47:[1,38]},t(f,[2,34]),t(f,[2,35]),t(f,[2,36]),t(f,[2,37]),t(f,[2,38]),t(e,[2,15]),t(e,[2,16]),t(e,[2,17]),{13:[1,39]},{17:[1,40]},t(e,[2,10]),{16:41,17:[2,21],29:32,30:33,34:_},{31:42,34:[1,43]},{34:[2,27]},{19:[1,44]},{39:45,41:l,42:h,43:d,44:u,45:y},t(E,[2,39]),t(E,[2,40]),{14:46,27:[1,49],28:[1,48],48:[1,47]},t(e,[2,9]),{17:[2,22]},t(g,[2,23],{32:50,33:51,35:52,37:m,38:O}),t([17,34,37,38],[2,28]),t(e,[2,14],{15:[1,55]}),t([27,28],[2,33]),t(e,[2,8]),t(e,[2,41]),t(e,[2,42]),t(e,[2,43]),t(g,[2,24],{33:56,36:[1,57],38:O}),t(g,[2,25]),t(k,[2,29]),t(g,[2,32]),t(k,[2,31]),{16:58,17:[1,59],29:32,30:33,34:_},t(g,[2,26]),{35:60,37:m},{17:[1,61]},t(e,[2,13]),t(k,[2,30]),t(e,[2,12])],defaultActions:{34:[2,27],41:[2,22]},parseError:(0,i.K2)((function(t,e){if(!e.recoverable){var r=new Error(t);throw r.hash=e,r}this.trace(t)}),"parseError"),parse:(0,i.K2)((function(t){var e=this,r=[0],a=[],n=[null],s=[],o=this.table,c="",l=0,h=0,d=0,u=s.slice.call(arguments,1),y=Object.create(this.lexer),p={yy:{}};for(var _ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,_)&&(p.yy[_]=this.yy[_]);y.setInput(t,p.yy),p.yy.lexer=y,p.yy.parser=this,void 0===y.yylloc&&(y.yylloc={});var f=y.yylloc;s.push(f);var E=y.options&&y.options.ranges;function g(){var t;return"number"!=typeof(t=a.pop()||y.lex()||1)&&(t instanceof Array&&(t=(a=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof p.yy.parseError?this.parseError=p.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,i.K2)((function(t){r.length=r.length-2*t,n.length=n.length-t,s.length=s.length-t}),"popStack"),(0,i.K2)(g,"lex");for(var m,O,k,b,R,N,x,T,A,M={};;){if(k=r[r.length-1],this.defaultActions[k]?b=this.defaultActions[k]:(null==m&&(m=g()),b=o[k]&&o[k][m]),void 0===b||!b.length||!b[0]){var w="";for(N in A=[],o[k])this.terminals_[N]&&N>2&&A.push("'"+this.terminals_[N]+"'");w=y.showPosition?"Parse error on line "+(l+1)+":\n"+y.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[m]||m)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==m?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(w,{text:y.match,token:this.terminals_[m]||m,line:y.yylineno,loc:f,expected:A})}if(b[0]instanceof Array&&b.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+m);switch(b[0]){case 1:r.push(m),n.push(y.yytext),s.push(y.yylloc),r.push(b[1]),m=null,O?(m=O,O=null):(h=y.yyleng,c=y.yytext,l=y.yylineno,f=y.yylloc,d>0&&d--);break;case 2:if(x=this.productions_[b[1]][1],M.$=n[n.length-x],M._$={first_line:s[s.length-(x||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(x||1)].first_column,last_column:s[s.length-1].last_column},E&&(M._$.range=[s[s.length-(x||1)].range[0],s[s.length-1].range[1]]),void 0!==(R=this.performAction.apply(M,[c,h,l,p.yy,b[1],n,s].concat(u))))return R;x&&(r=r.slice(0,-1*x*2),n=n.slice(0,-1*x),s=s.slice(0,-1*x)),r.push(this.productions_[b[1]][0]),n.push(M.$),s.push(M._$),T=o[r[r.length-2]][r[r.length-1]],r.push(T);break;case 3:return!0}}return!0}),"parse")},R=function(){return{EOF:1,parseError:(0,i.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,i.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,i.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,i.K2)((function(t){var e=t.length,r=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var a=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),r.length-1&&(this.yylineno-=r.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:r?(r.length===a.length?this.yylloc.first_column:0)+a[a.length-r.length].length-r[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,i.K2)((function(){return this._more=!0,this}),"more"),reject:(0,i.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,i.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,i.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,i.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,i.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,i.K2)((function(t,e){var r,a,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(a=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=a.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:a?a[a.length-1].length-a[a.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],r=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),r)return r;if(this._backtrack){for(var n in i)this[n]=i[n];return!1}return!1}),"test_match"),next:(0,i.K2)((function(){if(this.done)return this.EOF;var t,e,r,a;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),n=0;n<i.length;n++)if((r=this._input.match(this.rules[i[n]]))&&(!e||r[0].length>e[0].length)){if(e=r,a=n,this.options.backtrack_lexer){if(!1!==(t=this.test_match(r,i[n])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[a]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,i.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,i.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,i.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,i.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,i.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,i.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,i.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,i.K2)((function(t,e,r,a){switch(r){case 0:return this.begin("acc_title"),22;case 1:return this.popState(),"acc_title_value";case 2:return this.begin("acc_descr"),24;case 3:return this.popState(),"acc_descr_value";case 4:this.begin("acc_descr_multiline");break;case 5:this.popState();break;case 6:return"acc_descr_multiline_value";case 7:return 10;case 8:case 15:case 20:break;case 9:return 8;case 10:return 28;case 11:return 48;case 12:return 4;case 13:return this.begin("block"),15;case 14:return 36;case 16:return 37;case 17:case 18:return 34;case 19:return 38;case 21:return this.popState(),17;case 22:case 54:return e.yytext[0];case 23:return 18;case 24:return 19;case 25:case 29:case 30:case 43:return 41;case 26:case 27:case 28:case 36:case 38:case 45:return 43;case 31:case 32:case 33:case 34:case 35:case 37:case 44:return 42;case 39:case 40:case 41:case 42:return 44;case 46:return 45;case 47:case 50:case 51:case 52:return 46;case 48:case 49:return 47;case 53:return 27;case 55:return 6}}),"anonymous"),rules:[/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:[\s]+)/i,/^(?:"[^"%\r\n\v\b\\]+")/i,/^(?:"[^"]*")/i,/^(?:erDiagram\b)/i,/^(?:\{)/i,/^(?:,)/i,/^(?:\s+)/i,/^(?:\b((?:PK)|(?:FK)|(?:UK))\b)/i,/^(?:(.*?)[~](.*?)*[~])/i,/^(?:[\*A-Za-z_][A-Za-z0-9\-_\[\]\(\)]*)/i,/^(?:"[^"]*")/i,/^(?:[\n]+)/i,/^(?:\})/i,/^(?:.)/i,/^(?:\[)/i,/^(?:\])/i,/^(?:one or zero\b)/i,/^(?:one or more\b)/i,/^(?:one or many\b)/i,/^(?:1\+)/i,/^(?:\|o\b)/i,/^(?:zero or one\b)/i,/^(?:zero or more\b)/i,/^(?:zero or many\b)/i,/^(?:0\+)/i,/^(?:\}o\b)/i,/^(?:many\(0\))/i,/^(?:many\(1\))/i,/^(?:many\b)/i,/^(?:\}\|)/i,/^(?:one\b)/i,/^(?:only one\b)/i,/^(?:1\b)/i,/^(?:\|\|)/i,/^(?:o\|)/i,/^(?:o\{)/i,/^(?:\|\{)/i,/^(?:\s*u\b)/i,/^(?:\.\.)/i,/^(?:--)/i,/^(?:to\b)/i,/^(?:optionally to\b)/i,/^(?:\.-)/i,/^(?:-\.)/i,/^(?:[A-Za-z_][A-Za-z0-9\-_]*)/i,/^(?:.)/i,/^(?:$)/i],conditions:{acc_descr_multiline:{rules:[5,6],inclusive:!1},acc_descr:{rules:[3],inclusive:!1},acc_title:{rules:[1],inclusive:!1},block:{rules:[14,15,16,17,18,19,20,21,22],inclusive:!1},INITIAL:{rules:[0,2,4,7,8,9,10,11,12,13,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55],inclusive:!0}}}}();function N(){this.yy={}}return b.lexer=R,(0,i.K2)(N,"Parser"),N.prototype=b,b.Parser=N,new N}();f.parser=f;var E=f,g=new Map,m=[],O=(0,i.K2)((function(t,e=void 0){return g.has(t)?!g.get(t).alias&&e&&(g.get(t).alias=e,i.Rm.info(`Add alias '${e}' to entity '${t}'`)):(g.set(t,{attributes:[],alias:e}),i.Rm.info("Added new entity :",t)),g.get(t)}),"addEntity"),k=(0,i.K2)((()=>g),"getEntities"),b=(0,i.K2)((function(t,e){let r,a=O(t);for(r=e.length-1;r>=0;r--)a.attributes.push(e[r]),i.Rm.debug("Added attribute ",e[r].attributeName)}),"addAttributes"),R=(0,i.K2)((function(t,e,r,a){let n={entityA:t,roleA:e,entityB:r,relSpec:a};m.push(n),i.Rm.debug("Added new relationship :",n)}),"addRelationship"),N=(0,i.K2)((()=>m),"getRelationships"),x=(0,i.K2)((function(){g=new Map,m=[],(0,i.IU)()}),"clear"),T={Cardinality:{ZERO_OR_ONE:"ZERO_OR_ONE",ZERO_OR_MORE:"ZERO_OR_MORE",ONE_OR_MORE:"ONE_OR_MORE",ONLY_ONE:"ONLY_ONE",MD_PARENT:"MD_PARENT"},Identification:{NON_IDENTIFYING:"NON_IDENTIFYING",IDENTIFYING:"IDENTIFYING"},getConfig:(0,i.K2)((()=>(0,i.D7)().er),"getConfig"),addEntity:O,addAttributes:b,getEntities:k,addRelationship:R,getRelationships:N,clear:x,setAccTitle:i.SV,getAccTitle:i.iN,setAccDescription:i.EI,getAccDescription:i.m7,setDiagramTitle:i.ke,getDiagramTitle:i.ab},A={ONLY_ONE_START:"ONLY_ONE_START",ONLY_ONE_END:"ONLY_ONE_END",ZERO_OR_ONE_START:"ZERO_OR_ONE_START",ZERO_OR_ONE_END:"ZERO_OR_ONE_END",ONE_OR_MORE_START:"ONE_OR_MORE_START",ONE_OR_MORE_END:"ONE_OR_MORE_END",ZERO_OR_MORE_START:"ZERO_OR_MORE_START",ZERO_OR_MORE_END:"ZERO_OR_MORE_END",MD_PARENT_END:"MD_PARENT_END",MD_PARENT_START:"MD_PARENT_START"},M={ERMarkers:A,insertMarkers:(0,i.K2)((function(t,e){let r;t.append("defs").append("marker").attr("id",A.MD_PARENT_START).attr("refX",0).attr("refY",7).attr("markerWidth",190).attr("markerHeight",240).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",A.MD_PARENT_END).attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L1,7 L9,1 Z"),t.append("defs").append("marker").attr("id",A.ONLY_ONE_START).attr("refX",0).attr("refY",9).attr("markerWidth",18).attr("markerHeight",18).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M9,0 L9,18 M15,0 L15,18"),t.append("defs").append("marker").attr("id",A.ONLY_ONE_END).attr("refX",18).attr("refY",9).attr("markerWidth",18).attr("markerHeight",18).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M3,0 L3,18 M9,0 L9,18"),r=t.append("defs").append("marker").attr("id",A.ZERO_OR_ONE_START).attr("refX",0).attr("refY",9).attr("markerWidth",30).attr("markerHeight",18).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",21).attr("cy",9).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M9,0 L9,18"),r=t.append("defs").append("marker").attr("id",A.ZERO_OR_ONE_END).attr("refX",30).attr("refY",9).attr("markerWidth",30).attr("markerHeight",18).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",9).attr("cy",9).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M21,0 L21,18"),t.append("defs").append("marker").attr("id",A.ONE_OR_MORE_START).attr("refX",18).attr("refY",18).attr("markerWidth",45).attr("markerHeight",36).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M0,18 Q 18,0 36,18 Q 18,36 0,18 M42,9 L42,27"),t.append("defs").append("marker").attr("id",A.ONE_OR_MORE_END).attr("refX",27).attr("refY",18).attr("markerWidth",45).attr("markerHeight",36).attr("orient","auto").append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M3,9 L3,27 M9,18 Q27,0 45,18 Q27,36 9,18"),r=t.append("defs").append("marker").attr("id",A.ZERO_OR_MORE_START).attr("refX",18).attr("refY",18).attr("markerWidth",57).attr("markerHeight",36).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",48).attr("cy",18).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M0,18 Q18,0 36,18 Q18,36 0,18"),r=t.append("defs").append("marker").attr("id",A.ZERO_OR_MORE_END).attr("refX",39).attr("refY",18).attr("markerWidth",57).attr("markerHeight",36).attr("orient","auto"),r.append("circle").attr("stroke",e.stroke).attr("fill","white").attr("cx",9).attr("cy",18).attr("r",6),r.append("path").attr("stroke",e.stroke).attr("fill","none").attr("d","M21,18 Q39,0 57,18 Q39,36 21,18")}),"insertMarkers")},w=/[^\dA-Za-z](\W)*/g,I={},D=new Map,S=(0,i.K2)((function(t){const e=Object.keys(t);for(const r of e)I[r]=t[r]}),"setConf"),v=(0,i.K2)(((t,e,r)=>{const a=I.entityPadding/3,n=I.entityPadding/3,s=.85*I.fontSize,o=e.node().getBBox(),c=[];let l=!1,h=!1,d=0,u=0,y=0,p=0,_=o.height+2*a,f=1;r.forEach((t=>{void 0!==t.attributeKeyTypeList&&t.attributeKeyTypeList.length>0&&(l=!0),void 0!==t.attributeComment&&(h=!0)})),r.forEach((r=>{const n=`${e.node().id}-attr-${f}`;let o=0;const E=(0,i.QO)(r.attributeType),g=t.append("text").classed("er entityLabel",!0).attr("id",`${n}-type`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",(0,i.D7)().fontFamily).style("font-size",s+"px").text(E),m=t.append("text").classed("er entityLabel",!0).attr("id",`${n}-name`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",(0,i.D7)().fontFamily).style("font-size",s+"px").text(r.attributeName),O={};O.tn=g,O.nn=m;const k=g.node().getBBox(),b=m.node().getBBox();if(d=Math.max(d,k.width),u=Math.max(u,b.width),o=Math.max(k.height,b.height),l){const e=void 0!==r.attributeKeyTypeList?r.attributeKeyTypeList.join(","):"",a=t.append("text").classed("er entityLabel",!0).attr("id",`${n}-key`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",(0,i.D7)().fontFamily).style("font-size",s+"px").text(e);O.kn=a;const c=a.node().getBBox();y=Math.max(y,c.width),o=Math.max(o,c.height)}if(h){const e=t.append("text").classed("er entityLabel",!0).attr("id",`${n}-comment`).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","left").style("font-family",(0,i.D7)().fontFamily).style("font-size",s+"px").text(r.attributeComment||"");O.cn=e;const a=e.node().getBBox();p=Math.max(p,a.width),o=Math.max(o,a.height)}O.height=o,c.push(O),_+=o+2*a,f+=1}));let E=4;l&&(E+=2),h&&(E+=2);const g=d+u+y+p,m={width:Math.max(I.minEntityWidth,Math.max(o.width+2*I.entityPadding,g+n*E)),height:r.length>0?_:Math.max(I.minEntityHeight,o.height+2*I.entityPadding)};if(r.length>0){const r=Math.max(0,(m.width-g-n*E)/(E/2));e.attr("transform","translate("+m.width/2+","+(a+o.height/2)+")");let i=o.height+2*a,s="attributeBoxOdd";c.forEach((e=>{const o=i+a+e.height/2;e.tn.attr("transform","translate("+n+","+o+")");const c=t.insert("rect","#"+e.tn.node().id).classed(`er ${s}`,!0).attr("x",0).attr("y",i).attr("width",d+2*n+r).attr("height",e.height+2*a),_=parseFloat(c.attr("x"))+parseFloat(c.attr("width"));e.nn.attr("transform","translate("+(_+n)+","+o+")");const f=t.insert("rect","#"+e.nn.node().id).classed(`er ${s}`,!0).attr("x",_).attr("y",i).attr("width",u+2*n+r).attr("height",e.height+2*a);let E=parseFloat(f.attr("x"))+parseFloat(f.attr("width"));if(l){e.kn.attr("transform","translate("+(E+n)+","+o+")");const c=t.insert("rect","#"+e.kn.node().id).classed(`er ${s}`,!0).attr("x",E).attr("y",i).attr("width",y+2*n+r).attr("height",e.height+2*a);E=parseFloat(c.attr("x"))+parseFloat(c.attr("width"))}h&&(e.cn.attr("transform","translate("+(E+n)+","+o+")"),t.insert("rect","#"+e.cn.node().id).classed(`er ${s}`,"true").attr("x",E).attr("y",i).attr("width",p+2*n+r).attr("height",e.height+2*a)),i+=e.height+2*a,s="attributeBoxOdd"===s?"attributeBoxEven":"attributeBoxOdd"}))}else m.height=Math.max(I.minEntityHeight,_),e.attr("transform","translate("+m.width/2+","+m.height/2+")");return m}),"drawAttributes"),L=(0,i.K2)((function(t,e,r){let a;return[...e.keys()].forEach((function(n){const s=F(n,"entity");D.set(n,s);const o=t.append("g").attr("id",s);a=void 0===a?s:a;const c="text-"+s,l=o.append("text").classed("er entityLabel",!0).attr("id",c).attr("x",0).attr("y",0).style("dominant-baseline","middle").style("text-anchor","middle").style("font-family",(0,i.D7)().fontFamily).style("font-size",I.fontSize+"px").text(e.get(n).alias??n),{width:h,height:d}=v(o,l,e.get(n).attributes),u=o.insert("rect","#"+c).classed("er entityBox",!0).attr("x",0).attr("y",0).attr("width",h).attr("height",d).node().getBBox();r.setNode(s,{width:u.width,height:u.height,shape:"rect",id:s})})),a}),"drawEntities"),$=(0,i.K2)((function(t,e){e.nodes().forEach((function(r){void 0!==r&&void 0!==e.node(r)&&t.select("#"+r).attr("transform","translate("+(e.node(r).x-e.node(r).width/2)+","+(e.node(r).y-e.node(r).height/2)+" )")}))}),"adjustEntities"),K=(0,i.K2)((function(t){return(t.entityA+t.roleA+t.entityB).replace(/\s/g,"")}),"getEdgeName"),C=(0,i.K2)((function(t,e){return t.forEach((function(t){e.setEdge(D.get(t.entityA),D.get(t.entityB),{relationship:t},K(t))})),t}),"addRelationships"),B=0,P=(0,i.K2)((function(t,e,r,a,n){B++;const o=r.edge(D.get(e.entityA),D.get(e.entityB),K(e)),c=(0,s.n8j)().x((function(t){return t.x})).y((function(t){return t.y})).curve(s.qrM),l=t.insert("path","#"+a).classed("er relationshipLine",!0).attr("d",c(o.points)).style("stroke",I.stroke).style("fill","none");e.relSpec.relType===n.db.Identification.NON_IDENTIFYING&&l.attr("stroke-dasharray","8,8");let h="";switch(I.arrowMarkerAbsolute&&(h=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,h=h.replace(/\(/g,"\\("),h=h.replace(/\)/g,"\\)")),e.relSpec.cardA){case n.db.Cardinality.ZERO_OR_ONE:l.attr("marker-end","url("+h+"#"+M.ERMarkers.ZERO_OR_ONE_END+")");break;case n.db.Cardinality.ZERO_OR_MORE:l.attr("marker-end","url("+h+"#"+M.ERMarkers.ZERO_OR_MORE_END+")");break;case n.db.Cardinality.ONE_OR_MORE:l.attr("marker-end","url("+h+"#"+M.ERMarkers.ONE_OR_MORE_END+")");break;case n.db.Cardinality.ONLY_ONE:l.attr("marker-end","url("+h+"#"+M.ERMarkers.ONLY_ONE_END+")");break;case n.db.Cardinality.MD_PARENT:l.attr("marker-end","url("+h+"#"+M.ERMarkers.MD_PARENT_END+")")}switch(e.relSpec.cardB){case n.db.Cardinality.ZERO_OR_ONE:l.attr("marker-start","url("+h+"#"+M.ERMarkers.ZERO_OR_ONE_START+")");break;case n.db.Cardinality.ZERO_OR_MORE:l.attr("marker-start","url("+h+"#"+M.ERMarkers.ZERO_OR_MORE_START+")");break;case n.db.Cardinality.ONE_OR_MORE:l.attr("marker-start","url("+h+"#"+M.ERMarkers.ONE_OR_MORE_START+")");break;case n.db.Cardinality.ONLY_ONE:l.attr("marker-start","url("+h+"#"+M.ERMarkers.ONLY_ONE_START+")");break;case n.db.Cardinality.MD_PARENT:l.attr("marker-start","url("+h+"#"+M.ERMarkers.MD_PARENT_START+")")}const d=l.node().getTotalLength(),u=l.node().getPointAtLength(.5*d),y="rel"+B,p=e.roleA.split(/<br ?\/>/g),_=t.append("text").classed("er relationshipLabel",!0).attr("id",y).attr("x",u.x).attr("y",u.y).style("text-anchor","middle").style("dominant-baseline","middle").style("font-family",(0,i.D7)().fontFamily).style("font-size",I.fontSize+"px");if(1==p.length)_.text(e.roleA);else{const t=.5*-(p.length-1);p.forEach(((e,r)=>{_.append("tspan").attr("x",u.x).attr("dy",`${0===r?t:1}em`).text(e)}))}const f=_.node().getBBox();t.insert("rect","#"+y).classed("er relationshipLabelBox",!0).attr("x",u.x-f.width/2).attr("y",u.y-f.height/2).attr("width",f.width).attr("height",f.height)}),"drawRelationshipFromLayout"),Y=(0,i.K2)((function(t,e,r,c){I=(0,i.D7)().er,i.Rm.info("Drawing ER diagram");const l=(0,i.D7)().securityLevel;let h;"sandbox"===l&&(h=(0,s.Ltv)("#i"+e));const d=("sandbox"===l?(0,s.Ltv)(h.nodes()[0].contentDocument.body):(0,s.Ltv)("body")).select(`[id='${e}']`);let u;M.insertMarkers(d,I),u=new n.T({multigraph:!0,directed:!0,compound:!1}).setGraph({rankdir:I.layoutDirection,marginx:20,marginy:20,nodesep:100,edgesep:100,ranksep:100}).setDefaultEdgeLabel((function(){return{}}));const y=L(d,c.db.getEntities(),u),p=C(c.db.getRelationships(),u);(0,o.Zp)(u),$(d,u),p.forEach((function(t){P(d,t,u,y,c)}));const _=I.diagramPadding;a._K.insertTitle(d,"entityTitleText",I.titleTopMargin,c.db.getDiagramTitle());const f=d.node().getBBox(),E=f.width+2*_,g=f.height+2*_;(0,i.a$)(d,g,E,I.useMaxWidth),d.attr("viewBox",`${f.x-_} ${f.y-_} ${E} ${g}`)}),"draw"),Z="28e9f9db-3c8d-5aa5-9faf-44286ae5937c";function F(t="",e=""){const r=t.replace(w,"");return`${z(e)}${z(r)}${_(t,Z)}`}function z(t=""){return t.length>0?`${t}-`:""}(0,i.K2)(F,"generateId"),(0,i.K2)(z,"strWithHyphen");var W={parser:E,db:T,renderer:{setConf:S,draw:Y},styles:(0,i.K2)((t=>`\n .entityBox {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n }\n\n .attributeBoxOdd {\n fill: ${t.attributeBackgroundColorOdd};\n stroke: ${t.nodeBorder};\n }\n\n .attributeBoxEven {\n fill: ${t.attributeBackgroundColorEven};\n stroke: ${t.nodeBorder};\n }\n\n .relationshipLabelBox {\n fill: ${t.tertiaryColor};\n opacity: 0.7;\n background-color: ${t.tertiaryColor};\n rect {\n opacity: 0.5;\n }\n }\n\n .relationshipLine {\n stroke: ${t.lineColor};\n }\n\n .entityTitleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.textColor};\n } \n #MD_PARENT_START {\n fill: #f5f5f5 !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n }\n #MD_PARENT_END {\n fill: #f5f5f5 !important;\n stroke: ${t.lineColor} !important;\n stroke-width: 1;\n }\n \n`),"getStyles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7354.36d3c86d.js b/pr-preview/pr-1071/assets/js/7354.36d3c86d.js deleted file mode 100644 index 19f289bebb..0000000000 --- a/pr-preview/pr-1071/assets/js/7354.36d3c86d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7354],{97354:(e,r,t)=>{t.d(r,{diagram:()=>c});var a=t(6144),s=t(77286),n=t(10009),d=t(78731),o={parse:(0,n.K2)((async e=>{const r=await(0,d.qg)("info",e);n.Rm.debug(r)}),"parse")},i={version:a.r},c={parser:o,db:{getVersion:(0,n.K2)((()=>i.version),"getVersion")},renderer:{draw:(0,n.K2)(((e,r,t)=>{n.Rm.debug("rendering info diagram\n"+e);const a=(0,s.D)(r);(0,n.a$)(a,100,400,!0);a.append("g").append("text").attr("x",100).attr("y",40).attr("class","version").attr("font-size",32).style("text-anchor","middle").text(`v${t}`)}),"draw")}}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7357.32327aca.js b/pr-preview/pr-1071/assets/js/7357.32327aca.js deleted file mode 100644 index 01e9494085..0000000000 --- a/pr-preview/pr-1071/assets/js/7357.32327aca.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7357],{63933:(t,e,a)=>{function r(t,e){t.accDescr&&e.setAccDescription?.(t.accDescr),t.accTitle&&e.setAccTitle?.(t.accTitle),t.title&&e.setDiagramTitle?.(t.title)}a.d(e,{S:()=>r}),(0,a(10009).K2)(r,"populateCommonDb")},57357:(t,e,a)=>{a.d(e,{diagram:()=>x});var r=a(63933),n=a(8159),o=a(77286),l=a(10009),c=a(78731),i={packet:[]},s=structuredClone(i),d=l.UI.packet,k=(0,l.K2)((()=>{const t=(0,n.$t)({...d,...(0,l.zj)().packet});return t.showBits&&(t.paddingY+=10),t}),"getConfig"),p=(0,l.K2)((()=>s.packet),"getPacket"),b={pushWord:(0,l.K2)((t=>{t.length>0&&s.packet.push(t)}),"pushWord"),getPacket:p,getConfig:k,clear:(0,l.K2)((()=>{(0,l.IU)(),s=structuredClone(i)}),"clear"),setAccTitle:l.SV,getAccTitle:l.iN,setDiagramTitle:l.ke,getDiagramTitle:l.ab,getAccDescription:l.m7,setAccDescription:l.EI},g=(0,l.K2)((t=>{(0,r.S)(t,b);let e=-1,a=[],n=1;const{bitsPerRow:o}=b.getConfig();for(let{start:r,end:c,label:i}of t.blocks){if(c&&c<r)throw new Error(`Packet block ${r} - ${c} is invalid. End must be greater than start.`);if(r!==e+1)throw new Error(`Packet block ${r} - ${c??r} is not contiguous. It should start from ${e+1}.`);for(e=c??r,l.Rm.debug(`Packet block ${r} - ${e} with label ${i}`);a.length<=o+1&&b.getPacket().length<1e4;){const[t,e]=h({start:r,end:c,label:i},n,o);if(a.push(t),t.end+1===n*o&&(b.pushWord(a),a=[],n++),!e)break;({start:r,end:c,label:i}=e)}}b.pushWord(a)}),"populate"),h=(0,l.K2)(((t,e,a)=>{if(void 0===t.end&&(t.end=t.start),t.start>t.end)throw new Error(`Block start ${t.start} is greater than block end ${t.end}.`);return t.end+1<=e*a?[t,void 0]:[{start:t.start,end:e*a-1,label:t.label},{start:e*a,end:t.end,label:t.label}]}),"getNextFittingBlock"),f={parse:(0,l.K2)((async t=>{const e=await(0,c.qg)("packet",t);l.Rm.debug(e),g(e)}),"parse")},u=(0,l.K2)(((t,e,a,r)=>{const n=r.db,c=n.getConfig(),{rowHeight:i,paddingY:s,bitWidth:d,bitsPerRow:k}=c,p=n.getPacket(),b=n.getDiagramTitle(),g=i+s,h=g*(p.length+1)-(b?0:i),f=d*k+2,u=(0,o.D)(e);u.attr("viewbox",`0 0 ${f} ${h}`),(0,l.a$)(u,h,f,c.useMaxWidth);for(const[o,l]of p.entries())$(u,l,o,c);u.append("text").text(b).attr("x",f/2).attr("y",h-g/2).attr("dominant-baseline","middle").attr("text-anchor","middle").attr("class","packetTitle")}),"draw"),$=(0,l.K2)(((t,e,a,{rowHeight:r,paddingX:n,paddingY:o,bitWidth:l,bitsPerRow:c,showBits:i})=>{const s=t.append("g"),d=a*(r+o)+o;for(const k of e){const t=k.start%c*l+1,e=(k.end-k.start+1)*l-n;if(s.append("rect").attr("x",t).attr("y",d).attr("width",e).attr("height",r).attr("class","packetBlock"),s.append("text").attr("x",t+e/2).attr("y",d+r/2).attr("class","packetLabel").attr("dominant-baseline","middle").attr("text-anchor","middle").text(k.label),!i)continue;const a=k.end===k.start,o=d-2;s.append("text").attr("x",t+(a?e/2:0)).attr("y",o).attr("class","packetByte start").attr("dominant-baseline","auto").attr("text-anchor",a?"middle":"start").text(k.start),a||s.append("text").attr("x",t+e).attr("y",o).attr("class","packetByte end").attr("dominant-baseline","auto").attr("text-anchor","end").text(k.end)}}),"drawWord"),w={byteFontSize:"10px",startByteColor:"black",endByteColor:"black",labelColor:"black",labelFontSize:"12px",titleColor:"black",titleFontSize:"14px",blockStrokeColor:"black",blockStrokeWidth:"1",blockFillColor:"#efefef"},x={parser:f,db:b,renderer:{draw:u},styles:(0,l.K2)((({packet:t}={})=>{const e=(0,n.$t)(w,t);return`\n\t.packetByte {\n\t\tfont-size: ${e.byteFontSize};\n\t}\n\t.packetByte.start {\n\t\tfill: ${e.startByteColor};\n\t}\n\t.packetByte.end {\n\t\tfill: ${e.endByteColor};\n\t}\n\t.packetLabel {\n\t\tfill: ${e.labelColor};\n\t\tfont-size: ${e.labelFontSize};\n\t}\n\t.packetTitle {\n\t\tfill: ${e.titleColor};\n\t\tfont-size: ${e.titleFontSize};\n\t}\n\t.packetBlock {\n\t\tstroke: ${e.blockStrokeColor};\n\t\tstroke-width: ${e.blockStrokeWidth};\n\t\tfill: ${e.blockFillColor};\n\t}\n\t`}),"styles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/75100f0d.03b0b3ff.js b/pr-preview/pr-1071/assets/js/75100f0d.03b0b3ff.js deleted file mode 100644 index 7f386246e9..0000000000 --- a/pr-preview/pr-1071/assets/js/75100f0d.03b0b3ff.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7882],{82094:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>n,toc:()=>u});const n=JSON.parse('{"id":"architecture/index","title":"Architecture","description":"","source":"@site/versioned_docs/version-0.6/architecture/index.md","sourceDirName":"architecture","slug":"/architecture/","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/architecture/index.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation"}}');var c=r(74848),s=r(28453),o=r(44074);const i={},a="Architecture",l={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,s.R)(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(t.header,{children:(0,c.jsx)(t.h1,{id:"architecture",children:"Architecture"})}),"\n","\n",(0,c.jsx)(o.A,{})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(d,{...e})}):d(e)}},44074:(e,t,r)=>{r.d(t,{A:()=>b});var n=r(96540),c=r(34164),s=r(45357),o=r(14783),i=r(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function h(){const e=d();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const c=r.select(t),s=r.pluralForms.indexOf(c);return n[Math.min(s,n.length-1)]}(r,t,e)}}var m=r(40877),p=r(23230),f=r(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=r(74848);function j(e){let{href:t,children:r}=e;return(0,g.jsx)(o.A,{href:t,className:(0,c.A)("card padding--lg",x.cardContainer),children:r})}function v(e){let{href:t,icon:r,title:n,description:s}=e;return(0,g.jsxs)(j,{href:t,children:[(0,g.jsxs)(f.A,{as:"h2",className:(0,c.A)("text--truncate",x.cardTitle),title:n,children:[r," ",n]}),s&&(0,g.jsx)("p",{className:(0,c.A)("text--truncate",x.cardDescription),title:s,children:s})]})}function w(e){let{item:t}=e;const r=(0,s.Nr)(t),n=function(){const{selectMessage:e}=h();return t=>e(t,(0,p.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return r?(0,g.jsx)(v,{href:r,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??n(t.items.length)}):null}function A(e){let{item:t}=e;const r=(0,m.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",n=(0,s.cC)(t.docId??void 0);return(0,g.jsx)(v,{href:t.href,icon:r,title:t.label,description:t.description??n?.description})}function y(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(A,{item:t});case"category":return(0,g.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const r=(0,s.$S)();return(0,g.jsx)(b,{items:r.items,className:t})}function b(e){const{items:t,className:r}=e;if(!t)return(0,g.jsx)(N,{...e});const n=(0,s.d1)(t);return(0,g.jsx)("section",{className:(0,c.A)("row",r),children:n.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(y,{item:e})},t)))})}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>i});var n=r(96540);const c={},s=n.createContext(c);function o(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:o(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/758.b164c2b0.js b/pr-preview/pr-1071/assets/js/758.b164c2b0.js deleted file mode 100644 index 7d2e407c66..0000000000 --- a/pr-preview/pr-1071/assets/js/758.b164c2b0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[758],{96474:(t,e,s)=>{s.d(e,{A:()=>r,P:()=>o});var i=s(10009),n=s(20007),r=(0,i.K2)(((t,e)=>{let s;"sandbox"===e&&(s=(0,n.Ltv)("#i"+t));return("sandbox"===e?(0,n.Ltv)(s.nodes()[0].contentDocument.body):(0,n.Ltv)("body")).select(`[id="${t}"]`)}),"getDiagramElement"),o=(0,i.K2)(((t,e,s,n)=>{t.attr("class",s);const{width:r,height:o,x:l,y:h}=a(t,e);(0,i.a$)(t,o,r,n);const d=c(l,h,r,o,e);t.attr("viewBox",d),i.Rm.debug(`viewBox configured: ${d} with padding: ${e}`)}),"setupViewPortForSVG"),a=(0,i.K2)(((t,e)=>{const s=t.node()?.getBBox()||{width:0,height:0,x:0,y:0};return{width:s.width+2*e,height:s.height+2*e,x:s.x,y:s.y}}),"calculateDimensionsWithPadding"),c=(0,i.K2)(((t,e,s,i,n)=>`${t-n} ${e-n} ${s} ${i}`),"createViewBox")},90758:(t,e,s)=>{s.d(e,{Zk:()=>c,iP:()=>Bt,q7:()=>w,tM:()=>Ft});var i=s(96474),n=s(87308),r=s(8159),o=s(10009),a=function(){var t=(0,o.K2)((function(t,e,s,i){for(s=s||{},i=t.length;i--;s[t[i]]=e);return s}),"o"),e=[1,2],s=[1,3],i=[1,4],n=[2,4],r=[1,9],a=[1,11],c=[1,16],l=[1,17],h=[1,18],d=[1,19],u=[1,32],p=[1,20],y=[1,21],g=[1,22],f=[1,23],m=[1,24],S=[1,26],_=[1,27],b=[1,28],T=[1,29],k=[1,30],E=[1,31],x=[1,34],D=[1,35],C=[1,36],$=[1,37],v=[1,33],L=[1,4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],I=[1,4,5,14,15,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],A=[4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],K={trace:(0,o.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,SD:6,document:7,line:8,statement:9,classDefStatement:10,styleStatement:11,cssClassStatement:12,idStatement:13,DESCR:14,"--\x3e":15,HIDE_EMPTY:16,scale:17,WIDTH:18,COMPOSIT_STATE:19,STRUCT_START:20,STRUCT_STOP:21,STATE_DESCR:22,AS:23,ID:24,FORK:25,JOIN:26,CHOICE:27,CONCURRENT:28,note:29,notePosition:30,NOTE_TEXT:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,classDef:38,CLASSDEF_ID:39,CLASSDEF_STYLEOPTS:40,DEFAULT:41,style:42,STYLE_IDS:43,STYLEDEF_STYLEOPTS:44,class:45,CLASSENTITY_IDS:46,STYLECLASS:47,direction_tb:48,direction_bt:49,direction_rl:50,direction_lr:51,eol:52,";":53,EDGE_STATE:54,STYLE_SEPARATOR:55,left_of:56,right_of:57,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",6:"SD",14:"DESCR",15:"--\x3e",16:"HIDE_EMPTY",17:"scale",18:"WIDTH",19:"COMPOSIT_STATE",20:"STRUCT_START",21:"STRUCT_STOP",22:"STATE_DESCR",23:"AS",24:"ID",25:"FORK",26:"JOIN",27:"CHOICE",28:"CONCURRENT",29:"note",31:"NOTE_TEXT",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",38:"classDef",39:"CLASSDEF_ID",40:"CLASSDEF_STYLEOPTS",41:"DEFAULT",42:"style",43:"STYLE_IDS",44:"STYLEDEF_STYLEOPTS",45:"class",46:"CLASSENTITY_IDS",47:"STYLECLASS",48:"direction_tb",49:"direction_bt",50:"direction_rl",51:"direction_lr",53:";",54:"EDGE_STATE",55:"STYLE_SEPARATOR",56:"left_of",57:"right_of"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,3],[9,4],[9,1],[9,2],[9,1],[9,4],[9,3],[9,6],[9,1],[9,1],[9,1],[9,1],[9,4],[9,4],[9,1],[9,2],[9,2],[9,1],[10,3],[10,3],[11,3],[12,3],[32,1],[32,1],[32,1],[32,1],[52,1],[52,1],[13,1],[13,1],[13,3],[13,3],[30,1],[30,1]],performAction:(0,o.K2)((function(t,e,s,i,n,r,o){var a=r.length-1;switch(n){case 3:return i.setRootDoc(r[a]),r[a];case 4:this.$=[];break;case 5:"nl"!=r[a]&&(r[a-1].push(r[a]),this.$=r[a-1]);break;case 6:case 7:case 12:this.$=r[a];break;case 8:this.$="nl";break;case 13:const t=r[a-1];t.description=i.trimColon(r[a]),this.$=t;break;case 14:this.$={stmt:"relation",state1:r[a-2],state2:r[a]};break;case 15:const e=i.trimColon(r[a]);this.$={stmt:"relation",state1:r[a-3],state2:r[a-1],description:e};break;case 19:this.$={stmt:"state",id:r[a-3],type:"default",description:"",doc:r[a-1]};break;case 20:var c=r[a],l=r[a-2].trim();if(r[a].match(":")){var h=r[a].split(":");c=h[0],l=[l,h[1]]}this.$={stmt:"state",id:c,type:"default",description:l};break;case 21:this.$={stmt:"state",id:r[a-3],type:"default",description:r[a-5],doc:r[a-1]};break;case 22:this.$={stmt:"state",id:r[a],type:"fork"};break;case 23:this.$={stmt:"state",id:r[a],type:"join"};break;case 24:this.$={stmt:"state",id:r[a],type:"choice"};break;case 25:this.$={stmt:"state",id:i.getDividerId(),type:"divider"};break;case 26:this.$={stmt:"state",id:r[a-1].trim(),note:{position:r[a-2].trim(),text:r[a].trim()}};break;case 29:this.$=r[a].trim(),i.setAccTitle(this.$);break;case 30:case 31:this.$=r[a].trim(),i.setAccDescription(this.$);break;case 32:case 33:this.$={stmt:"classDef",id:r[a-1].trim(),classes:r[a].trim()};break;case 34:this.$={stmt:"style",id:r[a-1].trim(),styleClass:r[a].trim()};break;case 35:this.$={stmt:"applyClass",id:r[a-1].trim(),styleClass:r[a].trim()};break;case 36:i.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 37:i.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 38:i.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 39:i.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 42:case 43:this.$={stmt:"state",id:r[a].trim(),type:"default",description:""};break;case 44:case 45:this.$={stmt:"state",id:r[a-2].trim(),classes:[r[a].trim()],type:"default",description:""}}}),"anonymous"),table:[{3:1,4:e,5:s,6:i},{1:[3]},{3:5,4:e,5:s,6:i},{3:6,4:e,5:s,6:i},t([1,4,5,16,17,19,22,24,25,26,27,28,29,33,35,37,38,42,45,48,49,50,51,54],n,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:r,5:a,8:8,9:10,10:12,11:13,12:14,13:15,16:c,17:l,19:h,22:d,24:u,25:p,26:y,27:g,28:f,29:m,32:25,33:S,35:_,37:b,38:T,42:k,45:E,48:x,49:D,50:C,51:$,54:v},t(L,[2,5]),{9:38,10:12,11:13,12:14,13:15,16:c,17:l,19:h,22:d,24:u,25:p,26:y,27:g,28:f,29:m,32:25,33:S,35:_,37:b,38:T,42:k,45:E,48:x,49:D,50:C,51:$,54:v},t(L,[2,7]),t(L,[2,8]),t(L,[2,9]),t(L,[2,10]),t(L,[2,11]),t(L,[2,12],{14:[1,39],15:[1,40]}),t(L,[2,16]),{18:[1,41]},t(L,[2,18],{20:[1,42]}),{23:[1,43]},t(L,[2,22]),t(L,[2,23]),t(L,[2,24]),t(L,[2,25]),{30:44,31:[1,45],56:[1,46],57:[1,47]},t(L,[2,28]),{34:[1,48]},{36:[1,49]},t(L,[2,31]),{39:[1,50],41:[1,51]},{43:[1,52]},{46:[1,53]},t(I,[2,42],{55:[1,54]}),t(I,[2,43],{55:[1,55]}),t(L,[2,36]),t(L,[2,37]),t(L,[2,38]),t(L,[2,39]),t(L,[2,6]),t(L,[2,13]),{13:56,24:u,54:v},t(L,[2,17]),t(A,n,{7:57}),{24:[1,58]},{24:[1,59]},{23:[1,60]},{24:[2,46]},{24:[2,47]},t(L,[2,29]),t(L,[2,30]),{40:[1,61]},{40:[1,62]},{44:[1,63]},{47:[1,64]},{24:[1,65]},{24:[1,66]},t(L,[2,14],{14:[1,67]}),{4:r,5:a,8:8,9:10,10:12,11:13,12:14,13:15,16:c,17:l,19:h,21:[1,68],22:d,24:u,25:p,26:y,27:g,28:f,29:m,32:25,33:S,35:_,37:b,38:T,42:k,45:E,48:x,49:D,50:C,51:$,54:v},t(L,[2,20],{20:[1,69]}),{31:[1,70]},{24:[1,71]},t(L,[2,32]),t(L,[2,33]),t(L,[2,34]),t(L,[2,35]),t(I,[2,44]),t(I,[2,45]),t(L,[2,15]),t(L,[2,19]),t(A,n,{7:72}),t(L,[2,26]),t(L,[2,27]),{4:r,5:a,8:8,9:10,10:12,11:13,12:14,13:15,16:c,17:l,19:h,21:[1,73],22:d,24:u,25:p,26:y,27:g,28:f,29:m,32:25,33:S,35:_,37:b,38:T,42:k,45:E,48:x,49:D,50:C,51:$,54:v},t(L,[2,21])],defaultActions:{5:[2,1],6:[2,2],46:[2,46],47:[2,47]},parseError:(0,o.K2)((function(t,e){if(!e.recoverable){var s=new Error(t);throw s.hash=e,s}this.trace(t)}),"parseError"),parse:(0,o.K2)((function(t){var e=this,s=[0],i=[],n=[null],r=[],a=this.table,c="",l=0,h=0,d=0,u=r.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var f=p.yylloc;r.push(f);var m=p.options&&p.options.ranges;function S(){var t;return"number"!=typeof(t=i.pop()||p.lex()||1)&&(t instanceof Array&&(t=(i=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,o.K2)((function(t){s.length=s.length-2*t,n.length=n.length-t,r.length=r.length-t}),"popStack"),(0,o.K2)(S,"lex");for(var _,b,T,k,E,x,D,C,$,v={};;){if(T=s[s.length-1],this.defaultActions[T]?k=this.defaultActions[T]:(null==_&&(_=S()),k=a[T]&&a[T][_]),void 0===k||!k.length||!k[0]){var L="";for(x in $=[],a[T])this.terminals_[x]&&x>2&&$.push("'"+this.terminals_[x]+"'");L=p.showPosition?"Parse error on line "+(l+1)+":\n"+p.showPosition()+"\nExpecting "+$.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==_?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(L,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:f,expected:$})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+T+", token: "+_);switch(k[0]){case 1:s.push(_),n.push(p.yytext),r.push(p.yylloc),s.push(k[1]),_=null,b?(_=b,b=null):(h=p.yyleng,c=p.yytext,l=p.yylineno,f=p.yylloc,d>0&&d--);break;case 2:if(D=this.productions_[k[1]][1],v.$=n[n.length-D],v._$={first_line:r[r.length-(D||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(D||1)].first_column,last_column:r[r.length-1].last_column},m&&(v._$.range=[r[r.length-(D||1)].range[0],r[r.length-1].range[1]]),void 0!==(E=this.performAction.apply(v,[c,h,l,y.yy,k[1],n,r].concat(u))))return E;D&&(s=s.slice(0,-1*D*2),n=n.slice(0,-1*D),r=r.slice(0,-1*D)),s.push(this.productions_[k[1]][0]),n.push(v.$),r.push(v._$),C=a[s[s.length-2]][s[s.length-1]],s.push(C);break;case 3:return!0}}return!0}),"parse")},R=function(){return{EOF:1,parseError:(0,o.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,o.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,o.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,o.K2)((function(t){var e=t.length,s=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var i=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),s.length-1&&(this.yylineno-=s.length-1);var n=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:s?(s.length===i.length?this.yylloc.first_column:0)+i[i.length-s.length].length-s[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[n[0],n[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,o.K2)((function(){return this._more=!0,this}),"more"),reject:(0,o.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,o.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,o.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,o.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,o.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,o.K2)((function(t,e){var s,i,n;if(this.options.backtrack_lexer&&(n={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(n.yylloc.range=this.yylloc.range.slice(0))),(i=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],s=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),s)return s;if(this._backtrack){for(var r in n)this[r]=n[r];return!1}return!1}),"test_match"),next:(0,o.K2)((function(){if(this.done)return this.EOF;var t,e,s,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var n=this._currentRules(),r=0;r<n.length;r++)if((s=this._input.match(this.rules[n[r]]))&&(!e||s[0].length>e[0].length)){if(e=s,i=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(s,n[r])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,n[i]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,o.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,o.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,o.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,o.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,o.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,o.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,o.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,o.K2)((function(t,e,s,i){switch(s){case 0:return 41;case 1:case 42:return 48;case 2:case 43:return 49;case 3:case 44:return 50;case 4:case 45:return 51;case 5:case 6:case 8:case 9:case 10:case 11:case 54:case 56:case 62:break;case 7:case 77:return 5;case 12:case 32:return this.pushState("SCALE"),17;case 13:case 33:return 18;case 14:case 20:case 34:case 49:case 52:this.popState();break;case 15:return this.begin("acc_title"),33;case 16:return this.popState(),"acc_title_value";case 17:return this.begin("acc_descr"),35;case 18:return this.popState(),"acc_descr_value";case 19:this.begin("acc_descr_multiline");break;case 21:return"acc_descr_multiline_value";case 22:return this.pushState("CLASSDEF"),38;case 23:return this.popState(),this.pushState("CLASSDEFID"),"DEFAULT_CLASSDEF_ID";case 24:return this.popState(),this.pushState("CLASSDEFID"),39;case 25:return this.popState(),40;case 26:return this.pushState("CLASS"),45;case 27:return this.popState(),this.pushState("CLASS_STYLE"),46;case 28:return this.popState(),47;case 29:return this.pushState("STYLE"),42;case 30:return this.popState(),this.pushState("STYLEDEF_STYLES"),43;case 31:return this.popState(),44;case 35:this.pushState("STATE");break;case 36:case 39:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),25;case 37:case 40:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),26;case 38:case 41:return this.popState(),e.yytext=e.yytext.slice(0,-10).trim(),27;case 46:this.pushState("STATE_STRING");break;case 47:return this.pushState("STATE_ID"),"AS";case 48:case 64:return this.popState(),"ID";case 50:return"STATE_DESCR";case 51:return 19;case 53:return this.popState(),this.pushState("struct"),20;case 55:return this.popState(),21;case 57:return this.begin("NOTE"),29;case 58:return this.popState(),this.pushState("NOTE_ID"),56;case 59:return this.popState(),this.pushState("NOTE_ID"),57;case 60:this.popState(),this.pushState("FLOATING_NOTE");break;case 61:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";case 63:return"NOTE_TEXT";case 65:return this.popState(),this.pushState("NOTE_TEXT"),24;case 66:return this.popState(),e.yytext=e.yytext.substr(2).trim(),31;case 67:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),31;case 68:case 69:return 6;case 70:return 16;case 71:return 54;case 72:return 24;case 73:return e.yytext=e.yytext.trim(),14;case 74:return 15;case 75:return 28;case 76:return 55;case 78:return"INVALID"}}),"anonymous"),rules:[/^(?:default\b)/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:classDef\s+)/i,/^(?:DEFAULT\s+)/i,/^(?:\w+\s+)/i,/^(?:[^\n]*)/i,/^(?:class\s+)/i,/^(?:(\w+)+((,\s*\w+)*))/i,/^(?:[^\n]*)/i,/^(?:style\s+)/i,/^(?:[\w,]+\s+)/i,/^(?:[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:state\s+)/i,/^(?:.*<<fork>>)/i,/^(?:.*<<join>>)/i,/^(?:.*<<choice>>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:.*\[\[choice\]\])/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:["])/i,/^(?:\s*as\s+)/i,/^(?:[^\n\{]*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n\s\{]+)/i,/^(?:\n)/i,/^(?:\{)/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:\})/i,/^(?:[\n])/i,/^(?:note\s+)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:")/i,/^(?:\s*as\s*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n]*)/i,/^(?:\s*[^:\n\s\-]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:[\s\S]*?end note\b)/i,/^(?:stateDiagram\s+)/i,/^(?:stateDiagram-v2\s+)/i,/^(?:hide empty description\b)/i,/^(?:\[\*\])/i,/^(?:[^:\n\s\-\{]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:-->)/i,/^(?:--)/i,/^(?::::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{LINE:{rules:[9,10],inclusive:!1},struct:{rules:[9,10,22,26,29,35,42,43,44,45,54,55,56,57,71,72,73,74,75],inclusive:!1},FLOATING_NOTE_ID:{rules:[64],inclusive:!1},FLOATING_NOTE:{rules:[61,62,63],inclusive:!1},NOTE_TEXT:{rules:[66,67],inclusive:!1},NOTE_ID:{rules:[65],inclusive:!1},NOTE:{rules:[58,59,60],inclusive:!1},STYLEDEF_STYLEOPTS:{rules:[],inclusive:!1},STYLEDEF_STYLES:{rules:[31],inclusive:!1},STYLE_IDS:{rules:[],inclusive:!1},STYLE:{rules:[30],inclusive:!1},CLASS_STYLE:{rules:[28],inclusive:!1},CLASS:{rules:[27],inclusive:!1},CLASSDEFID:{rules:[25],inclusive:!1},CLASSDEF:{rules:[23,24],inclusive:!1},acc_descr_multiline:{rules:[20,21],inclusive:!1},acc_descr:{rules:[18],inclusive:!1},acc_title:{rules:[16],inclusive:!1},SCALE:{rules:[13,14,33,34],inclusive:!1},ALIAS:{rules:[],inclusive:!1},STATE_ID:{rules:[48],inclusive:!1},STATE_STRING:{rules:[49,50],inclusive:!1},FORK_STATE:{rules:[],inclusive:!1},STATE:{rules:[9,10,36,37,38,39,40,41,46,47,51,52,53],inclusive:!1},ID:{rules:[9,10],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,10,11,12,15,17,19,22,26,29,32,35,53,57,68,69,70,71,72,73,74,76,77,78],inclusive:!0}}}}();function w(){this.yy={}}return K.lexer=R,(0,o.K2)(w,"Parser"),w.prototype=K,K.Parser=w,new w}();a.parser=a;var c=a,l="state",h="relation",d="default",u="divider",p="fill:none",y="fill: #333",g="text",f="normal",m="rect",S="rectWithTitle",_="divider",b="roundedWithTitle",T="statediagram",k=`${T}-state`,E="transition",x=`${E} note-edge`,D=`${T}-note`,C=`${T}-cluster`,$=`${T}-cluster-alt`,v="parent",L="note",I="----",A=`${I}${L}`,K=`${I}${v}`,R=(0,o.K2)(((t,e="TB")=>{if(!t.doc)return e;let s=e;for(const i of t.doc)"dir"===i.stmt&&(s=i.value);return s}),"getDir"),w={getClasses:(0,o.K2)((function(t,e){return e.db.extract(e.db.getRootDocV2()),e.db.getClasses()}),"getClasses"),draw:(0,o.K2)((async function(t,e,s,a){o.Rm.info("REF0:"),o.Rm.info("Drawing state diagram (v2)",e);const{securityLevel:c,state:l,layout:h}=(0,o.D7)();a.db.extract(a.db.getRootDocV2());const d=a.db.getData(),u=(0,i.A)(e,c);d.type=a.type,d.layoutAlgorithm=h,d.nodeSpacing=l?.nodeSpacing||50,d.rankSpacing=l?.rankSpacing||50,d.markers=["barb"],d.diagramId=e,await(0,n.XX)(d,u);r._K.insertTitle(u,"statediagramTitleText",l?.titleTopMargin??25,a.db.getDiagramTitle()),(0,i.P)(u,8,T,l?.useMaxWidth??!0)}),"draw"),getDir:R},O=new Map,N=0;function B(t="",e=0,s="",i=I){return`state-${t}${null!==s&&s.length>0?`${i}${s}`:""}-${e}`}(0,o.K2)(B,"stateDomId");var F=(0,o.K2)(((t,e,s,i,n,r,a,c)=>{o.Rm.trace("items",e),e.forEach((e=>{switch(e.stmt){case l:case d:z(t,e,s,i,n,r,a,c);break;case h:{z(t,e.state1,s,i,n,r,a,c),z(t,e.state2,s,i,n,r,a,c);const l={id:"edge"+N,start:e.state1.id,end:e.state2.id,arrowhead:"normal",arrowTypeEnd:"arrow_barb",style:p,labelStyle:"",label:o.Y2.sanitizeText(e.description,(0,o.D7)()),arrowheadStyle:y,labelpos:"c",labelType:g,thickness:f,classes:E,look:a};n.push(l),N++}}}))}),"setupDoc"),P=(0,o.K2)(((t,e="TB")=>{let s=e;if(t.doc)for(const i of t.doc)"dir"===i.stmt&&(s=i.value);return s}),"getDir");function Y(t,e,s){if(!e.id||"</join></fork>"===e.id||"</choice>"===e.id)return;e.cssClasses&&(Array.isArray(e.cssCompiledStyles)||(e.cssCompiledStyles=[]),e.cssClasses.split(" ").forEach((t=>{if(s.get(t)){const i=s.get(t);e.cssCompiledStyles=[...e.cssCompiledStyles,...i.styles]}})));const i=t.find((t=>t.id===e.id));i?Object.assign(i,e):t.push(e)}function G(t){return t?.classes?.join(" ")??""}function j(t){return t?.styles??[]}(0,o.K2)(Y,"insertOrUpdateNode"),(0,o.K2)(G,"getClassesFromDbInfo"),(0,o.K2)(j,"getStylesFromDbInfo");var z=(0,o.K2)(((t,e,s,i,n,r,a,c)=>{const l=e.id,h=s.get(l),T=G(h),E=j(h);if(o.Rm.info("dataFetcher parsedItem",e,h,E),"root"!==l){let s=m;!0===e.start?s="stateStart":!1===e.start&&(s="stateEnd"),e.type!==d&&(s=e.type),O.get(l)||O.set(l,{id:l,shape:s,description:o.Y2.sanitizeText(l,(0,o.D7)()),cssClasses:`${T} ${k}`,cssStyles:E});const h=O.get(l);e.description&&(Array.isArray(h.description)?(h.shape=S,h.description.push(e.description)):h.description?.length>0?(h.shape=S,h.description===l?h.description=[e.description]:h.description=[h.description,e.description]):(h.shape=m,h.description=e.description),h.description=o.Y2.sanitizeTextOrArray(h.description,(0,o.D7)())),1===h.description?.length&&h.shape===S&&("group"===h.type?h.shape=b:h.shape=m),!h.type&&e.doc&&(o.Rm.info("Setting cluster for XCX",l,P(e)),h.type="group",h.isGroup=!0,h.dir=P(e),h.shape=e.type===u?_:b,h.cssClasses=`${h.cssClasses} ${C} ${r?$:""}`);const I={labelStyle:"",shape:h.shape,label:h.description,cssClasses:h.cssClasses,cssCompiledStyles:[],cssStyles:h.cssStyles,id:l,dir:h.dir,domId:B(l,N),type:h.type,isGroup:"group"===h.type,padding:8,rx:10,ry:10,look:a};if(I.shape===_&&(I.label=""),t&&"root"!==t.id&&(o.Rm.trace("Setting node ",l," to be child of its parent ",t.id),I.parentId=t.id),I.centerLabel=!0,e.note){const t={labelStyle:"",shape:"note",label:e.note.text,cssClasses:D,cssStyles:[],cssCompilesStyles:[],id:l+A+"-"+N,domId:B(l,N,L),type:h.type,isGroup:"group"===h.type,padding:(0,o.D7)().flowchart.padding,look:a,position:e.note.position},s=l+K,r={labelStyle:"",shape:"noteGroup",label:e.note.text,cssClasses:h.cssClasses,cssStyles:[],id:l+K,domId:B(l,N,v),type:"group",isGroup:!0,padding:16,look:a,position:e.note.position};N++,r.id=s,t.parentId=s,Y(i,r,c),Y(i,t,c),Y(i,I,c);let d=l,u=t.id;"left of"===e.note.position&&(d=t.id,u=l),n.push({id:d+"-"+u,start:d,end:u,arrowhead:"none",arrowTypeEnd:"",style:p,labelStyle:"",classes:x,arrowheadStyle:y,labelpos:"c",labelType:g,thickness:f,look:a})}else Y(i,I,c)}e.doc&&(o.Rm.trace("Adding nodes children "),F(e,e.doc,s,i,n,!r,a,c))}),"dataFetcher"),U=(0,o.K2)((()=>{O.clear(),N=0}),"reset"),M="[*]",X="start",V=M,W="color",H="fill";function J(){return new Map}(0,o.K2)(J,"newClassesList");var q=[],Z=[],Q="LR",tt=[],et=J(),st=(0,o.K2)((()=>({relations:[],states:new Map,documents:{}})),"newDoc"),it={root:st()},nt=it.root,rt=0,ot=0,at=(0,o.K2)((t=>JSON.parse(JSON.stringify(t))),"clone"),ct=(0,o.K2)((t=>{o.Rm.info("Setting root doc",t),tt=t}),"setRootDoc"),lt=(0,o.K2)((()=>tt),"getRootDoc"),ht=(0,o.K2)(((t,e,s)=>{if(e.stmt===h)ht(t,e.state1,!0),ht(t,e.state2,!1);else if(e.stmt===l&&("[*]"===e.id?(e.id=s?t.id+"_start":t.id+"_end",e.start=s):e.id=e.id.trim()),e.doc){const t=[];let s,i=[];for(s=0;s<e.doc.length;s++)if(e.doc[s].type===u){const n=at(e.doc[s]);n.doc=at(i),t.push(n),i=[]}else i.push(e.doc[s]);if(t.length>0&&i.length>0){const s={stmt:l,id:(0,r.$C)(),type:"divider",doc:at(i)};t.push(at(s)),e.doc=t}e.doc.forEach((t=>ht(e,t,!0)))}}),"docTranslator"),dt=(0,o.K2)((()=>(ht({id:"root"},{id:"root",doc:tt},!0),{id:"root",doc:tt})),"getRootDocV2"),ut=(0,o.K2)((t=>{let e;e=t.doc?t.doc:t,o.Rm.info(e),yt(!0),o.Rm.info("Extract initial document:",e),e.forEach((t=>{switch(o.Rm.warn("Statement",t.stmt),t.stmt){case l:pt(t.id.trim(),t.type,t.doc,t.description,t.note,t.classes,t.styles,t.textStyles);break;case h:xt(t.state1,t.state2,t.description);break;case"classDef":vt(t.id.trim(),t.classes);break;case"style":{const e=t.id.trim().split(","),s=t.styleClass.split(",");e.forEach((t=>{let e=gt(t);if(void 0===e){const s=t.trim();pt(s),e=gt(s)}e.styles=s.map((t=>t.replace(/;/g,"")?.trim()))}))}break;case"applyClass":It(t.id.trim(),t.styleClass)}}));const s=ft(),i=(0,o.D7)().look;U(),z(void 0,dt(),s,q,Z,!0,i,et),q.forEach((t=>{if(Array.isArray(t.label)){if(t.description=t.label.slice(1),t.isGroup&&t.description.length>0)throw new Error("Group nodes can only have label. Remove the additional description for node ["+t.id+"]");t.label=t.label[0]}}))}),"extract"),pt=(0,o.K2)((function(t,e=d,s=null,i=null,n=null,r=null,a=null,c=null){const l=t?.trim();if(nt.states.has(l)?(nt.states.get(l).doc||(nt.states.get(l).doc=s),nt.states.get(l).type||(nt.states.get(l).type=e)):(o.Rm.info("Adding state ",l,i),nt.states.set(l,{id:l,descriptions:[],type:e,doc:s,note:n,classes:[],styles:[],textStyles:[]})),i&&(o.Rm.info("Setting state description",l,i),"string"==typeof i&&Dt(l,i.trim()),"object"==typeof i&&i.forEach((t=>Dt(l,t.trim())))),n){const t=nt.states.get(l);t.note=n,t.note.text=o.Y2.sanitizeText(t.note.text,(0,o.D7)())}if(r){o.Rm.info("Setting state classes",l,r);("string"==typeof r?[r]:r).forEach((t=>It(l,t.trim())))}if(a){o.Rm.info("Setting state styles",l,a);("string"==typeof a?[a]:a).forEach((t=>At(l,t.trim())))}if(c){o.Rm.info("Setting state styles",l,a);("string"==typeof c?[c]:c).forEach((t=>Kt(l,t.trim())))}}),"addState"),yt=(0,o.K2)((function(t){q=[],Z=[],it={root:st()},nt=it.root,rt=0,et=J(),t||(0,o.IU)()}),"clear"),gt=(0,o.K2)((function(t){return nt.states.get(t)}),"getState"),ft=(0,o.K2)((function(){return nt.states}),"getStates"),mt=(0,o.K2)((function(){o.Rm.info("Documents = ",it)}),"logDocuments"),St=(0,o.K2)((function(){return nt.relations}),"getRelations");function _t(t=""){let e=t;return t===M&&(rt++,e=`${X}${rt}`),e}function bt(t="",e=d){return t===M?X:e}function Tt(t=""){let e=t;return t===V&&(e=`end${++rt}`),e}function kt(t="",e=d){return t===V?"end":e}function Et(t,e,s){let i=_t(t.id.trim()),n=bt(t.id.trim(),t.type),r=_t(e.id.trim()),a=bt(e.id.trim(),e.type);pt(i,n,t.doc,t.description,t.note,t.classes,t.styles,t.textStyles),pt(r,a,e.doc,e.description,e.note,e.classes,e.styles,e.textStyles),nt.relations.push({id1:i,id2:r,relationTitle:o.Y2.sanitizeText(s,(0,o.D7)())})}(0,o.K2)(_t,"startIdIfNeeded"),(0,o.K2)(bt,"startTypeIfNeeded"),(0,o.K2)(Tt,"endIdIfNeeded"),(0,o.K2)(kt,"endTypeIfNeeded"),(0,o.K2)(Et,"addRelationObjs");var xt=(0,o.K2)((function(t,e,s){if("object"==typeof t)Et(t,e,s);else{const i=_t(t.trim()),n=bt(t),r=Tt(e.trim()),a=kt(e);pt(i,n),pt(r,a),nt.relations.push({id1:i,id2:r,title:o.Y2.sanitizeText(s,(0,o.D7)())})}}),"addRelation"),Dt=(0,o.K2)((function(t,e){const s=nt.states.get(t),i=e.startsWith(":")?e.replace(":","").trim():e;s.descriptions.push(o.Y2.sanitizeText(i,(0,o.D7)()))}),"addDescription"),Ct=(0,o.K2)((function(t){return":"===t.substring(0,1)?t.substr(2).trim():t.trim()}),"cleanupLabel"),$t=(0,o.K2)((()=>"divider-id-"+ ++ot),"getDividerId"),vt=(0,o.K2)((function(t,e=""){et.has(t)||et.set(t,{id:t,styles:[],textStyles:[]});const s=et.get(t);null!=e&&e.split(",").forEach((t=>{const e=t.replace(/([^;]*);/,"$1").trim();if(RegExp(W).exec(t)){const t=e.replace(H,"bgFill").replace(W,H);s.textStyles.push(t)}s.styles.push(e)}))}),"addStyleClass"),Lt=(0,o.K2)((function(){return et}),"getClasses"),It=(0,o.K2)((function(t,e){t.split(",").forEach((function(t){let s=gt(t);if(void 0===s){const e=t.trim();pt(e),s=gt(e)}s.classes.push(e)}))}),"setCssClass"),At=(0,o.K2)((function(t,e){const s=gt(t);void 0!==s&&s.styles.push(e)}),"setStyle"),Kt=(0,o.K2)((function(t,e){const s=gt(t);void 0!==s&&s.textStyles.push(e)}),"setTextStyle"),Rt=(0,o.K2)((()=>Q),"getDirection"),wt=(0,o.K2)((t=>{Q=t}),"setDirection"),Ot=(0,o.K2)((t=>t&&":"===t[0]?t.substr(1).trim():t.trim()),"trimColon"),Nt=(0,o.K2)((()=>{const t=(0,o.D7)();return{nodes:q,edges:Z,other:{},config:t,direction:R(dt())}}),"getData"),Bt={getConfig:(0,o.K2)((()=>(0,o.D7)().state),"getConfig"),getData:Nt,addState:pt,clear:yt,getState:gt,getStates:ft,getRelations:St,getClasses:Lt,getDirection:Rt,addRelation:xt,getDividerId:$t,setDirection:wt,cleanupLabel:Ct,lineType:{LINE:0,DOTTED_LINE:1},relationType:{AGGREGATION:0,EXTENSION:1,COMPOSITION:2,DEPENDENCY:3},logDocuments:mt,getRootDoc:lt,setRootDoc:ct,getRootDocV2:dt,extract:ut,trimColon:Ot,getAccTitle:o.iN,setAccTitle:o.SV,getAccDescription:o.m7,setAccDescription:o.EI,addStyleClass:vt,setCssClass:It,addDescription:Dt,setDiagramTitle:o.ke,getDiagramTitle:o.ab},Ft=(0,o.K2)((t=>`\ndefs #statediagram-barbEnd {\n fill: ${t.transitionColor};\n stroke: ${t.transitionColor};\n }\ng.stateGroup text {\n fill: ${t.nodeBorder};\n stroke: none;\n font-size: 10px;\n}\ng.stateGroup text {\n fill: ${t.textColor};\n stroke: none;\n font-size: 10px;\n\n}\ng.stateGroup .state-title {\n font-weight: bolder;\n fill: ${t.stateLabelColor};\n}\n\ng.stateGroup rect {\n fill: ${t.mainBkg};\n stroke: ${t.nodeBorder};\n}\n\ng.stateGroup line {\n stroke: ${t.lineColor};\n stroke-width: 1;\n}\n\n.transition {\n stroke: ${t.transitionColor};\n stroke-width: 1;\n fill: none;\n}\n\n.stateGroup .composit {\n fill: ${t.background};\n border-bottom: 1px\n}\n\n.stateGroup .alt-composit {\n fill: #e0e0e0;\n border-bottom: 1px\n}\n\n.state-note {\n stroke: ${t.noteBorderColor};\n fill: ${t.noteBkgColor};\n\n text {\n fill: ${t.noteTextColor};\n stroke: none;\n font-size: 10px;\n }\n}\n\n.stateLabel .box {\n stroke: none;\n stroke-width: 0;\n fill: ${t.mainBkg};\n opacity: 0.5;\n}\n\n.edgeLabel .label rect {\n fill: ${t.labelBackgroundColor};\n opacity: 0.5;\n}\n.edgeLabel {\n background-color: ${t.edgeLabelBackground};\n p {\n background-color: ${t.edgeLabelBackground};\n }\n rect {\n opacity: 0.5;\n background-color: ${t.edgeLabelBackground};\n fill: ${t.edgeLabelBackground};\n }\n text-align: center;\n}\n.edgeLabel .label text {\n fill: ${t.transitionLabelColor||t.tertiaryTextColor};\n}\n.label div .edgeLabel {\n color: ${t.transitionLabelColor||t.tertiaryTextColor};\n}\n\n.stateLabel text {\n fill: ${t.stateLabelColor};\n font-size: 10px;\n font-weight: bold;\n}\n\n.node circle.state-start {\n fill: ${t.specialStateColor};\n stroke: ${t.specialStateColor};\n}\n\n.node .fork-join {\n fill: ${t.specialStateColor};\n stroke: ${t.specialStateColor};\n}\n\n.node circle.state-end {\n fill: ${t.innerEndBackground};\n stroke: ${t.background};\n stroke-width: 1.5\n}\n.end-state-inner {\n fill: ${t.compositeBackground||t.background};\n // stroke: ${t.background};\n stroke-width: 1.5\n}\n\n.node rect {\n fill: ${t.stateBkg||t.mainBkg};\n stroke: ${t.stateBorder||t.nodeBorder};\n stroke-width: 1px;\n}\n.node polygon {\n fill: ${t.mainBkg};\n stroke: ${t.stateBorder||t.nodeBorder};;\n stroke-width: 1px;\n}\n#statediagram-barbEnd {\n fill: ${t.lineColor};\n}\n\n.statediagram-cluster rect {\n fill: ${t.compositeTitleBackground};\n stroke: ${t.stateBorder||t.nodeBorder};\n stroke-width: 1px;\n}\n\n.cluster-label, .nodeLabel {\n color: ${t.stateLabelColor};\n // line-height: 1;\n}\n\n.statediagram-cluster rect.outer {\n rx: 5px;\n ry: 5px;\n}\n.statediagram-state .divider {\n stroke: ${t.stateBorder||t.nodeBorder};\n}\n\n.statediagram-state .title-state {\n rx: 5px;\n ry: 5px;\n}\n.statediagram-cluster.statediagram-cluster .inner {\n fill: ${t.compositeBackground||t.background};\n}\n.statediagram-cluster.statediagram-cluster-alt .inner {\n fill: ${t.altBackground?t.altBackground:"#efefef"};\n}\n\n.statediagram-cluster .inner {\n rx:0;\n ry:0;\n}\n\n.statediagram-state rect.basic {\n rx: 5px;\n ry: 5px;\n}\n.statediagram-state rect.divider {\n stroke-dasharray: 10,10;\n fill: ${t.altBackground?t.altBackground:"#efefef"};\n}\n\n.note-edge {\n stroke-dasharray: 5;\n}\n\n.statediagram-note rect {\n fill: ${t.noteBkgColor};\n stroke: ${t.noteBorderColor};\n stroke-width: 1px;\n rx: 0;\n ry: 0;\n}\n.statediagram-note rect {\n fill: ${t.noteBkgColor};\n stroke: ${t.noteBorderColor};\n stroke-width: 1px;\n rx: 0;\n ry: 0;\n}\n\n.statediagram-note text {\n fill: ${t.noteTextColor};\n}\n\n.statediagram-note .nodeLabel {\n color: ${t.noteTextColor};\n}\n.statediagram .edgeLabel {\n color: red; // ${t.noteTextColor};\n}\n\n#dependencyStart, #dependencyEnd {\n fill: ${t.lineColor};\n stroke: ${t.lineColor};\n stroke-width: 1;\n}\n\n.statediagramTitleText {\n text-anchor: middle;\n font-size: 18px;\n fill: ${t.textColor};\n}\n`),"getStyles")}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/75d659e1.d94ce473.js b/pr-preview/pr-1071/assets/js/75d659e1.d94ce473.js deleted file mode 100644 index cf67f65e4b..0000000000 --- a/pr-preview/pr-1071/assets/js/75d659e1.d94ce473.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8597],{5004:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>l});const r=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-0.6/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/0.6/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/deployment.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto"},"next":{"title":"Components","permalink":"/contrast/pr-preview/pr-1071/0.6/components/"}}');var s=t(74848),i=t(28453);const o={},a="Workload deployment",c={},l=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"RuntimeClass and Initializer",id:"runtimeclass-and-initializer",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components},{TabItem:t,Tabs:r}=n;return t||p("TabItem",!0),r||p("Tabs",!0),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,s.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,s.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup",children:"setup guide"})," on how to set it up."]}),"\n",(0,s.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,s.jsxs)(n.p,{children:["Contrast depends on a ",(0,s.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:["custom Kubernetes ",(0,s.jsx)(n.code,{children:"RuntimeClass"})," (",(0,s.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,s.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,s.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime.yml\n"})}),"\n",(0,s.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,s.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml\n"})}),"\n",(0,s.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,s.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,s.jsx)(n.h3,{id:"runtimeclass-and-initializer",children:"RuntimeClass and Initializer"}),"\n",(0,s.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,s.jsxs)(r,{groupId:"yaml-source",children:[(0,s.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,s.jsx)(t,{value:"helm",label:"helm",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,s.jsx)(t,{value:"copy",label:"copy",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,s.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,s.jsx)(n.code,{children:"runtimeClassName"})," when generating policies.\nIn addition, add the Contrast Initializer as ",(0,s.jsx)(n.code,{children:"initContainers"})," to these workloads and configure the\nworkload to use the certificates written to a ",(0,s.jsx)(n.code,{children:"volumeMount"})," named ",(0,s.jsx)(n.code,{children:"tls-certs"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n initContainers:\n - name: initializer\n image: "ghcr.io/edgelesssys/contrast/initializer:latest"\n env:\n - name: COORDINATOR_HOST\n value: coordinator\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n volumes:\n - name: tls-certs\n emptyDir: {}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,s.jsxs)(n.p,{children:["The initializer populates the shared volume with X.509 certificates for your workload.\nThese certificates are used by the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,s.jsxs)(r,{groupId:"tls",children:[(0,s.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,s.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,s.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"The app has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,s.jsx)(n.li,{children:"The app has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,s.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,s.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,s.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,s.jsx)(n.p,{children:"Add the following sidecar definition to your workload:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n initContainers:\n - name: tls-sidecar\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:latest"\n restartPolicy: Always\n env:\n - name: EDG_INGRESS_PROXY_CONFIG\n value: "main#8001#false##metrics#8080#true"\n - name: EDG_EGRESS_PROXY_CONFIG\n value: "backend#127.0.0.2:4001#backend.default:4001"\n volumeMounts:\n - name: tls-certs\n mountPath: /tls-config\n'})}),(0,s.jsxs)(n.p,{children:["The only change required to the app itself is to let it connect to ",(0,s.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,s.jsxs)(t,{value:"go",label:"Go integration",children:[(0,s.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,s.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,s.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,s.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,s.jsxs)(r,{groupId:"golang-tls-setup",children:[(0,s.jsx)(t,{value:"client",label:"Client",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,s.jsx)(t,{value:"server",label:"Server",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,s.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,s.jsxs)(n.p,{children:["Run the ",(0,s.jsx)(n.code,{children:"generate"})," command to generate the execution policies and add them as annotations to your\ndeployment files. A ",(0,s.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"contrast generate resources/\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/known-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,s.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,s.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,s.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,s.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,s.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,s.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,s.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,s.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,s.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,s.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,s.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,s.jsx)(n.p,{children:"After this step, the Coordinator will start issuing TLS certs to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,s.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,s.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,s.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The CLI will attest the Coordinator using embedded reference values. The CLI will write the service mesh\nroot certificate and the history of manifests into the ",(0,s.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies referenced\nin the manifest are also written to the directory."]}),"\n",(0,s.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,s.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,s.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,s.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,s.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,s.jsxs)(n.p,{children:["Using ",(0,s.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,s.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}function p(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var r=t(96540);const s={},i=r.createContext(s);function o(e){const n=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7680d80e.65a732c6.js b/pr-preview/pr-1071/assets/js/7680d80e.65a732c6.js deleted file mode 100644 index 5a24efbb34..0000000000 --- a/pr-preview/pr-1071/assets/js/7680d80e.65a732c6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9025],{88205:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-0.7/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/examples/emojivoto.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Examples","permalink":"/contrast/pr-preview/pr-1071/0.7/examples/"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.7/deployment"}}');var i=n(74848),s=n(28453);const a={},r="Confidential emoji voting",d={},l=[{value:"Motivation",id:"motivation",level:3},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Downloading the deployment",id:"downloading-the-deployment",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Voter's perspective: Verifying the ballot",id:"voters-perspective-verifying-the-ballot",level:2},{value:"Attest the Coordinator",id:"attest-the-coordinator",level:3},{value:"Manifest history and artifact audit",id:"manifest-history-and-artifact-audit",level:3},{value:"Confidential connection to the attested workload",id:"confidential-connection-to-the-attested-workload",level:3},{value:"Certificate SAN and manifest update (optional)",id:"certificate-san-and-manifest-update-optional",level:2},{value:"Configure the service SAN in the manifest",id:"configure-the-service-san-in-the-manifest",level:3},{value:"Update the manifest",id:"update-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(45741).A+"",width:"1503",height:"732"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,i.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voters perspective."]})}),"\n",(0,i.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,i.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,i.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,i.jsx)(t.code,{children:"voting"}),"). The ",(0,i.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,i.jsx)(t.h3,{id:"motivation",children:"Motivation"}),"\n",(0,i.jsx)(t.p,{children:"Using a voting service, users' votes are considered highly sensitive data, as we require\na secret ballot. Also, users are likely interested in the fairness of the ballot. For\nboth requirements, we can use Confidential Computing and, specifically, workload attestation\nto prove to those interested in voting that the app is running in a protected environment\nwhere their votes are processed without leaking to the platform provider or workload owner."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Installed Contrast CLI."}),"\nSee the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/getting-started/install",children:"installation instructions"})," on how to get it."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Running cluster with Confidential Containers support."}),"\nPlease follow the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup",children:"cluster setup instructions"}),"\nto create a cluster."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,i.jsx)(t.h3,{id:"downloading-the-deployment",children:"Downloading the deployment"}),"\n",(0,i.jsx)(t.p,{children:"The emojivoto deployment files are part of a zip file in the Contrast release. You can download the\nlatest deployment by running:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v0.7.3/emojivoto-demo.zip\n"})}),"\n",(0,i.jsxs)(t.p,{children:["After that, unzip the ",(0,i.jsx)(t.code,{children:"emojivoto-demo.zip"})," file to extract the ",(0,i.jsx)(t.code,{children:"deployment/"})," directory."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"unzip emojivoto-demo.zip\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,i.jsxs)(t.p,{children:["Contrast depends on a ",(0,i.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:["custom Kubernetes ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," (",(0,i.jsx)(t.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,i.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/runtime.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/coordinator.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,i.jsxs)(t.p,{children:["Run the ",(0,i.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,i.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"contrast generate deployment/\n"})}),"\n",(0,i.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,i.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,i.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/components/runtime",children:"runtime class"})," ",(0,i.jsx)(t.code,{children:"contrast-cc-<VERSIONHASH>"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,i.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,i.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsx)(t.p,{children:"The CLI will use the embedded reference values to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,i.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,i.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,i.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,i.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,i.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,i.jsx)(t.h2,{id:"voters-perspective-verifying-the-ballot",children:"Voter's perspective: Verifying the ballot"}),"\n",(0,i.jsx)(t.p,{children:"As voters, we want to verify the fairness and confidentiality of the deployment before\ndeciding to vote. Regardless of the scale of our distributed deployment, Contrast only\nneeds a single remote attestation step to verify the deployment. By doing remote attestation\nof the Coordinator, we transitively verify those systems the Coordinator has already attested\nor will attest in the future. Successful verification of the Coordinator means that\nwe can be sure it will enforce the configured manifest."}),"\n",(0,i.jsx)(t.h3,{id:"attest-the-coordinator",children:"Attest the Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"A potential voter can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The CLI will attest the Coordinator using embedded reference values. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,i.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,i.jsx)(t.h3,{id:"manifest-history-and-artifact-audit",children:"Manifest history and artifact audit"}),"\n",(0,i.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,i.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,i.jsx)(t.h3,{id:"confidential-connection-to-the-attested-workload",children:"Confidential connection to the attested workload"}),"\n",(0,i.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, you can securely connect\nto the workloads using the Coordinator's ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,i.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,i.jsx)(t.h2,{id:"certificate-san-and-manifest-update-optional",children:"Certificate SAN and manifest update (optional)"}),"\n",(0,i.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,i.jsx)(t.h3,{id:"configure-the-service-san-in-the-manifest",children:"Configure the service SAN in the manifest"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,i.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,i.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n'})}),"\n",(0,i.jsx)(t.h3,{id:"update-the-manifest",children:"Update the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,i.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,i.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,i.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,i.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},45741:(e,t,n)=>{n.d(t,{A:()=>o});const o=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var o=n(96540);const i={},s=o.createContext(i);function a(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7691.8b446dde.js b/pr-preview/pr-1071/assets/js/7691.8b446dde.js deleted file mode 100644 index d4f1b33fc0..0000000000 --- a/pr-preview/pr-1071/assets/js/7691.8b446dde.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7691],{17691:(t,e,n)=>{n.d(e,{diagram:()=>J});var i=n(10009),s=n(20007),r=n(3219),a=n(78041),o=n(75263),c=function(){var t=(0,i.K2)((function(t,e,n,i){for(n=n||{},i=t.length;i--;n[t[i]]=e);return n}),"o"),e=[6,8,10,11,12,14,16,17,20,21],n=[1,9],s=[1,10],r=[1,11],a=[1,12],o=[1,13],c=[1,16],l=[1,17],h={trace:(0,i.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,timeline:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,period_statement:18,event_statement:19,period:20,event:21,$accept:0,$end:1},terminals_:{2:"error",4:"timeline",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",20:"period",21:"event"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,1],[18,1],[19,1]],performAction:(0,i.K2)((function(t,e,n,i,s,r,a){var o=r.length-1;switch(s){case 1:return r[o-1];case 2:case 6:case 7:this.$=[];break;case 3:r[o-1].push(r[o]),this.$=r[o-1];break;case 4:case 5:this.$=r[o];break;case 8:i.getCommonDb().setDiagramTitle(r[o].substr(6)),this.$=r[o].substr(6);break;case 9:this.$=r[o].trim(),i.getCommonDb().setAccTitle(this.$);break;case 10:case 11:this.$=r[o].trim(),i.getCommonDb().setAccDescription(this.$);break;case 12:i.addSection(r[o].substr(8)),this.$=r[o].substr(8);break;case 15:i.addTask(r[o],0,""),this.$=r[o];break;case 16:i.addEvent(r[o].substr(2)),this.$=r[o]}}),"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:n,12:s,14:r,16:a,17:o,18:14,19:15,20:c,21:l},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:18,11:n,12:s,14:r,16:a,17:o,18:14,19:15,20:c,21:l},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,19]},{15:[1,20]},t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),t(e,[2,4]),t(e,[2,9]),t(e,[2,10])],defaultActions:{},parseError:(0,i.K2)((function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)}),"parseError"),parse:(0,i.K2)((function(t){var e=this,n=[0],s=[],r=[null],a=[],o=this.table,c="",l=0,h=0,d=0,u=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var f=p.yylloc;a.push(f);var m=p.options&&p.options.ranges;function x(){var t;return"number"!=typeof(t=s.pop()||p.lex()||1)&&(t instanceof Array&&(t=(s=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,i.K2)((function(t){n.length=n.length-2*t,r.length=r.length-t,a.length=a.length-t}),"popStack"),(0,i.K2)(x,"lex");for(var b,k,_,w,v,K,S,$,E,T={};;){if(_=n[n.length-1],this.defaultActions[_]?w=this.defaultActions[_]:(null==b&&(b=x()),w=o[_]&&o[_][b]),void 0===w||!w.length||!w[0]){var I="";for(K in E=[],o[_])this.terminals_[K]&&K>2&&E.push("'"+this.terminals_[K]+"'");I=p.showPosition?"Parse error on line "+(l+1)+":\n"+p.showPosition()+"\nExpecting "+E.join(", ")+", got '"+(this.terminals_[b]||b)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==b?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(I,{text:p.match,token:this.terminals_[b]||b,line:p.yylineno,loc:f,expected:E})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+_+", token: "+b);switch(w[0]){case 1:n.push(b),r.push(p.yytext),a.push(p.yylloc),n.push(w[1]),b=null,k?(b=k,k=null):(h=p.yyleng,c=p.yytext,l=p.yylineno,f=p.yylloc,d>0&&d--);break;case 2:if(S=this.productions_[w[1]][1],T.$=r[r.length-S],T._$={first_line:a[a.length-(S||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(S||1)].first_column,last_column:a[a.length-1].last_column},m&&(T._$.range=[a[a.length-(S||1)].range[0],a[a.length-1].range[1]]),void 0!==(v=this.performAction.apply(T,[c,h,l,y.yy,w[1],r,a].concat(u))))return v;S&&(n=n.slice(0,-1*S*2),r=r.slice(0,-1*S),a=a.slice(0,-1*S)),n.push(this.productions_[w[1]][0]),r.push(T.$),a.push(T._$),$=o[n[n.length-2]][n[n.length-1]],n.push($);break;case 3:return!0}}return!0}),"parse")},d=function(){return{EOF:1,parseError:(0,i.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,i.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,i.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,i.K2)((function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var i=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===i.length?this.yylloc.first_column:0)+i[i.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,i.K2)((function(){return this._more=!0,this}),"more"),reject:(0,i.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,i.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,i.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,i.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,i.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,i.K2)((function(t,e){var n,i,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),(i=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var r in s)this[r]=s[r];return!1}return!1}),"test_match"),next:(0,i.K2)((function(){if(this.done)return this.EOF;var t,e,n,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),r=0;r<s.length;r++)if((n=this._input.match(this.rules[s[r]]))&&(!e||n[0].length>e[0].length)){if(e=n,i=r,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,s[r])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,s[i]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,i.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,i.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,i.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,i.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,i.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,i.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,i.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,i.K2)((function(t,e,n,i){switch(n){case 0:case 1:case 3:case 4:break;case 2:return 10;case 5:return 4;case 6:return 11;case 7:return this.begin("acc_title"),12;case 8:return this.popState(),"acc_title_value";case 9:return this.begin("acc_descr"),14;case 10:return this.popState(),"acc_descr_value";case 11:this.begin("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 17;case 15:return 21;case 16:return 20;case 17:return 6;case 18:return"INVALID"}}),"anonymous"),rules:[/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:timeline\b)/i,/^(?:title\s[^\n]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:section\s[^:\n]+)/i,/^(?::\s[^:\n]+)/i,/^(?:[^#:\n]+)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,9,11,14,15,16,17,18],inclusive:!0}}}}();function u(){this.yy={}}return h.lexer=d,(0,i.K2)(u,"Parser"),u.prototype=h,h.Parser=u,new u}();c.parser=c;var l=c,h={};(0,i.VA)(h,{addEvent:()=>w,addSection:()=>x,addTask:()=>_,addTaskOrg:()=>v,clear:()=>m,default:()=>S,getCommonDb:()=>f,getSections:()=>b,getTasks:()=>k});var d="",u=0,p=[],y=[],g=[],f=(0,i.K2)((()=>i.Wt),"getCommonDb"),m=(0,i.K2)((function(){p.length=0,y.length=0,d="",g.length=0,(0,i.IU)()}),"clear"),x=(0,i.K2)((function(t){d=t,p.push(t)}),"addSection"),b=(0,i.K2)((function(){return p}),"getSections"),k=(0,i.K2)((function(){let t=K();let e=0;for(;!t&&e<100;)t=K(),e++;return y.push(...g),y}),"getTasks"),_=(0,i.K2)((function(t,e,n){const i={id:u++,section:d,type:d,task:t,score:e||0,events:n?[n]:[]};g.push(i)}),"addTask"),w=(0,i.K2)((function(t){g.find((t=>t.id===u-1)).events.push(t)}),"addEvent"),v=(0,i.K2)((function(t){const e={section:d,type:d,description:t,task:t,classes:[]};y.push(e)}),"addTaskOrg"),K=(0,i.K2)((function(){const t=(0,i.K2)((function(t){return g[t].processed}),"compileTask");let e=!0;for(const[n,i]of g.entries())t(n),e=e&&i.processed;return e}),"compileTasks"),S={clear:m,getCommonDb:f,addSection:x,getSections:b,getTasks:k,addTask:_,addTaskOrg:v,addEvent:w},$=(0,i.K2)((function(t,e){const n=t.append("rect");return n.attr("x",e.x),n.attr("y",e.y),n.attr("fill",e.fill),n.attr("stroke",e.stroke),n.attr("width",e.width),n.attr("height",e.height),n.attr("rx",e.rx),n.attr("ry",e.ry),void 0!==e.class&&n.attr("class",e.class),n}),"drawRect"),E=(0,i.K2)((function(t,e){const n=15,r=t.append("circle").attr("cx",e.cx).attr("cy",e.cy).attr("class","face").attr("r",n).attr("stroke-width",2).attr("overflow","visible"),a=t.append("g");function o(t){const i=(0,s.JLW)().startAngle(Math.PI/2).endAngle(Math.PI/2*3).innerRadius(7.5).outerRadius(n/2.2);t.append("path").attr("class","mouth").attr("d",i).attr("transform","translate("+e.cx+","+(e.cy+2)+")")}function c(t){const i=(0,s.JLW)().startAngle(3*Math.PI/2).endAngle(Math.PI/2*5).innerRadius(7.5).outerRadius(n/2.2);t.append("path").attr("class","mouth").attr("d",i).attr("transform","translate("+e.cx+","+(e.cy+7)+")")}function l(t){t.append("line").attr("class","mouth").attr("stroke",2).attr("x1",e.cx-5).attr("y1",e.cy+7).attr("x2",e.cx+5).attr("y2",e.cy+7).attr("class","mouth").attr("stroke-width","1px").attr("stroke","#666")}return a.append("circle").attr("cx",e.cx-5).attr("cy",e.cy-5).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),a.append("circle").attr("cx",e.cx+5).attr("cy",e.cy-5).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),(0,i.K2)(o,"smile"),(0,i.K2)(c,"sad"),(0,i.K2)(l,"ambivalent"),e.score>3?o(a):e.score<3?c(a):l(a),r}),"drawFace"),T=(0,i.K2)((function(t,e){const n=t.append("circle");return n.attr("cx",e.cx),n.attr("cy",e.cy),n.attr("class","actor-"+e.pos),n.attr("fill",e.fill),n.attr("stroke",e.stroke),n.attr("r",e.r),void 0!==n.class&&n.attr("class",n.class),void 0!==e.title&&n.append("title").text(e.title),n}),"drawCircle"),I=(0,i.K2)((function(t,e){const n=e.text.replace(/<br\s*\/?>/gi," "),i=t.append("text");i.attr("x",e.x),i.attr("y",e.y),i.attr("class","legend"),i.style("text-anchor",e.anchor),void 0!==e.class&&i.attr("class",e.class);const s=i.append("tspan");return s.attr("x",e.x+2*e.textMargin),s.text(n),i}),"drawText"),R=(0,i.K2)((function(t,e){function n(t,e,n,i,s){return t+","+e+" "+(t+n)+","+e+" "+(t+n)+","+(e+i-s)+" "+(t+n-1.2*s)+","+(e+i)+" "+t+","+(e+i)}(0,i.K2)(n,"genPoints");const s=t.append("polygon");s.attr("points",n(e.x,e.y,50,20,7)),s.attr("class","labelBox"),e.y=e.y+e.labelMargin,e.x=e.x+.5*e.labelMargin,I(t,e)}),"drawLabel"),A=(0,i.K2)((function(t,e,n){const i=t.append("g"),s=P();s.x=e.x,s.y=e.y,s.fill=e.fill,s.width=n.width,s.height=n.height,s.class="journey-section section-type-"+e.num,s.rx=3,s.ry=3,$(i,s),H(n)(e.text,i,s.x,s.y,s.width,s.height,{class:"journey-section section-type-"+e.num},n,e.colour)}),"drawSection"),L=-1,M=(0,i.K2)((function(t,e,n){const i=e.x+n.width/2,s=t.append("g");L++;s.append("line").attr("id","task"+L).attr("x1",i).attr("y1",e.y).attr("x2",i).attr("y2",450).attr("class","task-line").attr("stroke-width","1px").attr("stroke-dasharray","4 2").attr("stroke","#666"),E(s,{cx:i,cy:300+30*(5-e.score),score:e.score});const r=P();r.x=e.x,r.y=e.y,r.fill=e.fill,r.width=n.width,r.height=n.height,r.class="task task-type-"+e.num,r.rx=3,r.ry=3,$(s,r),H(n)(e.task,s,r.x,r.y,r.width,r.height,{class:"task"},n,e.colour)}),"drawTask"),C=(0,i.K2)((function(t,e){$(t,{x:e.startx,y:e.starty,width:e.stopx-e.startx,height:e.stopy-e.starty,fill:e.fill,class:"rect"}).lower()}),"drawBackgroundRect"),N=(0,i.K2)((function(){return{x:0,y:0,fill:void 0,"text-anchor":"start",width:100,height:100,textMargin:0,rx:0,ry:0}}),"getTextObj"),P=(0,i.K2)((function(){return{x:0,y:0,width:100,anchor:"start",height:100,rx:0,ry:0}}),"getNoteRect"),H=function(){function t(t,e,n,i,r,a,o,c){s(e.append("text").attr("x",n+r/2).attr("y",i+a/2+5).style("font-color",c).style("text-anchor","middle").text(t),o)}function e(t,e,n,i,r,a,o,c,l){const{taskFontSize:h,taskFontFamily:d}=c,u=t.split(/<br\s*\/?>/gi);for(let p=0;p<u.length;p++){const t=p*h-h*(u.length-1)/2,c=e.append("text").attr("x",n+r/2).attr("y",i).attr("fill",l).style("text-anchor","middle").style("font-size",h).style("font-family",d);c.append("tspan").attr("x",n+r/2).attr("dy",t).text(u[p]),c.attr("y",i+a/2).attr("dominant-baseline","central").attr("alignment-baseline","central"),s(c,o)}}function n(t,n,i,r,a,o,c,l){const h=n.append("switch"),d=h.append("foreignObject").attr("x",i).attr("y",r).attr("width",a).attr("height",o).attr("position","fixed").append("xhtml:div").style("display","table").style("height","100%").style("width","100%");d.append("div").attr("class","label").style("display","table-cell").style("text-align","center").style("vertical-align","middle").text(t),e(t,h,i,r,a,o,c,l),s(d,c)}function s(t,e){for(const n in e)n in e&&t.attr(n,e[n])}return(0,i.K2)(t,"byText"),(0,i.K2)(e,"byTspan"),(0,i.K2)(n,"byFo"),(0,i.K2)(s,"_setTextAttrs"),function(i){return"fo"===i.textPlacement?n:"old"===i.textPlacement?t:e}}(),O=(0,i.K2)((function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",5).attr("refY",2).attr("markerWidth",6).attr("markerHeight",4).attr("orient","auto").append("path").attr("d","M 0,0 V 4 L6,2 Z")}),"initGraphics");function j(t,e){t.each((function(){var t,n=(0,s.Ltv)(this),i=n.text().split(/(\s+|<br>)/).reverse(),r=[],a=n.attr("y"),o=parseFloat(n.attr("dy")),c=n.text(null).append("tspan").attr("x",0).attr("y",a).attr("dy",o+"em");for(let s=0;s<i.length;s++)t=i[i.length-1-s],r.push(t),c.text(r.join(" ").trim()),(c.node().getComputedTextLength()>e||"<br>"===t)&&(r.pop(),c.text(r.join(" ").trim()),r="<br>"===t?[""]:[t],c=n.append("tspan").attr("x",0).attr("y",a).attr("dy","1.1em").text(t))}))}(0,i.K2)(j,"wrap");var D=(0,i.K2)((function(t,e,n,i){const s=n%12-1,r=t.append("g");e.section=s,r.attr("class",(e.class?e.class+" ":"")+"timeline-node section-"+s);const a=r.append("g"),o=r.append("g"),c=o.append("text").text(e.descr).attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle").call(j,e.width).node().getBBox(),l=i.fontSize?.replace?i.fontSize.replace("px",""):i.fontSize;return e.height=c.height+1.1*l*.5+e.padding,e.height=Math.max(e.height,e.maxHeight),e.width=e.width+2*e.padding,o.attr("transform","translate("+e.width/2+", "+e.padding/2+")"),W(a,e,s,i),e}),"drawNode"),z=(0,i.K2)((function(t,e,n){const i=t.append("g"),s=i.append("text").text(e.descr).attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle").call(j,e.width).node().getBBox(),r=n.fontSize?.replace?n.fontSize.replace("px",""):n.fontSize;return i.remove(),s.height+1.1*r*.5+e.padding}),"getVirtualNodeHeight"),W=(0,i.K2)((function(t,e,n){t.append("path").attr("id","node-"+e.id).attr("class","node-bkg node-"+e.type).attr("d",`M0 ${e.height-5} v${10-e.height} q0,-5 5,-5 h${e.width-10} q5,0 5,5 v${e.height-5} H0 Z`),t.append("line").attr("class","node-line-"+n).attr("x1",0).attr("y1",e.height).attr("x2",e.width).attr("y2",e.height)}),"defaultBkg"),B={drawRect:$,drawCircle:T,drawSection:A,drawText:I,drawLabel:R,drawTask:M,drawBackgroundRect:C,getTextObj:N,getNoteRect:P,initGraphics:O,drawNode:D,getVirtualNodeHeight:z},F=(0,i.K2)((function(t,e,n,r){const a=(0,i.D7)(),o=a.leftMargin??50;i.Rm.debug("timeline",r.db);const c=a.securityLevel;let l;"sandbox"===c&&(l=(0,s.Ltv)("#i"+e));const h=("sandbox"===c?(0,s.Ltv)(l.nodes()[0].contentDocument.body):(0,s.Ltv)("body")).select("#"+e);h.append("g");const d=r.db.getTasks(),u=r.db.getCommonDb().getDiagramTitle();i.Rm.debug("task",d),B.initGraphics(h);const p=r.db.getSections();i.Rm.debug("sections",p);let y=0,g=0,f=0,m=0,x=50+o,b=50;m=50;let k=0,_=!0;p.forEach((function(t){const e={number:k,descr:t,section:k,width:150,padding:20,maxHeight:y},n=B.getVirtualNodeHeight(h,e,a);i.Rm.debug("sectionHeight before draw",n),y=Math.max(y,n+20)}));let w=0,v=0;i.Rm.debug("tasks.length",d.length);for(const[s,S]of d.entries()){const t={number:s,descr:S,section:S.section,width:150,padding:20,maxHeight:g},e=B.getVirtualNodeHeight(h,t,a);i.Rm.debug("taskHeight before draw",e),g=Math.max(g,e+20),w=Math.max(w,S.events.length);let n=0;for(const i of S.events){const t={descr:i,section:S.section,number:S.section,width:150,padding:20,maxHeight:50};n+=B.getVirtualNodeHeight(h,t,a)}v=Math.max(v,n)}i.Rm.debug("maxSectionHeight before draw",y),i.Rm.debug("maxTaskHeight before draw",g),p&&p.length>0?p.forEach((t=>{const e=d.filter((e=>e.section===t)),n={number:k,descr:t,section:k,width:200*Math.max(e.length,1)-50,padding:20,maxHeight:y};i.Rm.debug("sectionNode",n);const s=h.append("g"),r=B.drawNode(s,n,k,a);i.Rm.debug("sectionNode output",r),s.attr("transform",`translate(${x}, 50)`),b+=y+50,e.length>0&&V(h,e,k,x,b,g,a,w,v,y,!1),x+=200*Math.max(e.length,1),b=50,k++})):(_=!1,V(h,d,k,x,b,g,a,w,v,y,!0));const K=h.node().getBBox();i.Rm.debug("bounds",K),u&&h.append("text").text(u).attr("x",K.width/2-o).attr("font-size","4ex").attr("font-weight","bold").attr("y",20),f=_?y+g+150:g+100;h.append("g").attr("class","lineWrapper").append("line").attr("x1",o).attr("y1",f).attr("x2",K.width+3*o).attr("y2",f).attr("stroke-width",4).attr("stroke","black").attr("marker-end","url(#arrowhead)"),(0,i.ot)(void 0,h,a.timeline?.padding??50,a.timeline?.useMaxWidth??!1)}),"draw"),V=(0,i.K2)((function(t,e,n,s,r,a,o,c,l,h,d){for(const u of e){const e={descr:u.task,section:n,number:n,width:150,padding:20,maxHeight:a};i.Rm.debug("taskNode",e);const c=t.append("g").attr("class","taskWrapper"),p=B.drawNode(c,e,n,o).height;if(i.Rm.debug("taskHeight after draw",p),c.attr("transform",`translate(${s}, ${r})`),a=Math.max(a,p),u.events){const e=t.append("g").attr("class","lineWrapper");let i=a;r+=100,i+=G(t,u.events,n,s,r,o),r-=100,e.append("line").attr("x1",s+95).attr("y1",r+a).attr("x2",s+95).attr("y2",r+a+(d?a:h)+l+120).attr("stroke-width",2).attr("stroke","black").attr("marker-end","url(#arrowhead)").attr("stroke-dasharray","5,5")}s+=200,d&&!o.timeline?.disableMulticolor&&n++}r-=10}),"drawTasks"),G=(0,i.K2)((function(t,e,n,s,r,a){let o=0;const c=r;r+=100;for(const l of e){const e={descr:l,section:n,number:n,width:150,padding:20,maxHeight:50};i.Rm.debug("eventNode",e);const c=t.append("g").attr("class","eventWrapper"),h=B.drawNode(c,e,n,a).height;o+=h,c.attr("transform",`translate(${s}, ${r})`),r=r+10+h}return r=c,o}),"drawEvents"),U={setConf:(0,i.K2)((()=>{}),"setConf"),draw:F},q=(0,i.K2)((t=>{let e="";for(let n=0;n<t.THEME_COLOR_LIMIT;n++)t["lineColor"+n]=t["lineColor"+n]||t["cScaleInv"+n],(0,r.A)(t["lineColor"+n])?t["lineColor"+n]=(0,a.A)(t["lineColor"+n],20):t["lineColor"+n]=(0,o.A)(t["lineColor"+n],20);for(let n=0;n<t.THEME_COLOR_LIMIT;n++){const i=""+(17-3*n);e+=`\n .section-${n-1} rect, .section-${n-1} path, .section-${n-1} circle, .section-${n-1} path {\n fill: ${t["cScale"+n]};\n }\n .section-${n-1} text {\n fill: ${t["cScaleLabel"+n]};\n }\n .node-icon-${n-1} {\n font-size: 40px;\n color: ${t["cScaleLabel"+n]};\n }\n .section-edge-${n-1}{\n stroke: ${t["cScale"+n]};\n }\n .edge-depth-${n-1}{\n stroke-width: ${i};\n }\n .section-${n-1} line {\n stroke: ${t["cScaleInv"+n]} ;\n stroke-width: 3;\n }\n\n .lineWrapper line{\n stroke: ${t["cScaleLabel"+n]} ;\n }\n\n .disabled, .disabled circle, .disabled text {\n fill: lightgray;\n }\n .disabled text {\n fill: #efefef;\n }\n `}return e}),"genSections"),J={db:h,renderer:U,parser:l,styles:(0,i.K2)((t=>`\n .edge {\n stroke-width: 3;\n }\n ${q(t)}\n .section-root rect, .section-root path, .section-root circle {\n fill: ${t.git0};\n }\n .section-root text {\n fill: ${t.gitBranchLabel0};\n }\n .icon-container {\n height:100%;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .edge {\n fill: none;\n }\n .eventWrapper {\n filter: brightness(120%);\n }\n`),"getStyles")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7723.83dacf97.js b/pr-preview/pr-1071/assets/js/7723.83dacf97.js deleted file mode 100644 index 62aace32ae..0000000000 --- a/pr-preview/pr-1071/assets/js/7723.83dacf97.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7723],{57723:(e,s,c)=>{c.d(s,{createPieServices:()=>t.f});var t=c(88685);c(19369)}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/790f17e8.a523ad89.js b/pr-preview/pr-1071/assets/js/790f17e8.a523ad89.js deleted file mode 100644 index 316d53b0ae..0000000000 --- a/pr-preview/pr-1071/assets/js/790f17e8.a523ad89.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5242],{27808:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-0.8/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/0.8/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/components/service-mesh.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.8/components/policies"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/attestation"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"CONTRAST_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"CONTRAST_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"<name>#<port>#false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:"<name>"})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"<name>#<port>#true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: CONTRAST_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v0.8.1@sha256:de65f2921d617fd2cee3734c4d325b9464e655d3c29e95844163a0738937748a"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-tls-certs\n mountPath: /tls-config\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"<name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port>"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:"<name>"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7bd8db71.98254150.js b/pr-preview/pr-1071/assets/js/7bd8db71.98254150.js deleted file mode 100644 index e4e7ac3e37..0000000000 --- a/pr-preview/pr-1071/assets/js/7bd8db71.98254150.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1606],{57378:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-1.0/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/1.0/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/intro.md","tags":[],"version":"1.0","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/getting-started/install",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7bdde4a4.4a1da80b.js b/pr-preview/pr-1071/assets/js/7bdde4a4.4a1da80b.js deleted file mode 100644 index dd1ca474ac..0000000000 --- a/pr-preview/pr-1071/assets/js/7bdde4a4.4a1da80b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3752],{79218:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"examples/mysql","title":"Encrypted volume mount","description":"This tutorial guides you through deploying a simple application with an","source":"@site/docs/examples/mysql.md","sourceDirName":"examples","slug":"/examples/mysql","permalink":"/contrast/pr-preview/pr-1071/next/examples/mysql","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/examples/mysql.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/next/examples/emojivoto"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/next/deployment"}}');var r=n(74848),o=n(28453);const i={},a="Encrypted volume mount",l={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy MySQL with Contrast",id:"steps-to-deploy-mysql-with-contrast",level:2},{value:"Download the deployment files",id:"download-the-deployment-files",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy MySQL",id:"deploy-mysql",level:3},{value:"Verifying the deployment as a user",id:"verifying-the-deployment-as-a-user",level:2},{value:"Verifying the Coordinator",id:"verifying-the-coordinator",level:3},{value:"Auditing the manifest history and artifacts",id:"auditing-the-manifest-history-and-artifacts",level:3},{value:"Connecting to the application",id:"connecting-to-the-application",level:3},{value:"Updating the deployment",id:"updating-the-deployment",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components},{TabItem:n,Tabs:s}=t;return n||p("TabItem",!0),s||p("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"encrypted-volume-mount",children:"Encrypted volume mount"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsxs)(t.strong,{children:["This tutorial guides you through deploying a simple application with an\nencrypted MySQL database using the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/secrets#workload-secrets",children:"workload\nsecret"}),"."]})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.a,{href:"https://mysql.com",children:"MySQL"})," is an open-source database used to organize data into\ntables and quickly retrieve information about its content. All of the data in a\nMySQL database is stored in the ",(0,r.jsx)(t.code,{children:"/var/lib/mysql"})," directory. In this example, we\nuse the workload secret to setup an encrypted LUKS mount for the\n",(0,r.jsx)(t.code,{children:"/var/lib/mysql"})," directory to easily deploy an application with encrypted\npersistent storage using Contrast."]}),"\n",(0,r.jsxs)(t.p,{children:["The resources provided in this demo are designed for educational purposes and\nshouldn't be used in a production environment without proper evaluation. When\nworking with persistent storage, regular backups are recommended in order to\nprevent data loss. For confidential applications, please also refer to the\n",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/security-considerations",children:"security considerations"}),". Also be\naware of the differences in security implications of the workload secrets for\nthe data owner and the workload owner. For more details, see the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/secrets#workload-secrets",children:"Workload\nSecrets"})," documentation."]}),"\n",(0,r.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Installed Contrast CLI"}),"\n",(0,r.jsxs)(t.li,{children:["A running Kubernetes cluster with support for confidential containers, either on ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup",children:"AKS"})," or on ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal",children:"bare metal"})]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"steps-to-deploy-mysql-with-contrast",children:"Steps to deploy MySQL with Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"download-the-deployment-files",children:"Download the deployment files"}),"\n",(0,r.jsx)(t.p,{children:"The MySQL deployment files are part of the Contrast release. You can download them by running:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/latest/download/mysql-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,r.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast depends on a ",(0,r.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:["custom Kubernetes ",(0,r.jsx)(t.code,{children:"RuntimeClass"})]}),",\nwhich needs to be installed to the cluster initially.\nThis consists of a ",(0,r.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,r.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(n,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-aks-clh-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsxs)(t.p,{children:["Deploy the Contrast Coordinator, comprising a single replica deployment and a\n",(0,r.jsx)(t.code,{children:"LoadBalancer"})," service, into your cluster:"]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(n,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-aks-clh-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(t.p,{children:["Run the ",(0,r.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,r.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(n,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})})}),(0,r.jsxs)(n,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp deployment/\n"})}),(0,r.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(t.p,{children:["On bare-metal SEV-SNP, ",(0,r.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(t.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(t.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,r.jsxs)(n,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx deployment/\n"})}),(0,r.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(t.p,{children:["On bare-metal TDX, ",(0,r.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(t.code,{children:"MinimumTeeTcbSvn"})," and ",(0,r.jsx)(t.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(t.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,r.jsx)(t.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,r.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,r.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,r.jsx)(t.a,{href:"../components/runtime",children:"runtime class"})," ",(0,r.jsx)(t.code,{children:"contrast-cc"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads. It will attest the pod to the Coordinator and fetch the workload certificates and the workload secret."]}),(0,r.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe MySQL server and client."]})]}),"\n",(0,r.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,r.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsxs)(t.p,{children:["On bare metal, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(t.h3,{id:"deploy-mysql",children:"Deploy MySQL"}),"\n",(0,r.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the MySQL deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,r.jsx)(t.admonition,{title:"Persistent workload secrets",type:"note",children:(0,r.jsxs)(t.p,{children:["During the initialization process of the workload pod, the Contrast Initializer\nsends an attestation report to the Coordinator and receives a workload secret\nderived from the Coordinator's secret seed and the workload secret ID specified in the\nmanifest, and writes it to a secure in-memory ",(0,r.jsx)(t.code,{children:"volumeMount"}),"."]})}),"\n",(0,r.jsxs)(t.p,{children:["The MySQL deployment is declared as a StatefulSet with a mounted block device.\nAn init container running ",(0,r.jsx)(t.code,{children:"cryptsetup"})," uses the workload secret at\n",(0,r.jsx)(t.code,{children:"/contrast/secrets/workload-secret-seed"})," to generate a key and setup the block\ndevice as a LUKS partition. Before starting the MySQL container, the init\ncontainer uses the generated key to open the LUKS device, which is then mounted\nby the MySQL container. For the MySQL container, this process is completely\ntransparent and works like mounting any other volume. The ",(0,r.jsx)(t.code,{children:"cryptsetup"})," container\nwill remain running to provide the necessary decryption context for the workload\ncontainer."]}),"\n",(0,r.jsx)(t.h2,{id:"verifying-the-deployment-as-a-user",children:"Verifying the deployment as a user"}),"\n",(0,r.jsx)(t.p,{children:"In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before connecting to the database.\nWith Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment.\nContrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future.\nSuccessful verification of the Coordinator means that the user can be sure that the given manifest will be enforced."}),"\n",(0,r.jsx)(t.h3,{id:"verifying-the-coordinator",children:"Verifying the Coordinator"}),"\n",(0,r.jsx)(t.p,{children:"A user can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,r.jsxs)(t.p,{children:["The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,r.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,r.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,r.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsxs)(t.p,{children:["On bare metal, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(t.h3,{id:"auditing-the-manifest-history-and-artifacts",children:"Auditing the manifest history and artifacts"}),"\n",(0,r.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,r.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA user of the application should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,r.jsx)(t.h3,{id:"connecting-to-the-application",children:"Connecting to the application"}),"\n",(0,r.jsxs)(t.p,{children:["Other confidential containers can securely connect to the MySQL server via the\n",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"Service Mesh"}),". The configured ",(0,r.jsx)(t.code,{children:"mysql-client"}),"\ndeployment connects to the MySQL server and inserts test data into a table. To\nview the logs of the ",(0,r.jsx)(t.code,{children:"mysql-client"})," deployment, use the following commands:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl logs -l app.kubernetes.io/name=mysql-client -c mysql-client\n"})}),"\n",(0,r.jsx)(t.p,{children:"The Service Mesh ensures an mTLS connection between the MySQL client and server\nusing the mesh certificates. As a result, no other workload can connect to the\nMySQL server unless explicitly allowed in the manifest."}),"\n",(0,r.jsx)(t.h2,{id:"updating-the-deployment",children:"Updating the deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Because the workload secret is derived from the ",(0,r.jsx)(t.code,{children:"WorkloadSecredID"})," specified in\nthe manifest and not to an individual pod, once the pod restarts, the\n",(0,r.jsx)(t.code,{children:"cryptsetup"})," init container can deterministically generate the same key again\nand open the already partitioned LUKS device.\nFor more information on using the workload secret, see ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/secrets#workload-secrets",children:"Workload\nSecrets"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["For example, after making changes to the deployment files, the runtime policies\nneed to be regenerated with ",(0,r.jsx)(t.code,{children:"contrast generate"})," and the new manifest needs to be\nset using ",(0,r.jsx)(t.code,{children:"contrast set"}),"."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'contrast generate deployment/\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,r.jsx)(t.p,{children:"The new deployment can then be applied by running:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart statefulset/mysql-backend\nkubectl rollout restart deployment/mysql-client\n"})}),"\n",(0,r.jsxs)(t.p,{children:["The new MySQL backend pod will then start up the ",(0,r.jsx)(t.code,{children:"cryptsetup"})," init container which\nreceives the same workload secret as before and can therefore generate the\ncorrect key to open the LUKS device. All previously stored data in the MySQL\ndatabase is available in the newly created pod in an encrypted volume mount."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}function p(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7d1602ac.b79b6cd3.js b/pr-preview/pr-1071/assets/js/7d1602ac.b79b6cd3.js deleted file mode 100644 index fe6615d59a..0000000000 --- a/pr-preview/pr-1071/assets/js/7d1602ac.b79b6cd3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6069],{55238:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-0.8/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/basics/features.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.8/getting-started/install"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7edb0f0d.3b9797a0.js b/pr-preview/pr-1071/assets/js/7edb0f0d.3b9797a0.js deleted file mode 100644 index 2c2edf9be4..0000000000 --- a/pr-preview/pr-1071/assets/js/7edb0f0d.3b9797a0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5231],{32716:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>h});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/versioned_docs/version-0.7/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/architecture/observability.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/certificates"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/0.7/features-limitations"}}');var s=r(74848),i=r(28453);const o={},a="Observability",c={},h=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator starts two gRPC servers, one for the user API on port ",(0,s.jsx)(t.code,{children:"1313"})," and\none for the mesh API on port ",(0,s.jsx)(t.code,{children:"7777"}),". Metrics for both servers can be accessed\nusing different prefixes."]}),"\n",(0,s.jsxs)(t.p,{children:["All metric names for the user API are prefixed with ",(0,s.jsx)(t.code,{children:"contrast_userapi_grpc_server_"}),".\nExposed metrics include the number of handled requests of the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively. For each method\nyou can see the gRPC status code indicating whether the request succeeded or\nnot and the request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["For the mesh API, the metric names are prefixed with ",(0,s.jsx)(t.code,{children:"contrast_meshapi_grpc_server_"}),". The\nmetrics include similar data to the user API for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"})," which\ngets called by the ",(0,s.jsx)(t.a,{href:"../components#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>a});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/7f3f1ff7.c5b8c0ac.js b/pr-preview/pr-1071/assets/js/7f3f1ff7.c5b8c0ac.js deleted file mode 100644 index 7e627aa5a9..0000000000 --- a/pr-preview/pr-1071/assets/js/7f3f1ff7.c5b8c0ac.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6623],{86696:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-0.9/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/0.9/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/about/telemetry.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/0.9/features-limitations"}}');var r=n(74848),o=n(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/808ec8ef.f0fe9369.js b/pr-preview/pr-1071/assets/js/808ec8ef.f0fe9369.js deleted file mode 100644 index 57d99f5d5a..0000000000 --- a/pr-preview/pr-1071/assets/js/808ec8ef.f0fe9369.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6118],{20528:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>l,frontMatter:()=>o,metadata:()=>r,toc:()=>d});const r=JSON.parse('{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","source":"@site/versioned_docs/version-1.2/architecture/secrets.md","sourceDirName":"architecture","slug":"/architecture/secrets","permalink":"/contrast/pr-preview/pr-1071/architecture/secrets","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/architecture/secrets.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/architecture/attestation"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/architecture/certificates"}}');var n=s(74848),i=s(28453);const o={},a="Secrets & recovery",c={},d=[{value:"Persistence",id:"persistence",level:2},{value:"Recovery",id:"recovery",level:2},{value:"Workload Secrets",id:"workload-secrets",level:2},{value:"Secure persistence",id:"secure-persistence",level:3}];function h(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"secrets--recovery",children:"Secrets & recovery"})}),"\n",(0,n.jsx)(t.p,{children:"When the Coordinator is configured with the initial manifest, it generates a random secret seed.\nFrom this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history.\nThis derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state."}),"\n",(0,n.jsxs)(t.p,{children:["The secret seed is returned to the user on the first call to ",(0,n.jsx)(t.code,{children:"contrast set"}),", encrypted with the user's public seed share owner key.\nIf no seed share owner key is provided, a key is generated and stored in the working directory."]}),"\n",(0,n.jsx)(t.h2,{id:"persistence",children:"Persistence"}),"\n",(0,n.jsxs)(t.p,{children:["The Coordinator runs as a ",(0,n.jsx)(t.code,{children:"StatefulSet"})," with a dynamically provisioned persistent volume.\nThis volume stores the manifest history and the associated runtime policies.\nThe manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads.\nHowever, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users.\nThus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed."]}),"\n",(0,n.jsx)(t.h2,{id:"recovery",children:"Recovery"}),"\n",(0,n.jsxs)(t.p,{children:["When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests.\nIt needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures.\nThis procedure is called recovery and is initiated by the workload owner.\nThe CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the ",(0,n.jsx)(t.code,{children:"Recover"})," method.\nThe Coordinator recovers its key material and verifies the manifest history signature."]}),"\n",(0,n.jsx)(t.h2,{id:"workload-secrets",children:"Workload Secrets"}),"\n",(0,n.jsxs)(t.p,{children:["The Coordinator provides each workload a secret seed during attestation.\nThis secret can be used by the workload to derive additional secrets for example to encrypt persistent data.\nLike the workload certificates, it's written to the ",(0,n.jsx)(t.code,{children:"secrets/workload-secret-seed"})," path under the shared Kubernetes volume ",(0,n.jsx)(t.code,{children:"contrast-secrets"}),"."]}),"\n",(0,n.jsx)(t.admonition,{type:"warning",children:(0,n.jsx)(t.p,{children:"The workload owner can decrypt data encrypted with secrets derived from the workload secret.\nThe workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner.\nIf the data owner and the workload owner is the same entity, then they can safely use the workload secrets."})}),"\n",(0,n.jsx)(t.h3,{id:"secure-persistence",children:"Secure persistence"}),"\n",(0,n.jsx)(t.p,{children:"Remember that persistent volumes from the cloud provider are untrusted.\nUsing the workload secret, applications can set up trusted storage on top of untrusted block devices.\nThe following, slightly abbreviated resource outlines how this could be realized:"}),"\n",(0,n.jsx)(t.admonition,{type:"warning",children:(0,n.jsx)(t.p,{children:"This configuration snippet is intended to be educational and needs to be refined and adapted to your production environment.\nUsing it as-is may result in data corruption or data loss."})}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-yaml",children:"apiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n name: volume-tester\nspec:\n template:\n spec:\n containers:\n - name: main\n image: my.registry/my-image@sha256:0123...\n command:\n - /bin/sh\n - -ec\n - | # <-- Custom script that mounts the encrypted disk and then calls the original application.\n device=/dev/csi0\n if ! cryptsetup isLuks $device; then\n cryptsetup luksFormat $device /contrast/secrets/workload-secret-seed\n cryptsetup open $device state -d /contrast/secrets/workload-secret-seed\n mkfs.ext4 /dev/mapper/state\n cryptsetup close state\n fi\n cryptsetup open $device state -d /contrast/secrets/workload-secret-seed\n /path/to/original/app\n name: volume-tester\n volumeDevices:\n - name: state\n devicePath: /dev/csi0\n securityContext:\n privileged: true # <-- This is necessary for mounting devices.\n runtimeClassName: contrast-cc\n volumeClaimTemplates:\n - apiVersion: v1\n kind: PersistentVolumeClaim\n metadata:\n name: state\n spec:\n accessModes:\n - ReadWriteOnce\n resources:\n requests:\n storage: 1Gi\n volumeMode: Block # <-- The requested volume needs to be a raw block device.\n"})}),"\n",(0,n.jsx)(t.admonition,{type:"note",children:(0,n.jsxs)(t.p,{children:["This example assumes that you can modify the container image to include a shell and the ",(0,n.jsx)(t.code,{children:"cryptsetup"})," utility.\nAlternatively, you can set up a secure mount from a sidecar container inside an ",(0,n.jsx)(t.code,{children:"emptyDir"})," mount shared with the main container.\nThe Contrast end-to-end tests include ",(0,n.jsx)(t.a,{href:"https://github.com/edgelesssys/contrast/blob/0662a2e/internal/kuberesource/sets.go#L504",children:"an example"})," of this type of mount."]})})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},28453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>a});var r=s(96540);const n={},i=r.createContext(n);function o(e){const t=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),r.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8132774f.838ec563.js b/pr-preview/pr-1071/assets/js/8132774f.838ec563.js deleted file mode 100644 index 9d1f2a51d3..0000000000 --- a/pr-preview/pr-1071/assets/js/8132774f.838ec563.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1841],{58879:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>i});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-0.7/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/getting-started/cluster-setup.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/install"},"next":{"title":"Examples","permalink":"/contrast/pr-preview/pr-1071/0.7/examples/"}}');var t=r(74848),a=r(28453);const o={},c="Create a cluster",l={},i=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.p,{children:["Install the latest version of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli",children:"Login to your account"}),", which needs\nto have the permissions to create an AKS cluster, by executing:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a\nnon-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool."}),"\n",(0,t.jsx)(n.p,{children:"We'll first start by creating the non-CoCo cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.29 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"We then add a second node pool with CoCo support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool add \\\n --resource-group "${azResourceGroup:?}" \\\n --name nodepool2 \\\n --cluster-name "${azClusterName:?}" \\\n --node-count 1 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation\n'})}),"\n",(0,t.jsx)(n.p,{children:"Optionally, we can now remove the non-CoCo node pool:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool delete \\\n --resource-group "${azResourceGroup:?}" \\\n --cluster-name "${azClusterName:?}" \\\n --name nodepool1\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"For validation, list the available nodes using kubectl:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show two nodes:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\naks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>c});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8413.965072af.js b/pr-preview/pr-1071/assets/js/8413.965072af.js deleted file mode 100644 index a3e0d0d681..0000000000 --- a/pr-preview/pr-1071/assets/js/8413.965072af.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8413],{88413:(t,e,i)=>{i.d(e,{diagram:()=>Y});var n=i(10009),r=i(20007),s=i(62334),a=i(697),l=function(){var t=(0,n.K2)((function(t,e,i,n){for(i=i||{},n=t.length;n--;i[t[n]]=e);return i}),"o"),e=[1,3],i=[1,4],r=[1,5],s=[1,6],a=[5,6,8,9,11,13,31,32,33,34,35,36,44,62,63],l=[1,18],o=[2,7],h=[1,22],c=[1,23],u=[1,24],d=[1,25],y=[1,26],p=[1,27],_=[1,20],g=[1,28],E=[1,29],R=[62,63],m=[5,8,9,11,13,31,32,33,34,35,36,44,51,53,62,63],f=[1,47],I=[1,48],S=[1,49],N=[1,50],b=[1,51],k=[1,52],T=[1,53],x=[53,54],w=[1,64],A=[1,60],q=[1,61],v=[1,62],K=[1,63],$=[1,65],O=[1,69],L=[1,70],C=[1,67],M=[1,68],F=[5,8,9,11,13,31,32,33,34,35,36,44,62,63],D={trace:(0,n.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,acc_title:9,acc_title_value:10,acc_descr:11,acc_descr_value:12,acc_descr_multiline_value:13,requirementDef:14,elementDef:15,relationshipDef:16,requirementType:17,requirementName:18,STRUCT_START:19,requirementBody:20,ID:21,COLONSEP:22,id:23,TEXT:24,text:25,RISK:26,riskLevel:27,VERIFYMTHD:28,verifyType:29,STRUCT_STOP:30,REQUIREMENT:31,FUNCTIONAL_REQUIREMENT:32,INTERFACE_REQUIREMENT:33,PERFORMANCE_REQUIREMENT:34,PHYSICAL_REQUIREMENT:35,DESIGN_CONSTRAINT:36,LOW_RISK:37,MED_RISK:38,HIGH_RISK:39,VERIFY_ANALYSIS:40,VERIFY_DEMONSTRATION:41,VERIFY_INSPECTION:42,VERIFY_TEST:43,ELEMENT:44,elementName:45,elementBody:46,TYPE:47,type:48,DOCREF:49,ref:50,END_ARROW_L:51,relationship:52,LINE:53,END_ARROW_R:54,CONTAINS:55,COPIES:56,DERIVES:57,SATISFIES:58,VERIFIES:59,REFINES:60,TRACES:61,unqString:62,qString:63,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",9:"acc_title",10:"acc_title_value",11:"acc_descr",12:"acc_descr_value",13:"acc_descr_multiline_value",19:"STRUCT_START",21:"ID",22:"COLONSEP",24:"TEXT",26:"RISK",28:"VERIFYMTHD",30:"STRUCT_STOP",31:"REQUIREMENT",32:"FUNCTIONAL_REQUIREMENT",33:"INTERFACE_REQUIREMENT",34:"PERFORMANCE_REQUIREMENT",35:"PHYSICAL_REQUIREMENT",36:"DESIGN_CONSTRAINT",37:"LOW_RISK",38:"MED_RISK",39:"HIGH_RISK",40:"VERIFY_ANALYSIS",41:"VERIFY_DEMONSTRATION",42:"VERIFY_INSPECTION",43:"VERIFY_TEST",44:"ELEMENT",47:"TYPE",49:"DOCREF",51:"END_ARROW_L",53:"LINE",54:"END_ARROW_R",55:"CONTAINS",56:"COPIES",57:"DERIVES",58:"SATISFIES",59:"VERIFIES",60:"REFINES",61:"TRACES",62:"unqString",63:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,2],[4,2],[4,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[14,5],[20,5],[20,5],[20,5],[20,5],[20,2],[20,1],[17,1],[17,1],[17,1],[17,1],[17,1],[17,1],[27,1],[27,1],[27,1],[29,1],[29,1],[29,1],[29,1],[15,5],[46,5],[46,5],[46,2],[46,1],[16,5],[16,5],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[52,1],[18,1],[18,1],[23,1],[23,1],[25,1],[25,1],[45,1],[45,1],[48,1],[48,1],[50,1],[50,1]],performAction:(0,n.K2)((function(t,e,i,n,r,s,a){var l=s.length-1;switch(r){case 4:this.$=s[l].trim(),n.setAccTitle(this.$);break;case 5:case 6:this.$=s[l].trim(),n.setAccDescription(this.$);break;case 7:this.$=[];break;case 13:n.addRequirement(s[l-3],s[l-4]);break;case 14:n.setNewReqId(s[l-2]);break;case 15:n.setNewReqText(s[l-2]);break;case 16:n.setNewReqRisk(s[l-2]);break;case 17:n.setNewReqVerifyMethod(s[l-2]);break;case 20:this.$=n.RequirementType.REQUIREMENT;break;case 21:this.$=n.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 22:this.$=n.RequirementType.INTERFACE_REQUIREMENT;break;case 23:this.$=n.RequirementType.PERFORMANCE_REQUIREMENT;break;case 24:this.$=n.RequirementType.PHYSICAL_REQUIREMENT;break;case 25:this.$=n.RequirementType.DESIGN_CONSTRAINT;break;case 26:this.$=n.RiskLevel.LOW_RISK;break;case 27:this.$=n.RiskLevel.MED_RISK;break;case 28:this.$=n.RiskLevel.HIGH_RISK;break;case 29:this.$=n.VerifyType.VERIFY_ANALYSIS;break;case 30:this.$=n.VerifyType.VERIFY_DEMONSTRATION;break;case 31:this.$=n.VerifyType.VERIFY_INSPECTION;break;case 32:this.$=n.VerifyType.VERIFY_TEST;break;case 33:n.addElement(s[l-3]);break;case 34:n.setNewElementType(s[l-2]);break;case 35:n.setNewElementDocRef(s[l-2]);break;case 38:n.addRelationship(s[l-2],s[l],s[l-4]);break;case 39:n.addRelationship(s[l-2],s[l-4],s[l]);break;case 40:this.$=n.Relationships.CONTAINS;break;case 41:this.$=n.Relationships.COPIES;break;case 42:this.$=n.Relationships.DERIVES;break;case 43:this.$=n.Relationships.SATISFIES;break;case 44:this.$=n.Relationships.VERIFIES;break;case 45:this.$=n.Relationships.REFINES;break;case 46:this.$=n.Relationships.TRACES}}),"anonymous"),table:[{3:1,4:2,6:e,9:i,11:r,13:s},{1:[3]},{3:8,4:2,5:[1,7],6:e,9:i,11:r,13:s},{5:[1,9]},{10:[1,10]},{12:[1,11]},t(a,[2,6]),{3:12,4:2,6:e,9:i,11:r,13:s},{1:[2,2]},{4:17,5:l,7:13,8:o,9:i,11:r,13:s,14:14,15:15,16:16,17:19,23:21,31:h,32:c,33:u,34:d,35:y,36:p,44:_,62:g,63:E},t(a,[2,4]),t(a,[2,5]),{1:[2,1]},{8:[1,30]},{4:17,5:l,7:31,8:o,9:i,11:r,13:s,14:14,15:15,16:16,17:19,23:21,31:h,32:c,33:u,34:d,35:y,36:p,44:_,62:g,63:E},{4:17,5:l,7:32,8:o,9:i,11:r,13:s,14:14,15:15,16:16,17:19,23:21,31:h,32:c,33:u,34:d,35:y,36:p,44:_,62:g,63:E},{4:17,5:l,7:33,8:o,9:i,11:r,13:s,14:14,15:15,16:16,17:19,23:21,31:h,32:c,33:u,34:d,35:y,36:p,44:_,62:g,63:E},{4:17,5:l,7:34,8:o,9:i,11:r,13:s,14:14,15:15,16:16,17:19,23:21,31:h,32:c,33:u,34:d,35:y,36:p,44:_,62:g,63:E},{4:17,5:l,7:35,8:o,9:i,11:r,13:s,14:14,15:15,16:16,17:19,23:21,31:h,32:c,33:u,34:d,35:y,36:p,44:_,62:g,63:E},{18:36,62:[1,37],63:[1,38]},{45:39,62:[1,40],63:[1,41]},{51:[1,42],53:[1,43]},t(R,[2,20]),t(R,[2,21]),t(R,[2,22]),t(R,[2,23]),t(R,[2,24]),t(R,[2,25]),t(m,[2,49]),t(m,[2,50]),{1:[2,3]},{8:[2,8]},{8:[2,9]},{8:[2,10]},{8:[2,11]},{8:[2,12]},{19:[1,44]},{19:[2,47]},{19:[2,48]},{19:[1,45]},{19:[2,53]},{19:[2,54]},{52:46,55:f,56:I,57:S,58:N,59:b,60:k,61:T},{52:54,55:f,56:I,57:S,58:N,59:b,60:k,61:T},{5:[1,55]},{5:[1,56]},{53:[1,57]},t(x,[2,40]),t(x,[2,41]),t(x,[2,42]),t(x,[2,43]),t(x,[2,44]),t(x,[2,45]),t(x,[2,46]),{54:[1,58]},{5:w,20:59,21:A,24:q,26:v,28:K,30:$},{5:O,30:L,46:66,47:C,49:M},{23:71,62:g,63:E},{23:72,62:g,63:E},t(F,[2,13]),{22:[1,73]},{22:[1,74]},{22:[1,75]},{22:[1,76]},{5:w,20:77,21:A,24:q,26:v,28:K,30:$},t(F,[2,19]),t(F,[2,33]),{22:[1,78]},{22:[1,79]},{5:O,30:L,46:80,47:C,49:M},t(F,[2,37]),t(F,[2,38]),t(F,[2,39]),{23:81,62:g,63:E},{25:82,62:[1,83],63:[1,84]},{27:85,37:[1,86],38:[1,87],39:[1,88]},{29:89,40:[1,90],41:[1,91],42:[1,92],43:[1,93]},t(F,[2,18]),{48:94,62:[1,95],63:[1,96]},{50:97,62:[1,98],63:[1,99]},t(F,[2,36]),{5:[1,100]},{5:[1,101]},{5:[2,51]},{5:[2,52]},{5:[1,102]},{5:[2,26]},{5:[2,27]},{5:[2,28]},{5:[1,103]},{5:[2,29]},{5:[2,30]},{5:[2,31]},{5:[2,32]},{5:[1,104]},{5:[2,55]},{5:[2,56]},{5:[1,105]},{5:[2,57]},{5:[2,58]},{5:w,20:106,21:A,24:q,26:v,28:K,30:$},{5:w,20:107,21:A,24:q,26:v,28:K,30:$},{5:w,20:108,21:A,24:q,26:v,28:K,30:$},{5:w,20:109,21:A,24:q,26:v,28:K,30:$},{5:O,30:L,46:110,47:C,49:M},{5:O,30:L,46:111,47:C,49:M},t(F,[2,14]),t(F,[2,15]),t(F,[2,16]),t(F,[2,17]),t(F,[2,34]),t(F,[2,35])],defaultActions:{8:[2,2],12:[2,1],30:[2,3],31:[2,8],32:[2,9],33:[2,10],34:[2,11],35:[2,12],37:[2,47],38:[2,48],40:[2,53],41:[2,54],83:[2,51],84:[2,52],86:[2,26],87:[2,27],88:[2,28],90:[2,29],91:[2,30],92:[2,31],93:[2,32],95:[2,55],96:[2,56],98:[2,57],99:[2,58]},parseError:(0,n.K2)((function(t,e){if(!e.recoverable){var i=new Error(t);throw i.hash=e,i}this.trace(t)}),"parseError"),parse:(0,n.K2)((function(t){var e=this,i=[0],r=[],s=[null],a=[],l=this.table,o="",h=0,c=0,u=0,d=a.slice.call(arguments,1),y=Object.create(this.lexer),p={yy:{}};for(var _ in this.yy)Object.prototype.hasOwnProperty.call(this.yy,_)&&(p.yy[_]=this.yy[_]);y.setInput(t,p.yy),p.yy.lexer=y,p.yy.parser=this,void 0===y.yylloc&&(y.yylloc={});var g=y.yylloc;a.push(g);var E=y.options&&y.options.ranges;function R(){var t;return"number"!=typeof(t=r.pop()||y.lex()||1)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof p.yy.parseError?this.parseError=p.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,n.K2)((function(t){i.length=i.length-2*t,s.length=s.length-t,a.length=a.length-t}),"popStack"),(0,n.K2)(R,"lex");for(var m,f,I,S,N,b,k,T,x,w={};;){if(I=i[i.length-1],this.defaultActions[I]?S=this.defaultActions[I]:(null==m&&(m=R()),S=l[I]&&l[I][m]),void 0===S||!S.length||!S[0]){var A="";for(b in x=[],l[I])this.terminals_[b]&&b>2&&x.push("'"+this.terminals_[b]+"'");A=y.showPosition?"Parse error on line "+(h+1)+":\n"+y.showPosition()+"\nExpecting "+x.join(", ")+", got '"+(this.terminals_[m]||m)+"'":"Parse error on line "+(h+1)+": Unexpected "+(1==m?"end of input":"'"+(this.terminals_[m]||m)+"'"),this.parseError(A,{text:y.match,token:this.terminals_[m]||m,line:y.yylineno,loc:g,expected:x})}if(S[0]instanceof Array&&S.length>1)throw new Error("Parse Error: multiple actions possible at state: "+I+", token: "+m);switch(S[0]){case 1:i.push(m),s.push(y.yytext),a.push(y.yylloc),i.push(S[1]),m=null,f?(m=f,f=null):(c=y.yyleng,o=y.yytext,h=y.yylineno,g=y.yylloc,u>0&&u--);break;case 2:if(k=this.productions_[S[1]][1],w.$=s[s.length-k],w._$={first_line:a[a.length-(k||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(k||1)].first_column,last_column:a[a.length-1].last_column},E&&(w._$.range=[a[a.length-(k||1)].range[0],a[a.length-1].range[1]]),void 0!==(N=this.performAction.apply(w,[o,c,h,p.yy,S[1],s,a].concat(d))))return N;k&&(i=i.slice(0,-1*k*2),s=s.slice(0,-1*k),a=a.slice(0,-1*k)),i.push(this.productions_[S[1]][0]),s.push(w.$),a.push(w._$),T=l[i[i.length-2]][i[i.length-1]],i.push(T);break;case 3:return!0}}return!0}),"parse")},P=function(){return{EOF:1,parseError:(0,n.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,n.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,n.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,n.K2)((function(t){var e=t.length,i=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),i.length-1&&(this.yylineno-=i.length-1);var r=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:i?(i.length===n.length?this.yylloc.first_column:0)+n[n.length-i.length].length-i[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[r[0],r[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,n.K2)((function(){return this._more=!0,this}),"more"),reject:(0,n.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,n.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,n.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,n.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,n.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,n.K2)((function(t,e){var i,n,r;if(this.options.backtrack_lexer&&(r={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(r.yylloc.range=this.yylloc.range.slice(0))),(n=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=n.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-n[n.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],i=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var s in r)this[s]=r[s];return!1}return!1}),"test_match"),next:(0,n.K2)((function(){if(this.done)return this.EOF;var t,e,i,n;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var r=this._currentRules(),s=0;s<r.length;s++)if((i=this._input.match(this.rules[r[s]]))&&(!e||i[0].length>e[0].length)){if(e=i,n=s,this.options.backtrack_lexer){if(!1!==(t=this.test_match(i,r[s])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,r[n]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,n.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,n.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,n.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,n.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,n.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,n.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,n.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,n.K2)((function(t,e,i,n){switch(i){case 0:return"title";case 1:return this.begin("acc_title"),9;case 2:return this.popState(),"acc_title_value";case 3:return this.begin("acc_descr"),11;case 4:return this.popState(),"acc_descr_value";case 5:this.begin("acc_descr_multiline");break;case 6:case 48:this.popState();break;case 7:return"acc_descr_multiline_value";case 8:return 5;case 9:case 10:case 11:break;case 12:return 8;case 13:return 6;case 14:return 19;case 15:return 30;case 16:return 22;case 17:return 21;case 18:return 24;case 19:return 26;case 20:return 28;case 21:return 31;case 22:return 32;case 23:return 33;case 24:return 34;case 25:return 35;case 26:return 36;case 27:return 37;case 28:return 38;case 29:return 39;case 30:return 40;case 31:return 41;case 32:return 42;case 33:return 43;case 34:return 44;case 35:return 55;case 36:return 56;case 37:return 57;case 38:return 58;case 39:return 59;case 40:return 60;case 41:return 61;case 42:return 47;case 43:return 49;case 44:return 51;case 45:return 54;case 46:return 53;case 47:this.begin("string");break;case 49:return"qString";case 50:return e.yytext=e.yytext.trim(),62}}),"anonymous"),rules:[/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:$)/i,/^(?:requirementDiagram\b)/i,/^(?:\{)/i,/^(?:\})/i,/^(?::)/i,/^(?:id\b)/i,/^(?:text\b)/i,/^(?:risk\b)/i,/^(?:verifyMethod\b)/i,/^(?:requirement\b)/i,/^(?:functionalRequirement\b)/i,/^(?:interfaceRequirement\b)/i,/^(?:performanceRequirement\b)/i,/^(?:physicalRequirement\b)/i,/^(?:designConstraint\b)/i,/^(?:low\b)/i,/^(?:medium\b)/i,/^(?:high\b)/i,/^(?:analysis\b)/i,/^(?:demonstration\b)/i,/^(?:inspection\b)/i,/^(?:test\b)/i,/^(?:element\b)/i,/^(?:contains\b)/i,/^(?:copies\b)/i,/^(?:derives\b)/i,/^(?:satisfies\b)/i,/^(?:verifies\b)/i,/^(?:refines\b)/i,/^(?:traces\b)/i,/^(?:type\b)/i,/^(?:docref\b)/i,/^(?:<-)/i,/^(?:->)/i,/^(?:-)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[\w][^\r\n\{\<\>\-\=]*)/i],conditions:{acc_descr_multiline:{rules:[6,7],inclusive:!1},acc_descr:{rules:[4],inclusive:!1},acc_title:{rules:[2],inclusive:!1},unqString:{rules:[],inclusive:!1},token:{rules:[],inclusive:!1},string:{rules:[48,49],inclusive:!1},INITIAL:{rules:[0,1,3,5,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,50],inclusive:!0}}}}();function V(){this.yy={}}return D.lexer=P,(0,n.K2)(V,"Parser"),V.prototype=D,D.Parser=V,new V}();l.parser=l;var o=l,h=[],c={},u=new Map,d={},y=new Map,p=(0,n.K2)(((t,e)=>(u.has(t)||u.set(t,{name:t,type:e,id:c.id,text:c.text,risk:c.risk,verifyMethod:c.verifyMethod}),c={},u.get(t))),"addRequirement"),_=(0,n.K2)((()=>u),"getRequirements"),g=(0,n.K2)((t=>{void 0!==c&&(c.id=t)}),"setNewReqId"),E=(0,n.K2)((t=>{void 0!==c&&(c.text=t)}),"setNewReqText"),R=(0,n.K2)((t=>{void 0!==c&&(c.risk=t)}),"setNewReqRisk"),m=(0,n.K2)((t=>{void 0!==c&&(c.verifyMethod=t)}),"setNewReqVerifyMethod"),f=(0,n.K2)((t=>(y.has(t)||(y.set(t,{name:t,type:d.type,docRef:d.docRef}),n.Rm.info("Added new requirement: ",t)),d={},y.get(t))),"addElement"),I=(0,n.K2)((()=>y),"getElements"),S=(0,n.K2)((t=>{void 0!==d&&(d.type=t)}),"setNewElementType"),N=(0,n.K2)((t=>{void 0!==d&&(d.docRef=t)}),"setNewElementDocRef"),b=(0,n.K2)(((t,e,i)=>{h.push({type:t,src:e,dst:i})}),"addRelationship"),k=(0,n.K2)((()=>h),"getRelationships"),T=(0,n.K2)((()=>{h=[],c={},u=new Map,d={},y=new Map,(0,n.IU)()}),"clear"),x={RequirementType:{REQUIREMENT:"Requirement",FUNCTIONAL_REQUIREMENT:"Functional Requirement",INTERFACE_REQUIREMENT:"Interface Requirement",PERFORMANCE_REQUIREMENT:"Performance Requirement",PHYSICAL_REQUIREMENT:"Physical Requirement",DESIGN_CONSTRAINT:"Design Constraint"},RiskLevel:{LOW_RISK:"Low",MED_RISK:"Medium",HIGH_RISK:"High"},VerifyType:{VERIFY_ANALYSIS:"Analysis",VERIFY_DEMONSTRATION:"Demonstration",VERIFY_INSPECTION:"Inspection",VERIFY_TEST:"Test"},Relationships:{CONTAINS:"contains",COPIES:"copies",DERIVES:"derives",SATISFIES:"satisfies",VERIFIES:"verifies",REFINES:"refines",TRACES:"traces"},getConfig:(0,n.K2)((()=>(0,n.D7)().req),"getConfig"),addRequirement:p,getRequirements:_,setNewReqId:g,setNewReqText:E,setNewReqRisk:R,setNewReqVerifyMethod:m,setAccTitle:n.SV,getAccTitle:n.iN,setAccDescription:n.EI,getAccDescription:n.m7,addElement:f,getElements:I,setNewElementType:S,setNewElementDocRef:N,addRelationship:b,getRelationships:k,clear:T},w=(0,n.K2)((t=>`\n\n marker {\n fill: ${t.relationColor};\n stroke: ${t.relationColor};\n }\n\n marker.cross {\n stroke: ${t.lineColor};\n }\n\n svg {\n font-family: ${t.fontFamily};\n font-size: ${t.fontSize};\n }\n\n .reqBox {\n fill: ${t.requirementBackground};\n fill-opacity: 1.0;\n stroke: ${t.requirementBorderColor};\n stroke-width: ${t.requirementBorderSize};\n }\n \n .reqTitle, .reqLabel{\n fill: ${t.requirementTextColor};\n }\n .reqLabelBox {\n fill: ${t.relationLabelBackground};\n fill-opacity: 1.0;\n }\n\n .req-title-line {\n stroke: ${t.requirementBorderColor};\n stroke-width: ${t.requirementBorderSize};\n }\n .relationshipLine {\n stroke: ${t.relationColor};\n stroke-width: 1;\n }\n .relationshipLabel {\n fill: ${t.relationLabelColor};\n }\n\n`),"getStyles"),A={CONTAINS:"contains",ARROW:"arrow"},q={ReqMarkers:A,insertLineEndings:(0,n.K2)(((t,e)=>{let i=t.append("defs").append("marker").attr("id",A.CONTAINS+"_line_ending").attr("refX",0).attr("refY",e.line_height/2).attr("markerWidth",e.line_height).attr("markerHeight",e.line_height).attr("orient","auto").append("g");i.append("circle").attr("cx",e.line_height/2).attr("cy",e.line_height/2).attr("r",e.line_height/2).attr("fill","none"),i.append("line").attr("x1",0).attr("x2",e.line_height).attr("y1",e.line_height/2).attr("y2",e.line_height/2).attr("stroke-width",1),i.append("line").attr("y1",0).attr("y2",e.line_height).attr("x1",e.line_height/2).attr("x2",e.line_height/2).attr("stroke-width",1),t.append("defs").append("marker").attr("id",A.ARROW+"_line_ending").attr("refX",e.line_height).attr("refY",.5*e.line_height).attr("markerWidth",e.line_height).attr("markerHeight",e.line_height).attr("orient","auto").append("path").attr("d",`M0,0\n L${e.line_height},${e.line_height/2}\n M${e.line_height},${e.line_height/2}\n L0,${e.line_height}`).attr("stroke-width",1)}),"insertLineEndings")},v={},K=0,$=(0,n.K2)(((t,e)=>t.insert("rect","#"+e).attr("class","req reqBox").attr("x",0).attr("y",0).attr("width",v.rect_min_width+"px").attr("height",v.rect_min_height+"px")),"newRectNode"),O=(0,n.K2)(((t,e,i)=>{let n=v.rect_min_width/2,r=t.append("text").attr("class","req reqLabel reqTitle").attr("id",e).attr("x",n).attr("y",v.rect_padding).attr("dominant-baseline","hanging"),s=0;i.forEach((t=>{0==s?r.append("tspan").attr("text-anchor","middle").attr("x",v.rect_min_width/2).attr("dy",0).text(t):r.append("tspan").attr("text-anchor","middle").attr("x",v.rect_min_width/2).attr("dy",.75*v.line_height).text(t),s++}));let a=1.5*v.rect_padding+s*v.line_height*.75;return t.append("line").attr("class","req-title-line").attr("x1","0").attr("x2",v.rect_min_width).attr("y1",a).attr("y2",a),{titleNode:r,y:a}}),"newTitleNode"),L=(0,n.K2)(((t,e,i,n)=>{let r=t.append("text").attr("class","req reqLabel").attr("id",e).attr("x",v.rect_padding).attr("y",n).attr("dominant-baseline","hanging"),s=0;let a=[];return i.forEach((t=>{let e=t.length;for(;e>30&&s<3;){let i=t.substring(0,30);e=(t=t.substring(30,t.length)).length,a[a.length]=i,s++}if(3==s){let t=a[a.length-1];a[a.length-1]=t.substring(0,t.length-4)+"..."}else a[a.length]=t;s=0})),a.forEach((t=>{r.append("tspan").attr("x",v.rect_padding).attr("dy",v.line_height).text(t)})),r}),"newBodyNode"),C=(0,n.K2)(((t,e,i,n)=>{const r=e.node().getTotalLength(),s=e.node().getPointAtLength(.5*r),a="rel"+K;K++;const l=t.append("text").attr("class","req relationshipLabel").attr("id",a).attr("x",s.x).attr("y",s.y).attr("text-anchor","middle").attr("dominant-baseline","middle").text(n).node().getBBox();t.insert("rect","#"+a).attr("class","req reqLabelBox").attr("x",s.x-l.width/2).attr("y",s.y-l.height/2).attr("width",l.width).attr("height",l.height).attr("fill","white").attr("fill-opacity","85%")}),"addEdgeLabel"),M=(0,n.K2)((function(t,e,i,s,a){const l=i.edge(U(e.src),U(e.dst)),o=(0,r.n8j)().x((function(t){return t.x})).y((function(t){return t.y})),h=t.insert("path","#"+s).attr("class","er relationshipLine").attr("d",o(l.points)).attr("fill","none");e.type==a.db.Relationships.CONTAINS?h.attr("marker-start","url("+n.Y2.getUrl(v.arrowMarkerAbsolute)+"#"+e.type+"_line_ending)"):(h.attr("stroke-dasharray","10,7"),h.attr("marker-end","url("+n.Y2.getUrl(v.arrowMarkerAbsolute)+"#"+q.ReqMarkers.ARROW+"_line_ending)")),C(t,h,v,`<<${e.type}>>`)}),"drawRelationshipFromLayout"),F=(0,n.K2)(((t,e,i)=>{t.forEach(((t,r)=>{r=U(r),n.Rm.info("Added new requirement: ",r);const s=i.append("g").attr("id",r),a=$(s,"req-"+r);let l=[],o=O(s,r+"_title",[`<<${t.type}>>`,`${t.name}`]);l.push(o.titleNode);let h=L(s,r+"_body",[`Id: ${t.id}`,`Text: ${t.text}`,`Risk: ${t.risk}`,`Verification: ${t.verifyMethod}`],o.y);l.push(h);const c=a.node().getBBox();e.setNode(r,{width:c.width,height:c.height,shape:"rect",id:r})}))}),"drawReqs"),D=(0,n.K2)(((t,e,i)=>{t.forEach(((t,n)=>{const r=U(n),s=i.append("g").attr("id",r),a="element-"+r,l=$(s,a);let o=[],h=O(s,a+"_title",["<<Element>>",`${n}`]);o.push(h.titleNode);let c=L(s,a+"_body",[`Type: ${t.type||"Not Specified"}`,`Doc Ref: ${t.docRef||"None"}`],h.y);o.push(c);const u=l.node().getBBox();e.setNode(r,{width:u.width,height:u.height,shape:"rect",id:r})}))}),"drawElements"),P=(0,n.K2)(((t,e)=>(t.forEach((function(t){let i=U(t.src),n=U(t.dst);e.setEdge(i,n,{relationship:t})})),t)),"addRelationships"),V=(0,n.K2)((function(t,e){e.nodes().forEach((function(i){void 0!==i&&void 0!==e.node(i)&&(t.select("#"+i),t.select("#"+i).attr("transform","translate("+(e.node(i).x-e.node(i).width/2)+","+(e.node(i).y-e.node(i).height/2)+" )"))}))}),"adjustEntities"),U=(0,n.K2)((t=>t.replace(/\s/g,"").replace(/\./g,"_")),"elementString"),Y={parser:o,db:x,renderer:{draw:(0,n.K2)(((t,e,i,l)=>{const o=(v=(0,n.D7)().requirement).securityLevel;let h;"sandbox"===o&&(h=(0,r.Ltv)("#i"+e));const c=("sandbox"===o?(0,r.Ltv)(h.nodes()[0].contentDocument.body):(0,r.Ltv)("body")).select(`[id='${e}']`);q.insertLineEndings(c,v);const u=new a.T({multigraph:!1,compound:!1,directed:!0}).setGraph({rankdir:v.layoutDirection,marginx:20,marginy:20,nodesep:100,edgesep:100,ranksep:100}).setDefaultEdgeLabel((function(){return{}}));let d=l.db.getRequirements(),y=l.db.getElements(),p=l.db.getRelationships();F(d,u,c),D(y,u,c),P(p,u),(0,s.Zp)(u),V(c,u),p.forEach((function(t){M(c,t,u,e,l)}));const _=v.rect_padding,g=c.node().getBBox(),E=g.width+2*_,R=g.height+2*_;(0,n.a$)(c,R,E,v.useMaxWidth),c.attr("viewBox",`${g.x-_} ${g.y-_} ${E} ${R}`)}),"draw")},styles:w}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/84cf2b87.f72f7a7f.js b/pr-preview/pr-1071/assets/js/84cf2b87.f72f7a7f.js deleted file mode 100644 index e77edf7c37..0000000000 --- a/pr-preview/pr-1071/assets/js/84cf2b87.f72f7a7f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4411],{91892:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.7","label":"0.7","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.7","isLast":false,"docsSidebars":{"docs":[{"type":"category","label":"What is Contrast?","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/0.7/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.7/"},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/0.7/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false}],"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.7/getting-started/"},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.7/examples/"},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/0.7/deployment","docId":"deployment","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/0.7/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/0.7/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/0.7/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.7/components/"},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/0.7/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/0.7/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/0.7/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.7/architecture/"},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/0.7/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/0.7/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.7/about/"}]},"docs":{"about/index":{"id":"about/index","title":"About","description":"","sidebar":"docs"},"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/index":{"id":"architecture/index","title":"Architecture","description":"","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/index":{"id":"components/index","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"examples/index":{"id":"examples/index","title":"Examples","description":"","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/index":{"id":"getting-started/index","title":"Getting started","description":"","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8540.517c5c64.js b/pr-preview/pr-1071/assets/js/8540.517c5c64.js deleted file mode 100644 index f728d3d1e5..0000000000 --- a/pr-preview/pr-1071/assets/js/8540.517c5c64.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8540],{83814:(t,e,a)=>{a.d(e,{CP:()=>l,HT:()=>h,PB:()=>d,aC:()=>c,lC:()=>n,m:()=>o,tk:()=>i});var r=a(10009),s=a(16750),i=(0,r.K2)(((t,e)=>{const a=t.append("rect");if(a.attr("x",e.x),a.attr("y",e.y),a.attr("fill",e.fill),a.attr("stroke",e.stroke),a.attr("width",e.width),a.attr("height",e.height),e.name&&a.attr("name",e.name),e.rx&&a.attr("rx",e.rx),e.ry&&a.attr("ry",e.ry),void 0!==e.attrs)for(const r in e.attrs)a.attr(r,e.attrs[r]);return e.class&&a.attr("class",e.class),a}),"drawRect"),n=(0,r.K2)(((t,e)=>{const a={x:e.startx,y:e.starty,width:e.stopx-e.startx,height:e.stopy-e.starty,fill:e.fill,stroke:e.stroke,class:"rect"};i(t,a).lower()}),"drawBackgroundRect"),o=(0,r.K2)(((t,e)=>{const a=e.text.replace(r.H1," "),s=t.append("text");s.attr("x",e.x),s.attr("y",e.y),s.attr("class","legend"),s.style("text-anchor",e.anchor),e.class&&s.attr("class",e.class);const i=s.append("tspan");return i.attr("x",e.x+2*e.textMargin),i.text(a),s}),"drawText"),c=(0,r.K2)(((t,e,a,r)=>{const i=t.append("image");i.attr("x",e),i.attr("y",a);const n=(0,s.J)(r);i.attr("xlink:href",n)}),"drawImage"),l=(0,r.K2)(((t,e,a,r)=>{const i=t.append("use");i.attr("x",e),i.attr("y",a);const n=(0,s.J)(r);i.attr("xlink:href",`#${n}`)}),"drawEmbeddedImage"),d=(0,r.K2)((()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0})),"getNoteRect"),h=(0,r.K2)((()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0})),"getTextObj")},98160:(t,e,a)=>{a.d(e,{m:()=>s});var r=a(10009),s=class{constructor(t){this.init=t,this.records=this.init()}static{(0,r.K2)(this,"ImperativeState")}reset(){this.records=this.init()}}},58540:(t,e,a)=>{a.d(e,{diagram:()=>Ut});var r=a(83814),s=a(98160),i=a(8159),n=a(10009),o=a(20007),c=a(16750),l=function(){var t=(0,n.K2)((function(t,e,a,r){for(a=a||{},r=t.length;r--;a[t[r]]=e);return a}),"o"),e=[1,2],a=[1,3],r=[1,4],s=[2,4],i=[1,9],o=[1,11],c=[1,13],l=[1,14],d=[1,16],h=[1,17],p=[1,18],g=[1,24],u=[1,25],x=[1,26],y=[1,27],m=[1,28],b=[1,29],T=[1,30],f=[1,31],E=[1,32],w=[1,33],I=[1,34],L=[1,35],_=[1,36],P=[1,37],k=[1,38],A=[1,39],v=[1,41],N=[1,42],M=[1,43],D=[1,44],O=[1,45],S=[1,46],K=[1,4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,48,49,50,52,53,54,59,60,61,62,70],R=[4,5,16,50,52,53],Y=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],C=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,49,50,52,53,54,59,60,61,62,70],B=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,48,50,52,53,54,59,60,61,62,70],$=[4,5,13,14,16,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,47,50,52,53,54,59,60,61,62,70],V=[68,69,70],F=[1,122],W={trace:(0,n.K2)((function(){}),"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,SD:6,document:7,line:8,statement:9,box_section:10,box_line:11,participant_statement:12,create:13,box:14,restOfLine:15,end:16,signal:17,autonumber:18,NUM:19,off:20,activate:21,actor:22,deactivate:23,note_statement:24,links_statement:25,link_statement:26,properties_statement:27,details_statement:28,title:29,legacy_title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,loop:36,rect:37,opt:38,alt:39,else_sections:40,par:41,par_sections:42,par_over:43,critical:44,option_sections:45,break:46,option:47,and:48,else:49,participant:50,AS:51,participant_actor:52,destroy:53,note:54,placement:55,text2:56,over:57,actor_pair:58,links:59,link:60,properties:61,details:62,spaceList:63,",":64,left_of:65,right_of:66,signaltype:67,"+":68,"-":69,ACTOR:70,SOLID_OPEN_ARROW:71,DOTTED_OPEN_ARROW:72,SOLID_ARROW:73,BIDIRECTIONAL_SOLID_ARROW:74,DOTTED_ARROW:75,BIDIRECTIONAL_DOTTED_ARROW:76,SOLID_CROSS:77,DOTTED_CROSS:78,SOLID_POINT:79,DOTTED_POINT:80,TXT:81,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",6:"SD",13:"create",14:"box",15:"restOfLine",16:"end",18:"autonumber",19:"NUM",20:"off",21:"activate",23:"deactivate",29:"title",30:"legacy_title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"loop",37:"rect",38:"opt",39:"alt",41:"par",43:"par_over",44:"critical",46:"break",47:"option",48:"and",49:"else",50:"participant",51:"AS",52:"participant_actor",53:"destroy",54:"note",57:"over",59:"links",60:"link",61:"properties",62:"details",64:",",65:"left_of",66:"right_of",68:"+",69:"-",70:"ACTOR",71:"SOLID_OPEN_ARROW",72:"DOTTED_OPEN_ARROW",73:"SOLID_ARROW",74:"BIDIRECTIONAL_SOLID_ARROW",75:"DOTTED_ARROW",76:"BIDIRECTIONAL_DOTTED_ARROW",77:"SOLID_CROSS",78:"DOTTED_CROSS",79:"SOLID_POINT",80:"DOTTED_POINT",81:"TXT"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[10,0],[10,2],[11,2],[11,1],[11,1],[9,1],[9,2],[9,4],[9,2],[9,4],[9,3],[9,3],[9,2],[9,3],[9,3],[9,2],[9,2],[9,2],[9,2],[9,2],[9,1],[9,1],[9,2],[9,2],[9,1],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[9,4],[45,1],[45,4],[42,1],[42,4],[40,1],[40,4],[12,5],[12,3],[12,5],[12,3],[12,3],[24,4],[24,4],[25,3],[26,3],[27,3],[28,3],[63,2],[63,1],[58,3],[58,1],[55,1],[55,1],[17,5],[17,5],[17,4],[22,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[67,1],[56,1]],performAction:(0,n.K2)((function(t,e,a,r,s,i,n){var o=i.length-1;switch(s){case 3:return r.apply(i[o]),i[o];case 4:case 9:case 8:case 13:this.$=[];break;case 5:case 10:i[o-1].push(i[o]),this.$=i[o-1];break;case 6:case 7:case 11:case 12:case 62:this.$=i[o];break;case 15:i[o].type="createParticipant",this.$=i[o];break;case 16:i[o-1].unshift({type:"boxStart",boxData:r.parseBoxData(i[o-2])}),i[o-1].push({type:"boxEnd",boxText:i[o-2]}),this.$=i[o-1];break;case 18:this.$={type:"sequenceIndex",sequenceIndex:Number(i[o-2]),sequenceIndexStep:Number(i[o-1]),sequenceVisible:!0,signalType:r.LINETYPE.AUTONUMBER};break;case 19:this.$={type:"sequenceIndex",sequenceIndex:Number(i[o-1]),sequenceIndexStep:1,sequenceVisible:!0,signalType:r.LINETYPE.AUTONUMBER};break;case 20:this.$={type:"sequenceIndex",sequenceVisible:!1,signalType:r.LINETYPE.AUTONUMBER};break;case 21:this.$={type:"sequenceIndex",sequenceVisible:!0,signalType:r.LINETYPE.AUTONUMBER};break;case 22:this.$={type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:i[o-1].actor};break;case 23:this.$={type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:i[o-1].actor};break;case 29:r.setDiagramTitle(i[o].substring(6)),this.$=i[o].substring(6);break;case 30:r.setDiagramTitle(i[o].substring(7)),this.$=i[o].substring(7);break;case 31:this.$=i[o].trim(),r.setAccTitle(this.$);break;case 32:case 33:this.$=i[o].trim(),r.setAccDescription(this.$);break;case 34:i[o-1].unshift({type:"loopStart",loopText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.LOOP_START}),i[o-1].push({type:"loopEnd",loopText:i[o-2],signalType:r.LINETYPE.LOOP_END}),this.$=i[o-1];break;case 35:i[o-1].unshift({type:"rectStart",color:r.parseMessage(i[o-2]),signalType:r.LINETYPE.RECT_START}),i[o-1].push({type:"rectEnd",color:r.parseMessage(i[o-2]),signalType:r.LINETYPE.RECT_END}),this.$=i[o-1];break;case 36:i[o-1].unshift({type:"optStart",optText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.OPT_START}),i[o-1].push({type:"optEnd",optText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.OPT_END}),this.$=i[o-1];break;case 37:i[o-1].unshift({type:"altStart",altText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.ALT_START}),i[o-1].push({type:"altEnd",signalType:r.LINETYPE.ALT_END}),this.$=i[o-1];break;case 38:i[o-1].unshift({type:"parStart",parText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.PAR_START}),i[o-1].push({type:"parEnd",signalType:r.LINETYPE.PAR_END}),this.$=i[o-1];break;case 39:i[o-1].unshift({type:"parStart",parText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.PAR_OVER_START}),i[o-1].push({type:"parEnd",signalType:r.LINETYPE.PAR_END}),this.$=i[o-1];break;case 40:i[o-1].unshift({type:"criticalStart",criticalText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.CRITICAL_START}),i[o-1].push({type:"criticalEnd",signalType:r.LINETYPE.CRITICAL_END}),this.$=i[o-1];break;case 41:i[o-1].unshift({type:"breakStart",breakText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.BREAK_START}),i[o-1].push({type:"breakEnd",optText:r.parseMessage(i[o-2]),signalType:r.LINETYPE.BREAK_END}),this.$=i[o-1];break;case 43:this.$=i[o-3].concat([{type:"option",optionText:r.parseMessage(i[o-1]),signalType:r.LINETYPE.CRITICAL_OPTION},i[o]]);break;case 45:this.$=i[o-3].concat([{type:"and",parText:r.parseMessage(i[o-1]),signalType:r.LINETYPE.PAR_AND},i[o]]);break;case 47:this.$=i[o-3].concat([{type:"else",altText:r.parseMessage(i[o-1]),signalType:r.LINETYPE.ALT_ELSE},i[o]]);break;case 48:i[o-3].draw="participant",i[o-3].type="addParticipant",i[o-3].description=r.parseMessage(i[o-1]),this.$=i[o-3];break;case 49:i[o-1].draw="participant",i[o-1].type="addParticipant",this.$=i[o-1];break;case 50:i[o-3].draw="actor",i[o-3].type="addParticipant",i[o-3].description=r.parseMessage(i[o-1]),this.$=i[o-3];break;case 51:i[o-1].draw="actor",i[o-1].type="addParticipant",this.$=i[o-1];break;case 52:i[o-1].type="destroyParticipant",this.$=i[o-1];break;case 53:this.$=[i[o-1],{type:"addNote",placement:i[o-2],actor:i[o-1].actor,text:i[o]}];break;case 54:i[o-2]=[].concat(i[o-1],i[o-1]).slice(0,2),i[o-2][0]=i[o-2][0].actor,i[o-2][1]=i[o-2][1].actor,this.$=[i[o-1],{type:"addNote",placement:r.PLACEMENT.OVER,actor:i[o-2].slice(0,2),text:i[o]}];break;case 55:this.$=[i[o-1],{type:"addLinks",actor:i[o-1].actor,text:i[o]}];break;case 56:this.$=[i[o-1],{type:"addALink",actor:i[o-1].actor,text:i[o]}];break;case 57:this.$=[i[o-1],{type:"addProperties",actor:i[o-1].actor,text:i[o]}];break;case 58:this.$=[i[o-1],{type:"addDetails",actor:i[o-1].actor,text:i[o]}];break;case 61:this.$=[i[o-2],i[o]];break;case 63:this.$=r.PLACEMENT.LEFTOF;break;case 64:this.$=r.PLACEMENT.RIGHTOF;break;case 65:this.$=[i[o-4],i[o-1],{type:"addMessage",from:i[o-4].actor,to:i[o-1].actor,signalType:i[o-3],msg:i[o],activate:!0},{type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:i[o-1].actor}];break;case 66:this.$=[i[o-4],i[o-1],{type:"addMessage",from:i[o-4].actor,to:i[o-1].actor,signalType:i[o-3],msg:i[o]},{type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:i[o-4].actor}];break;case 67:this.$=[i[o-3],i[o-1],{type:"addMessage",from:i[o-3].actor,to:i[o-1].actor,signalType:i[o-2],msg:i[o]}];break;case 68:this.$={type:"addParticipant",actor:i[o]};break;case 69:this.$=r.LINETYPE.SOLID_OPEN;break;case 70:this.$=r.LINETYPE.DOTTED_OPEN;break;case 71:this.$=r.LINETYPE.SOLID;break;case 72:this.$=r.LINETYPE.BIDIRECTIONAL_SOLID;break;case 73:this.$=r.LINETYPE.DOTTED;break;case 74:this.$=r.LINETYPE.BIDIRECTIONAL_DOTTED;break;case 75:this.$=r.LINETYPE.SOLID_CROSS;break;case 76:this.$=r.LINETYPE.DOTTED_CROSS;break;case 77:this.$=r.LINETYPE.SOLID_POINT;break;case 78:this.$=r.LINETYPE.DOTTED_POINT;break;case 79:this.$=r.parseMessage(i[o].trim().substring(1))}}),"anonymous"),table:[{3:1,4:e,5:a,6:r},{1:[3]},{3:5,4:e,5:a,6:r},{3:6,4:e,5:a,6:r},t([1,4,5,13,14,18,21,23,29,30,31,33,35,36,37,38,39,41,43,44,46,50,52,53,54,59,60,61,62,70],s,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:i,5:o,8:8,9:10,12:12,13:c,14:l,17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},t(K,[2,5]),{9:47,12:12,13:c,14:l,17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},t(K,[2,7]),t(K,[2,8]),t(K,[2,14]),{12:48,50:P,52:k,53:A},{15:[1,49]},{5:[1,50]},{5:[1,53],19:[1,51],20:[1,52]},{22:54,70:S},{22:55,70:S},{5:[1,56]},{5:[1,57]},{5:[1,58]},{5:[1,59]},{5:[1,60]},t(K,[2,29]),t(K,[2,30]),{32:[1,61]},{34:[1,62]},t(K,[2,33]),{15:[1,63]},{15:[1,64]},{15:[1,65]},{15:[1,66]},{15:[1,67]},{15:[1,68]},{15:[1,69]},{15:[1,70]},{22:71,70:S},{22:72,70:S},{22:73,70:S},{67:74,71:[1,75],72:[1,76],73:[1,77],74:[1,78],75:[1,79],76:[1,80],77:[1,81],78:[1,82],79:[1,83],80:[1,84]},{55:85,57:[1,86],65:[1,87],66:[1,88]},{22:89,70:S},{22:90,70:S},{22:91,70:S},{22:92,70:S},t([5,51,64,71,72,73,74,75,76,77,78,79,80,81],[2,68]),t(K,[2,6]),t(K,[2,15]),t(R,[2,9],{10:93}),t(K,[2,17]),{5:[1,95],19:[1,94]},{5:[1,96]},t(K,[2,21]),{5:[1,97]},{5:[1,98]},t(K,[2,24]),t(K,[2,25]),t(K,[2,26]),t(K,[2,27]),t(K,[2,28]),t(K,[2,31]),t(K,[2,32]),t(Y,s,{7:99}),t(Y,s,{7:100}),t(Y,s,{7:101}),t(C,s,{40:102,7:103}),t(B,s,{42:104,7:105}),t(B,s,{7:105,42:106}),t($,s,{45:107,7:108}),t(Y,s,{7:109}),{5:[1,111],51:[1,110]},{5:[1,113],51:[1,112]},{5:[1,114]},{22:117,68:[1,115],69:[1,116],70:S},t(V,[2,69]),t(V,[2,70]),t(V,[2,71]),t(V,[2,72]),t(V,[2,73]),t(V,[2,74]),t(V,[2,75]),t(V,[2,76]),t(V,[2,77]),t(V,[2,78]),{22:118,70:S},{22:120,58:119,70:S},{70:[2,63]},{70:[2,64]},{56:121,81:F},{56:123,81:F},{56:124,81:F},{56:125,81:F},{4:[1,128],5:[1,130],11:127,12:129,16:[1,126],50:P,52:k,53:A},{5:[1,131]},t(K,[2,19]),t(K,[2,20]),t(K,[2,22]),t(K,[2,23]),{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[1,132],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[1,133],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[1,134],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{16:[1,135]},{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[2,46],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,49:[1,136],50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{16:[1,137]},{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[2,44],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,48:[1,138],50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{16:[1,139]},{16:[1,140]},{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[2,42],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,47:[1,141],50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{4:i,5:o,8:8,9:10,12:12,13:c,14:l,16:[1,142],17:15,18:d,21:h,22:40,23:p,24:19,25:20,26:21,27:22,28:23,29:g,30:u,31:x,33:y,35:m,36:b,37:T,38:f,39:E,41:w,43:I,44:L,46:_,50:P,52:k,53:A,54:v,59:N,60:M,61:D,62:O,70:S},{15:[1,143]},t(K,[2,49]),{15:[1,144]},t(K,[2,51]),t(K,[2,52]),{22:145,70:S},{22:146,70:S},{56:147,81:F},{56:148,81:F},{56:149,81:F},{64:[1,150],81:[2,62]},{5:[2,55]},{5:[2,79]},{5:[2,56]},{5:[2,57]},{5:[2,58]},t(K,[2,16]),t(R,[2,10]),{12:151,50:P,52:k,53:A},t(R,[2,12]),t(R,[2,13]),t(K,[2,18]),t(K,[2,34]),t(K,[2,35]),t(K,[2,36]),t(K,[2,37]),{15:[1,152]},t(K,[2,38]),{15:[1,153]},t(K,[2,39]),t(K,[2,40]),{15:[1,154]},t(K,[2,41]),{5:[1,155]},{5:[1,156]},{56:157,81:F},{56:158,81:F},{5:[2,67]},{5:[2,53]},{5:[2,54]},{22:159,70:S},t(R,[2,11]),t(C,s,{7:103,40:160}),t(B,s,{7:105,42:161}),t($,s,{7:108,45:162}),t(K,[2,48]),t(K,[2,50]),{5:[2,65]},{5:[2,66]},{81:[2,61]},{16:[2,47]},{16:[2,45]},{16:[2,43]}],defaultActions:{5:[2,1],6:[2,2],87:[2,63],88:[2,64],121:[2,55],122:[2,79],123:[2,56],124:[2,57],125:[2,58],147:[2,67],148:[2,53],149:[2,54],157:[2,65],158:[2,66],159:[2,61],160:[2,47],161:[2,45],162:[2,43]},parseError:(0,n.K2)((function(t,e){if(!e.recoverable){var a=new Error(t);throw a.hash=e,a}this.trace(t)}),"parseError"),parse:(0,n.K2)((function(t){var e=this,a=[0],r=[],s=[null],i=[],o=this.table,c="",l=0,d=0,h=0,p=i.slice.call(arguments,1),g=Object.create(this.lexer),u={yy:{}};for(var x in this.yy)Object.prototype.hasOwnProperty.call(this.yy,x)&&(u.yy[x]=this.yy[x]);g.setInput(t,u.yy),u.yy.lexer=g,u.yy.parser=this,void 0===g.yylloc&&(g.yylloc={});var y=g.yylloc;i.push(y);var m=g.options&&g.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||g.lex()||1)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof u.yy.parseError?this.parseError=u.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError,(0,n.K2)((function(t){a.length=a.length-2*t,s.length=s.length-t,i.length=i.length-t}),"popStack"),(0,n.K2)(b,"lex");for(var T,f,E,w,I,L,_,P,k,A={};;){if(E=a[a.length-1],this.defaultActions[E]?w=this.defaultActions[E]:(null==T&&(T=b()),w=o[E]&&o[E][T]),void 0===w||!w.length||!w[0]){var v="";for(L in k=[],o[E])this.terminals_[L]&&L>2&&k.push("'"+this.terminals_[L]+"'");v=g.showPosition?"Parse error on line "+(l+1)+":\n"+g.showPosition()+"\nExpecting "+k.join(", ")+", got '"+(this.terminals_[T]||T)+"'":"Parse error on line "+(l+1)+": Unexpected "+(1==T?"end of input":"'"+(this.terminals_[T]||T)+"'"),this.parseError(v,{text:g.match,token:this.terminals_[T]||T,line:g.yylineno,loc:y,expected:k})}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+E+", token: "+T);switch(w[0]){case 1:a.push(T),s.push(g.yytext),i.push(g.yylloc),a.push(w[1]),T=null,f?(T=f,f=null):(d=g.yyleng,c=g.yytext,l=g.yylineno,y=g.yylloc,h>0&&h--);break;case 2:if(_=this.productions_[w[1]][1],A.$=s[s.length-_],A._$={first_line:i[i.length-(_||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(_||1)].first_column,last_column:i[i.length-1].last_column},m&&(A._$.range=[i[i.length-(_||1)].range[0],i[i.length-1].range[1]]),void 0!==(I=this.performAction.apply(A,[c,d,l,u.yy,w[1],s,i].concat(p))))return I;_&&(a=a.slice(0,-1*_*2),s=s.slice(0,-1*_),i=i.slice(0,-1*_)),a.push(this.productions_[w[1]][0]),s.push(A.$),i.push(A._$),P=o[a[a.length-2]][a[a.length-1]],a.push(P);break;case 3:return!0}}return!0}),"parse")},q=function(){return{EOF:1,parseError:(0,n.K2)((function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)}),"parseError"),setInput:(0,n.K2)((function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this}),"setInput"),input:(0,n.K2)((function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t}),"input"),unput:(0,n.K2)((function(t){var e=t.length,a=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),a.length-1&&(this.yylineno-=a.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:a?(a.length===r.length?this.yylloc.first_column:0)+r[r.length-a.length].length-a[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this}),"unput"),more:(0,n.K2)((function(){return this._more=!0,this}),"more"),reject:(0,n.K2)((function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"reject"),less:(0,n.K2)((function(t){this.unput(this.match.slice(t))}),"less"),pastInput:(0,n.K2)((function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")}),"pastInput"),upcomingInput:(0,n.K2)((function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")}),"upcomingInput"),showPosition:(0,n.K2)((function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"}),"showPosition"),test_match:(0,n.K2)((function(t,e){var a,r,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],a=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a)return a;if(this._backtrack){for(var i in s)this[i]=s[i];return!1}return!1}),"test_match"),next:(0,n.K2)((function(){if(this.done)return this.EOF;var t,e,a,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),i=0;i<s.length;i++)if((a=this._input.match(this.rules[s[i]]))&&(!e||a[0].length>e[0].length)){if(e=a,r=i,this.options.backtrack_lexer){if(!1!==(t=this.test_match(a,s[i])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,s[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}),"next"),lex:(0,n.K2)((function(){var t=this.next();return t||this.lex()}),"lex"),begin:(0,n.K2)((function(t){this.conditionStack.push(t)}),"begin"),popState:(0,n.K2)((function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]}),"popState"),_currentRules:(0,n.K2)((function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules}),"_currentRules"),topState:(0,n.K2)((function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"}),"topState"),pushState:(0,n.K2)((function(t){this.begin(t)}),"pushState"),stateStackSize:(0,n.K2)((function(){return this.conditionStack.length}),"stateStackSize"),options:{"case-insensitive":!0},performAction:(0,n.K2)((function(t,e,a,r){switch(a){case 0:case 51:case 66:return 5;case 1:case 2:case 3:case 4:case 5:break;case 6:return 19;case 7:return this.begin("LINE"),14;case 8:return this.begin("ID"),50;case 9:return this.begin("ID"),52;case 10:return 13;case 11:return this.begin("ID"),53;case 12:return e.yytext=e.yytext.trim(),this.begin("ALIAS"),70;case 13:return this.popState(),this.popState(),this.begin("LINE"),51;case 14:return this.popState(),this.popState(),5;case 15:return this.begin("LINE"),36;case 16:return this.begin("LINE"),37;case 17:return this.begin("LINE"),38;case 18:return this.begin("LINE"),39;case 19:return this.begin("LINE"),49;case 20:return this.begin("LINE"),41;case 21:return this.begin("LINE"),43;case 22:return this.begin("LINE"),48;case 23:return this.begin("LINE"),44;case 24:return this.begin("LINE"),47;case 25:return this.begin("LINE"),46;case 26:return this.popState(),15;case 27:return 16;case 28:return 65;case 29:return 66;case 30:return 59;case 31:return 60;case 32:return 61;case 33:return 62;case 34:return 57;case 35:return 54;case 36:return this.begin("ID"),21;case 37:return this.begin("ID"),23;case 38:return 29;case 39:return 30;case 40:return this.begin("acc_title"),31;case 41:return this.popState(),"acc_title_value";case 42:return this.begin("acc_descr"),33;case 43:return this.popState(),"acc_descr_value";case 44:this.begin("acc_descr_multiline");break;case 45:this.popState();break;case 46:return"acc_descr_multiline_value";case 47:return 6;case 48:return 18;case 49:return 20;case 50:return 64;case 52:return e.yytext=e.yytext.trim(),70;case 53:return 73;case 54:return 74;case 55:return 75;case 56:return 76;case 57:return 71;case 58:return 72;case 59:return 77;case 60:return 78;case 61:return 79;case 62:return 80;case 63:return 81;case 64:return 68;case 65:return 69;case 67:return"INVALID"}}),"anonymous"),rules:[/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[0-9]+(?=[ \n]+))/i,/^(?:box\b)/i,/^(?:participant\b)/i,/^(?:actor\b)/i,/^(?:create\b)/i,/^(?:destroy\b)/i,/^(?:[^\<->\->:\n,;]+?([\-]*[^\<->\->:\n,;]+?)*?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:par_over\b)/i,/^(?:and\b)/i,/^(?:critical\b)/i,/^(?:option\b)/i,/^(?:break\b)/i,/^(?:(?:[:]?(?:no)?wrap)?[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:links\b)/i,/^(?:link\b)/i,/^(?:properties\b)/i,/^(?:details\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:title:\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:sequenceDiagram\b)/i,/^(?:autonumber\b)/i,/^(?:off\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\<->\->:\n,;]+((?!(-x|--x|-\)|--\)))[\-]*[^\+\<->\->:\n,;]+)*)/i,/^(?:->>)/i,/^(?:<<->>)/i,/^(?:-->>)/i,/^(?:<<-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?:-[\)])/i,/^(?:--[\)])/i,/^(?::(?:(?:no)?wrap)?[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[45,46],inclusive:!1},acc_descr:{rules:[43],inclusive:!1},acc_title:{rules:[41],inclusive:!1},ID:{rules:[2,3,12],inclusive:!1},ALIAS:{rules:[2,3,13,14],inclusive:!1},LINE:{rules:[2,3,26],inclusive:!1},INITIAL:{rules:[0,1,3,4,5,6,7,8,9,10,11,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,35,36,37,38,39,40,42,44,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67],inclusive:!0}}}}();function z(){this.yy={}}return W.lexer=q,(0,n.K2)(z,"Parser"),z.prototype=W,W.Parser=z,new z}();l.parser=l;var d=l,h=new s.m((()=>({prevActor:void 0,actors:new Map,createdActors:new Map,destroyedActors:new Map,boxes:[],messages:[],notes:[],sequenceNumbersEnabled:!1,wrapEnabled:void 0,currentBox:void 0,lastCreated:void 0,lastDestroyed:void 0}))),p=(0,n.K2)((function(t){h.records.boxes.push({name:t.text,wrap:t.wrap??M(),fill:t.color,actorKeys:[]}),h.records.currentBox=h.records.boxes.slice(-1)[0]}),"addBox"),g=(0,n.K2)((function(t,e,a,r){let s=h.records.currentBox;const i=h.records.actors.get(t);if(i){if(h.records.currentBox&&i.box&&h.records.currentBox!==i.box)throw new Error(`A same participant should only be defined in one Box: ${i.name} can't be in '${i.box.name}' and in '${h.records.currentBox.name}' at the same time.`);if(s=i.box?i.box:h.records.currentBox,i.box=s,i&&e===i.name&&null==a)return}if(null==a?.text&&(a={text:e,type:r}),null!=r&&null!=a.text||(a={text:e,type:r}),h.records.actors.set(t,{box:s,name:e,description:a.text,wrap:a.wrap??M(),prevActor:h.records.prevActor,links:{},properties:{},actorCnt:null,rectData:null,type:r??"participant"}),h.records.prevActor){const e=h.records.actors.get(h.records.prevActor);e&&(e.nextActor=t)}h.records.currentBox&&h.records.currentBox.actorKeys.push(t),h.records.prevActor=t}),"addActor"),u=(0,n.K2)((t=>{let e,a=0;if(!t)return 0;for(e=0;e<h.records.messages.length;e++)h.records.messages[e].type===K.ACTIVE_START&&h.records.messages[e].from===t&&a++,h.records.messages[e].type===K.ACTIVE_END&&h.records.messages[e].from===t&&a--;return a}),"activationCount"),x=(0,n.K2)((function(t,e,a,r){h.records.messages.push({from:t,to:e,message:a.text,wrap:a.wrap??M(),answer:r})}),"addMessage"),y=(0,n.K2)((function(t,e,a,r,s=!1){if(r===K.ACTIVE_END){if(u(t??"")<1){const e=new Error("Trying to inactivate an inactive participant ("+t+")");throw e.hash={text:"->>-",token:"->>-",line:"1",loc:{first_line:1,last_line:1,first_column:1,last_column:1},expected:["'ACTIVE_PARTICIPANT'"]},e}}return h.records.messages.push({from:t,to:e,message:a?.text??"",wrap:a?.wrap??M(),type:r,activate:s}),!0}),"addSignal"),m=(0,n.K2)((function(){return h.records.boxes.length>0}),"hasAtLeastOneBox"),b=(0,n.K2)((function(){return h.records.boxes.some((t=>t.name))}),"hasAtLeastOneBoxWithTitle"),T=(0,n.K2)((function(){return h.records.messages}),"getMessages"),f=(0,n.K2)((function(){return h.records.boxes}),"getBoxes"),E=(0,n.K2)((function(){return h.records.actors}),"getActors"),w=(0,n.K2)((function(){return h.records.createdActors}),"getCreatedActors"),I=(0,n.K2)((function(){return h.records.destroyedActors}),"getDestroyedActors"),L=(0,n.K2)((function(t){return h.records.actors.get(t)}),"getActor"),_=(0,n.K2)((function(){return[...h.records.actors.keys()]}),"getActorKeys"),P=(0,n.K2)((function(){h.records.sequenceNumbersEnabled=!0}),"enableSequenceNumbers"),k=(0,n.K2)((function(){h.records.sequenceNumbersEnabled=!1}),"disableSequenceNumbers"),A=(0,n.K2)((()=>h.records.sequenceNumbersEnabled),"showSequenceNumbers"),v=(0,n.K2)((function(t){h.records.wrapEnabled=t}),"setWrap"),N=(0,n.K2)((t=>{if(void 0===t)return{};t=t.trim();const e=null!==/^:?wrap:/.exec(t)||null===/^:?nowrap:/.exec(t)&&void 0;return{cleanedText:(void 0===e?t:t.replace(/^:?(?:no)?wrap:/,"")).trim(),wrap:e}}),"extractWrap"),M=(0,n.K2)((()=>void 0!==h.records.wrapEnabled?h.records.wrapEnabled:(0,n.D7)().sequence?.wrap??!1),"autoWrap"),D=(0,n.K2)((function(){h.reset(),(0,n.IU)()}),"clear"),O=(0,n.K2)((function(t){const e=t.trim(),{wrap:a,cleanedText:r}=N(e),s={text:r,wrap:a};return n.Rm.debug(`parseMessage: ${JSON.stringify(s)}`),s}),"parseMessage"),S=(0,n.K2)((function(t){const e=/^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/.exec(t);let a=e?.[1]?e[1].trim():"transparent",r=e?.[2]?e[2].trim():void 0;if(window?.CSS)window.CSS.supports("color",a)||(a="transparent",r=t.trim());else{const e=(new Option).style;e.color=a,e.color!==a&&(a="transparent",r=t.trim())}const{wrap:s,cleanedText:i}=N(r);return{text:i?(0,n.jZ)(i,(0,n.D7)()):void 0,color:a,wrap:s}}),"parseBoxData"),K={SOLID:0,DOTTED:1,NOTE:2,SOLID_CROSS:3,DOTTED_CROSS:4,SOLID_OPEN:5,DOTTED_OPEN:6,LOOP_START:10,LOOP_END:11,ALT_START:12,ALT_ELSE:13,ALT_END:14,OPT_START:15,OPT_END:16,ACTIVE_START:17,ACTIVE_END:18,PAR_START:19,PAR_AND:20,PAR_END:21,RECT_START:22,RECT_END:23,SOLID_POINT:24,DOTTED_POINT:25,AUTONUMBER:26,CRITICAL_START:27,CRITICAL_OPTION:28,CRITICAL_END:29,BREAK_START:30,BREAK_END:31,PAR_OVER_START:32,BIDIRECTIONAL_SOLID:33,BIDIRECTIONAL_DOTTED:34},R=(0,n.K2)((function(t,e,a){const r={actor:t,placement:e,message:a.text,wrap:a.wrap??M()},s=[].concat(t,t);h.records.notes.push(r),h.records.messages.push({from:s[0],to:s[1],message:a.text,wrap:a.wrap??M(),type:K.NOTE,placement:e})}),"addNote"),Y=(0,n.K2)((function(t,e){const a=L(t);try{let t=(0,n.jZ)(e.text,(0,n.D7)());t=t.replace(/&/g,"&"),t=t.replace(/=/g,"=");B(a,JSON.parse(t))}catch(r){n.Rm.error("error while parsing actor link text",r)}}),"addLinks"),C=(0,n.K2)((function(t,e){const a=L(t);try{const t={};let r=(0,n.jZ)(e.text,(0,n.D7)());const s=r.indexOf("@");r=r.replace(/&/g,"&"),r=r.replace(/=/g,"=");const i=r.slice(0,s-1).trim(),o=r.slice(s+1).trim();t[i]=o,B(a,t)}catch(r){n.Rm.error("error while parsing actor link text",r)}}),"addALink");function B(t,e){if(null==t.links)t.links=e;else for(const a in e)t.links[a]=e[a]}(0,n.K2)(B,"insertLinks");var $=(0,n.K2)((function(t,e){const a=L(t);try{const t=(0,n.jZ)(e.text,(0,n.D7)());V(a,JSON.parse(t))}catch(r){n.Rm.error("error while parsing actor properties text",r)}}),"addProperties");function V(t,e){if(null==t.properties)t.properties=e;else for(const a in e)t.properties[a]=e[a]}function F(){h.records.currentBox=void 0}(0,n.K2)(V,"insertProperties"),(0,n.K2)(F,"boxEnd");var W=(0,n.K2)((function(t,e){const a=L(t),r=document.getElementById(e.text);try{const t=r.innerHTML,e=JSON.parse(t);e.properties&&V(a,e.properties),e.links&&B(a,e.links)}catch(s){n.Rm.error("error while parsing actor details text",s)}}),"addDetails"),q=(0,n.K2)((function(t,e){if(void 0!==t?.properties)return t.properties[e]}),"getActorProperty"),z=(0,n.K2)((function(t){if(Array.isArray(t))t.forEach((function(t){z(t)}));else switch(t.type){case"sequenceIndex":h.records.messages.push({from:void 0,to:void 0,message:{start:t.sequenceIndex,step:t.sequenceIndexStep,visible:t.sequenceVisible},wrap:!1,type:t.signalType});break;case"addParticipant":g(t.actor,t.actor,t.description,t.draw);break;case"createParticipant":if(h.records.actors.has(t.actor))throw new Error("It is not possible to have actors with the same id, even if one is destroyed before the next is created. Use 'AS' aliases to simulate the behavior");h.records.lastCreated=t.actor,g(t.actor,t.actor,t.description,t.draw),h.records.createdActors.set(t.actor,h.records.messages.length);break;case"destroyParticipant":h.records.lastDestroyed=t.actor,h.records.destroyedActors.set(t.actor,h.records.messages.length);break;case"activeStart":case"activeEnd":y(t.actor,void 0,void 0,t.signalType);break;case"addNote":R(t.actor,t.placement,t.text);break;case"addLinks":Y(t.actor,t.text);break;case"addALink":C(t.actor,t.text);break;case"addProperties":$(t.actor,t.text);break;case"addDetails":W(t.actor,t.text);break;case"addMessage":if(h.records.lastCreated){if(t.to!==h.records.lastCreated)throw new Error("The created participant "+h.records.lastCreated.name+" does not have an associated creating message after its declaration. Please check the sequence diagram.");h.records.lastCreated=void 0}else if(h.records.lastDestroyed){if(t.to!==h.records.lastDestroyed&&t.from!==h.records.lastDestroyed)throw new Error("The destroyed participant "+h.records.lastDestroyed.name+" does not have an associated destroying message after its declaration. Please check the sequence diagram.");h.records.lastDestroyed=void 0}y(t.from,t.to,t.msg,t.signalType,t.activate);break;case"boxStart":p(t.boxData);break;case"boxEnd":F();break;case"loopStart":y(void 0,void 0,t.loopText,t.signalType);break;case"loopEnd":case"rectEnd":case"optEnd":case"altEnd":case"parEnd":case"criticalEnd":case"breakEnd":y(void 0,void 0,void 0,t.signalType);break;case"rectStart":y(void 0,void 0,t.color,t.signalType);break;case"optStart":y(void 0,void 0,t.optText,t.signalType);break;case"altStart":case"else":y(void 0,void 0,t.altText,t.signalType);break;case"setAccTitle":(0,n.SV)(t.text);break;case"parStart":case"and":y(void 0,void 0,t.parText,t.signalType);break;case"criticalStart":y(void 0,void 0,t.criticalText,t.signalType);break;case"option":y(void 0,void 0,t.optionText,t.signalType);break;case"breakStart":y(void 0,void 0,t.breakText,t.signalType)}}),"apply"),H={addActor:g,addMessage:x,addSignal:y,addLinks:Y,addDetails:W,addProperties:$,autoWrap:M,setWrap:v,enableSequenceNumbers:P,disableSequenceNumbers:k,showSequenceNumbers:A,getMessages:T,getActors:E,getCreatedActors:w,getDestroyedActors:I,getActor:L,getActorKeys:_,getActorProperty:q,getAccTitle:n.iN,getBoxes:f,getDiagramTitle:n.ab,setDiagramTitle:n.ke,getConfig:(0,n.K2)((()=>(0,n.D7)().sequence),"getConfig"),clear:D,parseMessage:O,parseBoxData:S,LINETYPE:K,ARROWTYPE:{FILLED:0,OPEN:1},PLACEMENT:{LEFTOF:0,RIGHTOF:1,OVER:2},addNote:R,setAccTitle:n.SV,apply:z,setAccDescription:n.EI,getAccDescription:n.m7,hasAtLeastOneBox:m,hasAtLeastOneBoxWithTitle:b},j=(0,n.K2)((t=>`.actor {\n stroke: ${t.actorBorder};\n fill: ${t.actorBkg};\n }\n\n text.actor > tspan {\n fill: ${t.actorTextColor};\n stroke: none;\n }\n\n .actor-line {\n stroke: ${t.actorLineColor};\n }\n\n .messageLine0 {\n stroke-width: 1.5;\n stroke-dasharray: none;\n stroke: ${t.signalColor};\n }\n\n .messageLine1 {\n stroke-width: 1.5;\n stroke-dasharray: 2, 2;\n stroke: ${t.signalColor};\n }\n\n #arrowhead path {\n fill: ${t.signalColor};\n stroke: ${t.signalColor};\n }\n\n .sequenceNumber {\n fill: ${t.sequenceNumberColor};\n }\n\n #sequencenumber {\n fill: ${t.signalColor};\n }\n\n #crosshead path {\n fill: ${t.signalColor};\n stroke: ${t.signalColor};\n }\n\n .messageText {\n fill: ${t.signalTextColor};\n stroke: none;\n }\n\n .labelBox {\n stroke: ${t.labelBoxBorderColor};\n fill: ${t.labelBoxBkgColor};\n }\n\n .labelText, .labelText > tspan {\n fill: ${t.labelTextColor};\n stroke: none;\n }\n\n .loopText, .loopText > tspan {\n fill: ${t.loopTextColor};\n stroke: none;\n }\n\n .loopLine {\n stroke-width: 2px;\n stroke-dasharray: 2, 2;\n stroke: ${t.labelBoxBorderColor};\n fill: ${t.labelBoxBorderColor};\n }\n\n .note {\n //stroke: #decc93;\n stroke: ${t.noteBorderColor};\n fill: ${t.noteBkgColor};\n }\n\n .noteText, .noteText > tspan {\n fill: ${t.noteTextColor};\n stroke: none;\n }\n\n .activation0 {\n fill: ${t.activationBkgColor};\n stroke: ${t.activationBorderColor};\n }\n\n .activation1 {\n fill: ${t.activationBkgColor};\n stroke: ${t.activationBorderColor};\n }\n\n .activation2 {\n fill: ${t.activationBkgColor};\n stroke: ${t.activationBorderColor};\n }\n\n .actorPopupMenu {\n position: absolute;\n }\n\n .actorPopupMenuPanel {\n position: absolute;\n fill: ${t.actorBkg};\n box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);\n filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));\n}\n .actor-man line {\n stroke: ${t.actorBorder};\n fill: ${t.actorBkg};\n }\n .actor-man circle, line {\n stroke: ${t.actorBorder};\n fill: ${t.actorBkg};\n stroke-width: 2px;\n }\n`),"getStyles"),U="actor-top",J="actor-bottom",X="actor-man",G=(0,n.K2)((function(t,e){return(0,r.tk)(t,e)}),"drawRect"),Z=(0,n.K2)((function(t,e,a,r,s){if(void 0===e.links||null===e.links||0===Object.keys(e.links).length)return{height:0,width:0};const i=e.links,n=e.actorCnt,o=e.rectData;var l="none";s&&(l="block !important");const d=t.append("g");d.attr("id","actor"+n+"_popup"),d.attr("class","actorPopupMenu"),d.attr("display",l);var h="";void 0!==o.class&&(h=" "+o.class);let p=o.width>a?o.width:a;const g=d.append("rect");if(g.attr("class","actorPopupMenuPanel"+h),g.attr("x",o.x),g.attr("y",o.height),g.attr("fill",o.fill),g.attr("stroke",o.stroke),g.attr("width",p),g.attr("height",o.height),g.attr("rx",o.rx),g.attr("ry",o.ry),null!=i){var u=20;for(let t in i){var x=d.append("a"),y=(0,c.J)(i[t]);x.attr("xlink:href",y),x.attr("target","_blank"),It(r)(t,x,o.x+10,o.height+u,p,20,{class:"actor"},r),u+=30}}return g.attr("height",u),{height:o.height+u,width:p}}),"drawPopup"),Q=(0,n.K2)((function(t){return"var pu = document.getElementById('"+t+"'); if (pu != null) { pu.style.display = pu.style.display == 'block' ? 'none' : 'block'; }"}),"popupMenuToggle"),tt=(0,n.K2)((async function(t,e,a=null){let r=t.append("foreignObject");const s=await(0,n.VJ)(e.text,(0,n.zj)()),i=r.append("xhtml:div").attr("style","width: fit-content;").attr("xmlns","http://www.w3.org/1999/xhtml").html(s).node().getBoundingClientRect();if(r.attr("height",Math.round(i.height)).attr("width",Math.round(i.width)),"noteText"===e.class){const a=t.node().firstChild;a.setAttribute("height",i.height+2*e.textMargin);const s=a.getBBox();r.attr("x",Math.round(s.x+s.width/2-i.width/2)).attr("y",Math.round(s.y+s.height/2-i.height/2))}else if(a){let{startx:t,stopx:s,starty:n}=a;if(t>s){const e=t;t=s,s=e}r.attr("x",Math.round(t+Math.abs(t-s)/2-i.width/2)),"loopText"===e.class?r.attr("y",Math.round(n)):r.attr("y",Math.round(n-i.height))}return[r]}),"drawKatex"),et=(0,n.K2)((function(t,e){let a=0,r=0;const s=e.text.split(n.Y2.lineBreakRegex),[o,c]=(0,i.I5)(e.fontSize);let l=[],d=0,h=(0,n.K2)((()=>e.y),"yfunc");if(void 0!==e.valign&&void 0!==e.textMargin&&e.textMargin>0)switch(e.valign){case"top":case"start":h=(0,n.K2)((()=>Math.round(e.y+e.textMargin)),"yfunc");break;case"middle":case"center":h=(0,n.K2)((()=>Math.round(e.y+(a+r+e.textMargin)/2)),"yfunc");break;case"bottom":case"end":h=(0,n.K2)((()=>Math.round(e.y+(a+r+2*e.textMargin)-e.textMargin)),"yfunc")}if(void 0!==e.anchor&&void 0!==e.textMargin&&void 0!==e.width)switch(e.anchor){case"left":case"start":e.x=Math.round(e.x+e.textMargin),e.anchor="start",e.dominantBaseline="middle",e.alignmentBaseline="middle";break;case"middle":case"center":e.x=Math.round(e.x+e.width/2),e.anchor="middle",e.dominantBaseline="middle",e.alignmentBaseline="middle";break;case"right":case"end":e.x=Math.round(e.x+e.width-e.textMargin),e.anchor="end",e.dominantBaseline="middle",e.alignmentBaseline="middle"}for(let[n,p]of s.entries()){void 0!==e.textMargin&&0===e.textMargin&&void 0!==o&&(d=n*o);const s=t.append("text");s.attr("x",e.x),s.attr("y",h()),void 0!==e.anchor&&s.attr("text-anchor",e.anchor).attr("dominant-baseline",e.dominantBaseline).attr("alignment-baseline",e.alignmentBaseline),void 0!==e.fontFamily&&s.style("font-family",e.fontFamily),void 0!==c&&s.style("font-size",c),void 0!==e.fontWeight&&s.style("font-weight",e.fontWeight),void 0!==e.fill&&s.attr("fill",e.fill),void 0!==e.class&&s.attr("class",e.class),void 0!==e.dy?s.attr("dy",e.dy):0!==d&&s.attr("dy",d);const g=p||i.pe;if(e.tspan){const t=s.append("tspan");t.attr("x",e.x),void 0!==e.fill&&t.attr("fill",e.fill),t.text(g)}else s.text(g);void 0!==e.valign&&void 0!==e.textMargin&&e.textMargin>0&&(r+=(s._groups||s)[0][0].getBBox().height,a=r),l.push(s)}return l}),"drawText"),at=(0,n.K2)((function(t,e){function a(t,e,a,r,s){return t+","+e+" "+(t+a)+","+e+" "+(t+a)+","+(e+r-s)+" "+(t+a-1.2*s)+","+(e+r)+" "+t+","+(e+r)}(0,n.K2)(a,"genPoints");const r=t.append("polygon");return r.attr("points",a(e.x,e.y,e.width,e.height,7)),r.attr("class","labelBox"),e.y=e.y+e.height/2,et(t,e),r}),"drawLabel"),rt=-1,st=(0,n.K2)(((t,e,a,r)=>{t.select&&a.forEach((a=>{const s=e.get(a),i=t.select("#actor"+s.actorCnt);!r.mirrorActors&&s.stopy?i.attr("y2",s.stopy+s.height/2):r.mirrorActors&&i.attr("y2",s.stopy)}))}),"fixLifeLineHeights"),it=(0,n.K2)((function(t,e,a,s){const i=s?e.stopy:e.starty,o=e.x+e.width/2,c=i+e.height,l=t.append("g").lower();var d=l;s||(rt++,Object.keys(e.links||{}).length&&!a.forceMenus&&d.attr("onclick",Q(`actor${rt}_popup`)).attr("cursor","pointer"),d.append("line").attr("id","actor"+rt).attr("x1",o).attr("y1",c).attr("x2",o).attr("y2",2e3).attr("class","actor-line 200").attr("stroke-width","0.5px").attr("stroke","#999").attr("name",e.name),d=l.append("g"),e.actorCnt=rt,null!=e.links&&d.attr("id","root-"+rt));const h=(0,r.PB)();var p="actor";e.properties?.class?p=e.properties.class:h.fill="#eaeaea",p+=s?` ${J}`:` ${U}`,h.x=e.x,h.y=i,h.width=e.width,h.height=e.height,h.class=p,h.rx=3,h.ry=3,h.name=e.name;const g=G(d,h);if(e.rectData=h,e.properties?.icon){const t=e.properties.icon.trim();"@"===t.charAt(0)?(0,r.CP)(d,h.x+h.width-20,h.y+10,t.substr(1)):(0,r.aC)(d,h.x+h.width-20,h.y+10,t)}wt(a,(0,n.Wi)(e.description))(e.description,d,h.x,h.y,h.width,h.height,{class:"actor actor-box"},a);let u=e.height;if(g.node){const t=g.node().getBBox();e.height=t.height,u=t.height}return u}),"drawActorTypeParticipant"),nt=(0,n.K2)((function(t,e,a,s){const i=s?e.stopy:e.starty,o=e.x+e.width/2,c=i+80,l=t.append("g").lower();s||(rt++,l.append("line").attr("id","actor"+rt).attr("x1",o).attr("y1",c).attr("x2",o).attr("y2",2e3).attr("class","actor-line 200").attr("stroke-width","0.5px").attr("stroke","#999").attr("name",e.name),e.actorCnt=rt);const d=t.append("g");let h=X;h+=s?` ${J}`:` ${U}`,d.attr("class",h),d.attr("name",e.name);const p=(0,r.PB)();p.x=e.x,p.y=i,p.fill="#eaeaea",p.width=e.width,p.height=e.height,p.class="actor",p.rx=3,p.ry=3,d.append("line").attr("id","actor-man-torso"+rt).attr("x1",o).attr("y1",i+25).attr("x2",o).attr("y2",i+45),d.append("line").attr("id","actor-man-arms"+rt).attr("x1",o-18).attr("y1",i+33).attr("x2",o+18).attr("y2",i+33),d.append("line").attr("x1",o-18).attr("y1",i+60).attr("x2",o).attr("y2",i+45),d.append("line").attr("x1",o).attr("y1",i+45).attr("x2",o+18-2).attr("y2",i+60);const g=d.append("circle");g.attr("cx",e.x+e.width/2),g.attr("cy",i+10),g.attr("r",15),g.attr("width",e.width),g.attr("height",e.height);const u=d.node().getBBox();return e.height=u.height,wt(a,(0,n.Wi)(e.description))(e.description,d,p.x,p.y+35,p.width,p.height,{class:`actor ${X}`},a),e.height}),"drawActorTypeActor"),ot=(0,n.K2)((async function(t,e,a,r){switch(e.type){case"actor":return await nt(t,e,a,r);case"participant":return await it(t,e,a,r)}}),"drawActor"),ct=(0,n.K2)((function(t,e,a){const r=t.append("g");pt(r,e),e.name&&wt(a)(e.name,r,e.x,e.y+(e.textMaxHeight||0)/2,e.width,0,{class:"text"},a),r.lower()}),"drawBox"),lt=(0,n.K2)((function(t){return t.append("g")}),"anchorElement"),dt=(0,n.K2)((function(t,e,a,s,i){const n=(0,r.PB)(),o=e.anchored;n.x=e.startx,n.y=e.starty,n.class="activation"+i%3,n.width=e.stopx-e.startx,n.height=a-e.starty,G(o,n)}),"drawActivation"),ht=(0,n.K2)((async function(t,e,a,s){const{boxMargin:i,boxTextMargin:o,labelBoxHeight:c,labelBoxWidth:l,messageFontFamily:d,messageFontSize:h,messageFontWeight:p}=s,g=t.append("g"),u=(0,n.K2)((function(t,e,a,r){return g.append("line").attr("x1",t).attr("y1",e).attr("x2",a).attr("y2",r).attr("class","loopLine")}),"drawLoopLine");u(e.startx,e.starty,e.stopx,e.starty),u(e.stopx,e.starty,e.stopx,e.stopy),u(e.startx,e.stopy,e.stopx,e.stopy),u(e.startx,e.starty,e.startx,e.stopy),void 0!==e.sections&&e.sections.forEach((function(t){u(e.startx,t.y,e.stopx,t.y).style("stroke-dasharray","3, 3")}));let x=(0,r.HT)();x.text=a,x.x=e.startx,x.y=e.starty,x.fontFamily=d,x.fontSize=h,x.fontWeight=p,x.anchor="middle",x.valign="middle",x.tspan=!1,x.width=l||50,x.height=c||20,x.textMargin=o,x.class="labelText",at(g,x),x=ft(),x.text=e.title,x.x=e.startx+l/2+(e.stopx-e.startx)/2,x.y=e.starty+i+o,x.anchor="middle",x.valign="middle",x.textMargin=o,x.class="loopText",x.fontFamily=d,x.fontSize=h,x.fontWeight=p,x.wrap=!0;let y=(0,n.Wi)(x.text)?await tt(g,x,e):et(g,x);if(void 0!==e.sectionTitles)for(const[r,m]of Object.entries(e.sectionTitles))if(m.message){x.text=m.message,x.x=e.startx+(e.stopx-e.startx)/2,x.y=e.sections[r].y+i+o,x.class="loopText",x.anchor="middle",x.valign="middle",x.tspan=!1,x.fontFamily=d,x.fontSize=h,x.fontWeight=p,x.wrap=e.wrap,(0,n.Wi)(x.text)?(e.starty=e.sections[r].y,await tt(g,x,e)):et(g,x);let t=Math.round(y.map((t=>(t._groups||t)[0][0].getBBox().height)).reduce(((t,e)=>t+e)));e.sections[r].height+=t-(i+o)}return e.height=Math.round(e.stopy-e.starty),g}),"drawLoop"),pt=(0,n.K2)((function(t,e){(0,r.lC)(t,e)}),"drawBackgroundRect"),gt=(0,n.K2)((function(t){t.append("defs").append("symbol").attr("id","database").attr("fill-rule","evenodd").attr("clip-rule","evenodd").append("path").attr("transform","scale(.5)").attr("d","M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z")}),"insertDatabaseIcon"),ut=(0,n.K2)((function(t){t.append("defs").append("symbol").attr("id","computer").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z")}),"insertComputerIcon"),xt=(0,n.K2)((function(t){t.append("defs").append("symbol").attr("id","clock").attr("width","24").attr("height","24").append("path").attr("transform","scale(.5)").attr("d","M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z")}),"insertClockIcon"),yt=(0,n.K2)((function(t){t.append("defs").append("marker").attr("id","arrowhead").attr("refX",7.9).attr("refY",5).attr("markerUnits","userSpaceOnUse").attr("markerWidth",12).attr("markerHeight",12).attr("orient","auto-start-reverse").append("path").attr("d","M -1 0 L 10 5 L 0 10 z")}),"insertArrowHead"),mt=(0,n.K2)((function(t){t.append("defs").append("marker").attr("id","filled-head").attr("refX",15.5).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 18,7 L9,13 L14,7 L9,1 Z")}),"insertArrowFilledHead"),bt=(0,n.K2)((function(t){t.append("defs").append("marker").attr("id","sequencenumber").attr("refX",15).attr("refY",15).attr("markerWidth",60).attr("markerHeight",40).attr("orient","auto").append("circle").attr("cx",15).attr("cy",15).attr("r",6)}),"insertSequenceNumber"),Tt=(0,n.K2)((function(t){t.append("defs").append("marker").attr("id","crosshead").attr("markerWidth",15).attr("markerHeight",8).attr("orient","auto").attr("refX",4).attr("refY",4.5).append("path").attr("fill","none").attr("stroke","#000000").style("stroke-dasharray","0, 0").attr("stroke-width","1pt").attr("d","M 1,2 L 6,7 M 6,2 L 1,7")}),"insertArrowCrossHead"),ft=(0,n.K2)((function(){return{x:0,y:0,fill:void 0,anchor:void 0,style:"#666",width:void 0,height:void 0,textMargin:0,rx:0,ry:0,tspan:!0,valign:void 0}}),"getTextObj"),Et=(0,n.K2)((function(){return{x:0,y:0,fill:"#EDF2AE",stroke:"#666",width:100,anchor:"start",height:100,rx:0,ry:0}}),"getNoteRect"),wt=function(){function t(t,e,a,r,i,n,o){s(e.append("text").attr("x",a+i/2).attr("y",r+n/2+5).style("text-anchor","middle").text(t),o)}function e(t,e,a,r,o,c,l,d){const{actorFontSize:h,actorFontFamily:p,actorFontWeight:g}=d,[u,x]=(0,i.I5)(h),y=t.split(n.Y2.lineBreakRegex);for(let i=0;i<y.length;i++){const t=i*u-u*(y.length-1)/2,n=e.append("text").attr("x",a+o/2).attr("y",r).style("text-anchor","middle").style("font-size",x).style("font-weight",g).style("font-family",p);n.append("tspan").attr("x",a+o/2).attr("dy",t).text(y[i]),n.attr("y",r+c/2).attr("dominant-baseline","central").attr("alignment-baseline","central"),s(n,l)}}function a(t,a,r,i,n,o,c,l){const d=a.append("switch"),h=d.append("foreignObject").attr("x",r).attr("y",i).attr("width",n).attr("height",o).append("xhtml:div").style("display","table").style("height","100%").style("width","100%");h.append("div").style("display","table-cell").style("text-align","center").style("vertical-align","middle").text(t),e(t,d,r,i,n,o,c,l),s(h,c)}async function r(t,a,r,i,o,c,l,d){const h=await(0,n.Dl)(t,(0,n.zj)()),p=a.append("switch"),g=p.append("foreignObject").attr("x",r+o/2-h.width/2).attr("y",i+c/2-h.height/2).attr("width",h.width).attr("height",h.height).append("xhtml:div").style("height","100%").style("width","100%");g.append("div").style("text-align","center").style("vertical-align","middle").html(await(0,n.VJ)(t,(0,n.zj)())),e(t,p,r,i,o,c,l,d),s(g,l)}function s(t,e){for(const a in e)e.hasOwnProperty(a)&&t.attr(a,e[a])}return(0,n.K2)(t,"byText"),(0,n.K2)(e,"byTspan"),(0,n.K2)(a,"byFo"),(0,n.K2)(r,"byKatex"),(0,n.K2)(s,"_setTextAttrs"),function(s,i=!1){return i?r:"fo"===s.textPlacement?a:"old"===s.textPlacement?t:e}}(),It=function(){function t(t,e,a,s,i,n,o){r(e.append("text").attr("x",a).attr("y",s).style("text-anchor","start").text(t),o)}function e(t,e,a,s,i,o,c,l){const{actorFontSize:d,actorFontFamily:h,actorFontWeight:p}=l,g=t.split(n.Y2.lineBreakRegex);for(let n=0;n<g.length;n++){const t=n*d-d*(g.length-1)/2,i=e.append("text").attr("x",a).attr("y",s).style("text-anchor","start").style("font-size",d).style("font-weight",p).style("font-family",h);i.append("tspan").attr("x",a).attr("dy",t).text(g[n]),i.attr("y",s+o/2).attr("dominant-baseline","central").attr("alignment-baseline","central"),r(i,c)}}function a(t,a,s,i,n,o,c,l){const d=a.append("switch"),h=d.append("foreignObject").attr("x",s).attr("y",i).attr("width",n).attr("height",o).append("xhtml:div").style("display","table").style("height","100%").style("width","100%");h.append("div").style("display","table-cell").style("text-align","center").style("vertical-align","middle").text(t),e(t,d,s,i,0,o,c,l),r(h,c)}function r(t,e){for(const a in e)e.hasOwnProperty(a)&&t.attr(a,e[a])}return(0,n.K2)(t,"byText"),(0,n.K2)(e,"byTspan"),(0,n.K2)(a,"byFo"),(0,n.K2)(r,"_setTextAttrs"),function(r){return"fo"===r.textPlacement?a:"old"===r.textPlacement?t:e}}(),Lt={drawRect:G,drawText:et,drawLabel:at,drawActor:ot,drawBox:ct,drawPopup:Z,anchorElement:lt,drawActivation:dt,drawLoop:ht,drawBackgroundRect:pt,insertArrowHead:yt,insertArrowFilledHead:mt,insertSequenceNumber:bt,insertArrowCrossHead:Tt,insertDatabaseIcon:gt,insertComputerIcon:ut,insertClockIcon:xt,getTextObj:ft,getNoteRect:Et,fixLifeLineHeights:st,sanitizeUrl:c.J},_t={},Pt={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],activations:[],models:{getHeight:(0,n.K2)((function(){return Math.max.apply(null,0===this.actors.length?[0]:this.actors.map((t=>t.height||0)))+(0===this.loops.length?0:this.loops.map((t=>t.height||0)).reduce(((t,e)=>t+e)))+(0===this.messages.length?0:this.messages.map((t=>t.height||0)).reduce(((t,e)=>t+e)))+(0===this.notes.length?0:this.notes.map((t=>t.height||0)).reduce(((t,e)=>t+e)))}),"getHeight"),clear:(0,n.K2)((function(){this.actors=[],this.boxes=[],this.loops=[],this.messages=[],this.notes=[]}),"clear"),addBox:(0,n.K2)((function(t){this.boxes.push(t)}),"addBox"),addActor:(0,n.K2)((function(t){this.actors.push(t)}),"addActor"),addLoop:(0,n.K2)((function(t){this.loops.push(t)}),"addLoop"),addMessage:(0,n.K2)((function(t){this.messages.push(t)}),"addMessage"),addNote:(0,n.K2)((function(t){this.notes.push(t)}),"addNote"),lastActor:(0,n.K2)((function(){return this.actors[this.actors.length-1]}),"lastActor"),lastLoop:(0,n.K2)((function(){return this.loops[this.loops.length-1]}),"lastLoop"),lastMessage:(0,n.K2)((function(){return this.messages[this.messages.length-1]}),"lastMessage"),lastNote:(0,n.K2)((function(){return this.notes[this.notes.length-1]}),"lastNote"),actors:[],boxes:[],loops:[],messages:[],notes:[]},init:(0,n.K2)((function(){this.sequenceItems=[],this.activations=[],this.models.clear(),this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0,Rt((0,n.D7)())}),"init"),updateVal:(0,n.K2)((function(t,e,a,r){void 0===t[e]?t[e]=a:t[e]=r(a,t[e])}),"updateVal"),updateBounds:(0,n.K2)((function(t,e,a,r){const s=this;let i=0;function o(o){return(0,n.K2)((function(n){i++;const c=s.sequenceItems.length-i+1;s.updateVal(n,"starty",e-c*_t.boxMargin,Math.min),s.updateVal(n,"stopy",r+c*_t.boxMargin,Math.max),s.updateVal(Pt.data,"startx",t-c*_t.boxMargin,Math.min),s.updateVal(Pt.data,"stopx",a+c*_t.boxMargin,Math.max),"activation"!==o&&(s.updateVal(n,"startx",t-c*_t.boxMargin,Math.min),s.updateVal(n,"stopx",a+c*_t.boxMargin,Math.max),s.updateVal(Pt.data,"starty",e-c*_t.boxMargin,Math.min),s.updateVal(Pt.data,"stopy",r+c*_t.boxMargin,Math.max))}),"updateItemBounds")}(0,n.K2)(o,"updateFn"),this.sequenceItems.forEach(o()),this.activations.forEach(o("activation"))}),"updateBounds"),insert:(0,n.K2)((function(t,e,a,r){const s=n.Y2.getMin(t,a),i=n.Y2.getMax(t,a),o=n.Y2.getMin(e,r),c=n.Y2.getMax(e,r);this.updateVal(Pt.data,"startx",s,Math.min),this.updateVal(Pt.data,"starty",o,Math.min),this.updateVal(Pt.data,"stopx",i,Math.max),this.updateVal(Pt.data,"stopy",c,Math.max),this.updateBounds(s,o,i,c)}),"insert"),newActivation:(0,n.K2)((function(t,e,a){const r=a.get(t.from),s=Yt(t.from).length||0,i=r.x+r.width/2+(s-1)*_t.activationWidth/2;this.activations.push({startx:i,starty:this.verticalPos+2,stopx:i+_t.activationWidth,stopy:void 0,actor:t.from,anchored:Lt.anchorElement(e)})}),"newActivation"),endActivation:(0,n.K2)((function(t){const e=this.activations.map((function(t){return t.actor})).lastIndexOf(t.from);return this.activations.splice(e,1)[0]}),"endActivation"),createLoop:(0,n.K2)((function(t={message:void 0,wrap:!1,width:void 0},e){return{startx:void 0,starty:this.verticalPos,stopx:void 0,stopy:void 0,title:t.message,wrap:t.wrap,width:t.width,height:0,fill:e}}),"createLoop"),newLoop:(0,n.K2)((function(t={message:void 0,wrap:!1,width:void 0},e){this.sequenceItems.push(this.createLoop(t,e))}),"newLoop"),endLoop:(0,n.K2)((function(){return this.sequenceItems.pop()}),"endLoop"),isLoopOverlap:(0,n.K2)((function(){return!!this.sequenceItems.length&&this.sequenceItems[this.sequenceItems.length-1].overlap}),"isLoopOverlap"),addSectionToLoop:(0,n.K2)((function(t){const e=this.sequenceItems.pop();e.sections=e.sections||[],e.sectionTitles=e.sectionTitles||[],e.sections.push({y:Pt.getVerticalPos(),height:0}),e.sectionTitles.push(t),this.sequenceItems.push(e)}),"addSectionToLoop"),saveVerticalPos:(0,n.K2)((function(){this.isLoopOverlap()&&(this.savedVerticalPos=this.verticalPos)}),"saveVerticalPos"),resetVerticalPos:(0,n.K2)((function(){this.isLoopOverlap()&&(this.verticalPos=this.savedVerticalPos)}),"resetVerticalPos"),bumpVerticalPos:(0,n.K2)((function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=n.Y2.getMax(this.data.stopy,this.verticalPos)}),"bumpVerticalPos"),getVerticalPos:(0,n.K2)((function(){return this.verticalPos}),"getVerticalPos"),getBounds:(0,n.K2)((function(){return{bounds:this.data,models:this.models}}),"getBounds")},kt=(0,n.K2)((async function(t,e){Pt.bumpVerticalPos(_t.boxMargin),e.height=_t.boxMargin,e.starty=Pt.getVerticalPos();const a=(0,r.PB)();a.x=e.startx,a.y=e.starty,a.width=e.width||_t.width,a.class="note";const s=t.append("g"),i=Lt.drawRect(s,a),o=(0,r.HT)();o.x=e.startx,o.y=e.starty,o.width=a.width,o.dy="1em",o.text=e.message,o.class="noteText",o.fontFamily=_t.noteFontFamily,o.fontSize=_t.noteFontSize,o.fontWeight=_t.noteFontWeight,o.anchor=_t.noteAlign,o.textMargin=_t.noteMargin,o.valign="center";const c=(0,n.Wi)(o.text)?await tt(s,o):et(s,o),l=Math.round(c.map((t=>(t._groups||t)[0][0].getBBox().height)).reduce(((t,e)=>t+e)));i.attr("height",l+2*_t.noteMargin),e.height+=l+2*_t.noteMargin,Pt.bumpVerticalPos(l+2*_t.noteMargin),e.stopy=e.starty+l+2*_t.noteMargin,e.stopx=e.startx+a.width,Pt.insert(e.startx,e.starty,e.stopx,e.stopy),Pt.models.addNote(e)}),"drawNote"),At=(0,n.K2)((t=>({fontFamily:t.messageFontFamily,fontSize:t.messageFontSize,fontWeight:t.messageFontWeight})),"messageFont"),vt=(0,n.K2)((t=>({fontFamily:t.noteFontFamily,fontSize:t.noteFontSize,fontWeight:t.noteFontWeight})),"noteFont"),Nt=(0,n.K2)((t=>({fontFamily:t.actorFontFamily,fontSize:t.actorFontSize,fontWeight:t.actorFontWeight})),"actorFont");async function Mt(t,e){Pt.bumpVerticalPos(10);const{startx:a,stopx:r,message:s}=e,o=n.Y2.splitBreaks(s).length,c=(0,n.Wi)(s),l=c?await(0,n.Dl)(s,(0,n.D7)()):i._K.calculateTextDimensions(s,At(_t));if(!c){const t=l.height/o;e.height+=t,Pt.bumpVerticalPos(t)}let d,h=l.height-10;const p=l.width;if(a===r){d=Pt.getVerticalPos()+h,_t.rightAngles||(h+=_t.boxMargin,d=Pt.getVerticalPos()+h),h+=30;const t=n.Y2.getMax(p/2,_t.width/2);Pt.insert(a-t,Pt.getVerticalPos()-10+h,r+t,Pt.getVerticalPos()+30+h)}else h+=_t.boxMargin,d=Pt.getVerticalPos()+h,Pt.insert(a,d-10,r,d);return Pt.bumpVerticalPos(h),e.height+=h,e.stopy=e.starty+e.height,Pt.insert(e.fromBounds,e.starty,e.toBounds,e.stopy),d}(0,n.K2)(Mt,"boundMessage");var Dt=(0,n.K2)((async function(t,e,a,s){const{startx:o,stopx:c,starty:l,message:d,type:h,sequenceIndex:p,sequenceVisible:g}=e,u=i._K.calculateTextDimensions(d,At(_t)),x=(0,r.HT)();x.x=o,x.y=l+10,x.width=c-o,x.class="messageText",x.dy="1em",x.text=d,x.fontFamily=_t.messageFontFamily,x.fontSize=_t.messageFontSize,x.fontWeight=_t.messageFontWeight,x.anchor=_t.messageAlign,x.valign="center",x.textMargin=_t.wrapPadding,x.tspan=!1,(0,n.Wi)(x.text)?await tt(t,x,{startx:o,stopx:c,starty:a}):et(t,x);const y=u.width;let m;o===c?m=_t.rightAngles?t.append("path").attr("d",`M ${o},${a} H ${o+n.Y2.getMax(_t.width/2,y/2)} V ${a+25} H ${o}`):t.append("path").attr("d","M "+o+","+a+" C "+(o+60)+","+(a-10)+" "+(o+60)+","+(a+30)+" "+o+","+(a+20)):(m=t.append("line"),m.attr("x1",o),m.attr("y1",a),m.attr("x2",c),m.attr("y2",a)),h===s.db.LINETYPE.DOTTED||h===s.db.LINETYPE.DOTTED_CROSS||h===s.db.LINETYPE.DOTTED_POINT||h===s.db.LINETYPE.DOTTED_OPEN||h===s.db.LINETYPE.BIDIRECTIONAL_DOTTED?(m.style("stroke-dasharray","3, 3"),m.attr("class","messageLine1")):m.attr("class","messageLine0");let b="";_t.arrowMarkerAbsolute&&(b=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,b=b.replace(/\(/g,"\\("),b=b.replace(/\)/g,"\\)")),m.attr("stroke-width",2),m.attr("stroke","none"),m.style("fill","none"),h!==s.db.LINETYPE.SOLID&&h!==s.db.LINETYPE.DOTTED||m.attr("marker-end","url("+b+"#arrowhead)"),h!==s.db.LINETYPE.BIDIRECTIONAL_SOLID&&h!==s.db.LINETYPE.BIDIRECTIONAL_DOTTED||(m.attr("marker-start","url("+b+"#arrowhead)"),m.attr("marker-end","url("+b+"#arrowhead)")),h!==s.db.LINETYPE.SOLID_POINT&&h!==s.db.LINETYPE.DOTTED_POINT||m.attr("marker-end","url("+b+"#filled-head)"),h!==s.db.LINETYPE.SOLID_CROSS&&h!==s.db.LINETYPE.DOTTED_CROSS||m.attr("marker-end","url("+b+"#crosshead)"),(g||_t.showSequenceNumbers)&&(m.attr("marker-start","url("+b+"#sequencenumber)"),t.append("text").attr("x",o).attr("y",a+4).attr("font-family","sans-serif").attr("font-size","12px").attr("text-anchor","middle").attr("class","sequenceNumber").text(p))}),"drawMessage"),Ot=(0,n.K2)((function(t,e,a,r,s,i,o){let c,l=0,d=0,h=0;for(const p of r){const t=e.get(p),r=t.box;c&&c!=r&&(o||Pt.models.addBox(c),d+=_t.boxMargin+c.margin),r&&r!=c&&(o||(r.x=l+d,r.y=s),d+=r.margin),t.width=t.width||_t.width,t.height=n.Y2.getMax(t.height||_t.height,_t.height),t.margin=t.margin||_t.actorMargin,h=n.Y2.getMax(h,t.height),a.get(t.name)&&(d+=t.width/2),t.x=l+d,t.starty=Pt.getVerticalPos(),Pt.insert(t.x,s,t.x+t.width,t.height),l+=t.width+d,t.box&&(t.box.width=l+r.margin-t.box.x),d=t.margin,c=t.box,Pt.models.addActor(t)}c&&!o&&Pt.models.addBox(c),Pt.bumpVerticalPos(h)}),"addActorRenderingData"),St=(0,n.K2)((async function(t,e,a,r){if(r){let r=0;Pt.bumpVerticalPos(2*_t.boxMargin);for(const s of a){const a=e.get(s);a.stopy||(a.stopy=Pt.getVerticalPos());const i=await Lt.drawActor(t,a,_t,!0);r=n.Y2.getMax(r,i)}Pt.bumpVerticalPos(r+_t.boxMargin)}else for(const s of a){const a=e.get(s);await Lt.drawActor(t,a,_t,!1)}}),"drawActors"),Kt=(0,n.K2)((function(t,e,a,r){let s=0,i=0;for(const n of a){const a=e.get(n),o=Wt(a),c=Lt.drawPopup(t,a,o,_t,_t.forceMenus,r);c.height>s&&(s=c.height),c.width+a.x>i&&(i=c.width+a.x)}return{maxHeight:s,maxWidth:i}}),"drawActorsPopup"),Rt=(0,n.K2)((function(t){(0,n.hH)(_t,t),t.fontFamily&&(_t.actorFontFamily=_t.noteFontFamily=_t.messageFontFamily=t.fontFamily),t.fontSize&&(_t.actorFontSize=_t.noteFontSize=_t.messageFontSize=t.fontSize),t.fontWeight&&(_t.actorFontWeight=_t.noteFontWeight=_t.messageFontWeight=t.fontWeight)}),"setConf"),Yt=(0,n.K2)((function(t){return Pt.activations.filter((function(e){return e.actor===t}))}),"actorActivations"),Ct=(0,n.K2)((function(t,e){const a=e.get(t),r=Yt(t);return[r.reduce((function(t,e){return n.Y2.getMin(t,e.startx)}),a.x+a.width/2-1),r.reduce((function(t,e){return n.Y2.getMax(t,e.stopx)}),a.x+a.width/2+1)]}),"activationBounds");function Bt(t,e,a,r,s){Pt.bumpVerticalPos(a);let o=r;if(e.id&&e.message&&t[e.id]){const a=t[e.id].width,s=At(_t);e.message=i._K.wrapLabel(`[${e.message}]`,a-2*_t.wrapPadding,s),e.width=a,e.wrap=!0;const c=i._K.calculateTextDimensions(e.message,s),l=n.Y2.getMax(c.height,_t.labelBoxHeight);o=r+l,n.Rm.debug(`${l} - ${e.message}`)}s(e),Pt.bumpVerticalPos(o)}function $t(t,e,a,r,s,i,o){function c(a,r){a.x<s.get(t.from).x?(Pt.insert(e.stopx-r,e.starty,e.startx,e.stopy+a.height/2+_t.noteMargin),e.stopx=e.stopx+r):(Pt.insert(e.startx,e.starty,e.stopx+r,e.stopy+a.height/2+_t.noteMargin),e.stopx=e.stopx-r)}function l(a,r){a.x<s.get(t.to).x?(Pt.insert(e.startx-r,e.starty,e.stopx,e.stopy+a.height/2+_t.noteMargin),e.startx=e.startx+r):(Pt.insert(e.stopx,e.starty,e.startx+r,e.stopy+a.height/2+_t.noteMargin),e.startx=e.startx-r)}if((0,n.K2)(c,"receiverAdjustment"),(0,n.K2)(l,"senderAdjustment"),i.get(t.to)==r){const e=s.get(t.to);c(e,"actor"==e.type?21:e.width/2+3),e.starty=a-e.height/2,Pt.bumpVerticalPos(e.height/2)}else if(o.get(t.from)==r){const e=s.get(t.from);if(_t.mirrorActors){l(e,"actor"==e.type?18:e.width/2)}e.stopy=a-e.height/2,Pt.bumpVerticalPos(e.height/2)}else if(o.get(t.to)==r){const e=s.get(t.to);if(_t.mirrorActors){c(e,"actor"==e.type?21:e.width/2+3)}e.stopy=a-e.height/2,Pt.bumpVerticalPos(e.height/2)}}(0,n.K2)(Bt,"adjustLoopHeightForWrap"),(0,n.K2)($t,"adjustCreatedDestroyedData");var Vt=(0,n.K2)((async function(t,e,a,r){const{securityLevel:s,sequence:i}=(0,n.D7)();let c;_t=i,"sandbox"===s&&(c=(0,o.Ltv)("#i"+e));const l="sandbox"===s?(0,o.Ltv)(c.nodes()[0].contentDocument.body):(0,o.Ltv)("body"),d="sandbox"===s?c.nodes()[0].contentDocument:document;Pt.init(),n.Rm.debug(r.db);const h="sandbox"===s?l.select(`[id="${e}"]`):(0,o.Ltv)(`[id="${e}"]`),p=r.db.getActors(),g=r.db.getCreatedActors(),u=r.db.getDestroyedActors(),x=r.db.getBoxes();let y=r.db.getActorKeys();const m=r.db.getMessages(),b=r.db.getDiagramTitle(),T=r.db.hasAtLeastOneBox(),f=r.db.hasAtLeastOneBoxWithTitle(),E=await Ft(p,m,r);if(_t.height=await qt(p,E,x),Lt.insertComputerIcon(h),Lt.insertDatabaseIcon(h),Lt.insertClockIcon(h),T&&(Pt.bumpVerticalPos(_t.boxMargin),f&&Pt.bumpVerticalPos(x[0].textMaxHeight)),!0===_t.hideUnusedParticipants){const t=new Set;m.forEach((e=>{t.add(e.from),t.add(e.to)})),y=y.filter((e=>t.has(e)))}Ot(h,p,g,y,0,m,!1);const w=await jt(m,p,E,r);function I(t,e){const a=Pt.endActivation(t);a.starty+18>e&&(a.starty=e-6,e+=12),Lt.drawActivation(h,a,e,_t,Yt(t.from).length),Pt.insert(a.startx,e-10,a.stopx,e)}Lt.insertArrowHead(h),Lt.insertArrowCrossHead(h),Lt.insertArrowFilledHead(h),Lt.insertSequenceNumber(h),(0,n.K2)(I,"activeEnd");let L=1,_=1;const P=[],k=[];let A=0;for(const o of m){let t,e,a;switch(o.type){case r.db.LINETYPE.NOTE:Pt.resetVerticalPos(),e=o.noteModel,await kt(h,e);break;case r.db.LINETYPE.ACTIVE_START:Pt.newActivation(o,h,p);break;case r.db.LINETYPE.ACTIVE_END:I(o,Pt.getVerticalPos());break;case r.db.LINETYPE.LOOP_START:Bt(w,o,_t.boxMargin,_t.boxMargin+_t.boxTextMargin,(t=>Pt.newLoop(t)));break;case r.db.LINETYPE.LOOP_END:t=Pt.endLoop(),await Lt.drawLoop(h,t,"loop",_t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos()),Pt.models.addLoop(t);break;case r.db.LINETYPE.RECT_START:Bt(w,o,_t.boxMargin,_t.boxMargin,(t=>Pt.newLoop(void 0,t.message)));break;case r.db.LINETYPE.RECT_END:t=Pt.endLoop(),k.push(t),Pt.models.addLoop(t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos());break;case r.db.LINETYPE.OPT_START:Bt(w,o,_t.boxMargin,_t.boxMargin+_t.boxTextMargin,(t=>Pt.newLoop(t)));break;case r.db.LINETYPE.OPT_END:t=Pt.endLoop(),await Lt.drawLoop(h,t,"opt",_t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos()),Pt.models.addLoop(t);break;case r.db.LINETYPE.ALT_START:Bt(w,o,_t.boxMargin,_t.boxMargin+_t.boxTextMargin,(t=>Pt.newLoop(t)));break;case r.db.LINETYPE.ALT_ELSE:Bt(w,o,_t.boxMargin+_t.boxTextMargin,_t.boxMargin,(t=>Pt.addSectionToLoop(t)));break;case r.db.LINETYPE.ALT_END:t=Pt.endLoop(),await Lt.drawLoop(h,t,"alt",_t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos()),Pt.models.addLoop(t);break;case r.db.LINETYPE.PAR_START:case r.db.LINETYPE.PAR_OVER_START:Bt(w,o,_t.boxMargin,_t.boxMargin+_t.boxTextMargin,(t=>Pt.newLoop(t))),Pt.saveVerticalPos();break;case r.db.LINETYPE.PAR_AND:Bt(w,o,_t.boxMargin+_t.boxTextMargin,_t.boxMargin,(t=>Pt.addSectionToLoop(t)));break;case r.db.LINETYPE.PAR_END:t=Pt.endLoop(),await Lt.drawLoop(h,t,"par",_t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos()),Pt.models.addLoop(t);break;case r.db.LINETYPE.AUTONUMBER:L=o.message.start||L,_=o.message.step||_,o.message.visible?r.db.enableSequenceNumbers():r.db.disableSequenceNumbers();break;case r.db.LINETYPE.CRITICAL_START:Bt(w,o,_t.boxMargin,_t.boxMargin+_t.boxTextMargin,(t=>Pt.newLoop(t)));break;case r.db.LINETYPE.CRITICAL_OPTION:Bt(w,o,_t.boxMargin+_t.boxTextMargin,_t.boxMargin,(t=>Pt.addSectionToLoop(t)));break;case r.db.LINETYPE.CRITICAL_END:t=Pt.endLoop(),await Lt.drawLoop(h,t,"critical",_t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos()),Pt.models.addLoop(t);break;case r.db.LINETYPE.BREAK_START:Bt(w,o,_t.boxMargin,_t.boxMargin+_t.boxTextMargin,(t=>Pt.newLoop(t)));break;case r.db.LINETYPE.BREAK_END:t=Pt.endLoop(),await Lt.drawLoop(h,t,"break",_t),Pt.bumpVerticalPos(t.stopy-Pt.getVerticalPos()),Pt.models.addLoop(t);break;default:try{a=o.msgModel,a.starty=Pt.getVerticalPos(),a.sequenceIndex=L,a.sequenceVisible=r.db.showSequenceNumbers();const t=await Mt(0,a);$t(o,a,t,A,p,g,u),P.push({messageModel:a,lineStartY:t}),Pt.models.addMessage(a)}catch(R){n.Rm.error("error while drawing message",R)}}[r.db.LINETYPE.SOLID_OPEN,r.db.LINETYPE.DOTTED_OPEN,r.db.LINETYPE.SOLID,r.db.LINETYPE.DOTTED,r.db.LINETYPE.SOLID_CROSS,r.db.LINETYPE.DOTTED_CROSS,r.db.LINETYPE.SOLID_POINT,r.db.LINETYPE.DOTTED_POINT,r.db.LINETYPE.BIDIRECTIONAL_SOLID,r.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(o.type)&&(L+=_),A++}n.Rm.debug("createdActors",g),n.Rm.debug("destroyedActors",u),await St(h,p,y,!1);for(const n of P)await Dt(h,n.messageModel,n.lineStartY,r);_t.mirrorActors&&await St(h,p,y,!0),k.forEach((t=>Lt.drawBackgroundRect(h,t))),st(h,p,y,_t);for(const n of Pt.models.boxes)n.height=Pt.getVerticalPos()-n.y,Pt.insert(n.x,n.y,n.x+n.width,n.height),n.startx=n.x,n.starty=n.y,n.stopx=n.startx+n.width,n.stopy=n.starty+n.height,n.stroke="rgb(0,0,0, 0.5)",Lt.drawBox(h,n,_t);T&&Pt.bumpVerticalPos(_t.boxMargin);const v=Kt(h,p,y,d),{bounds:N}=Pt.getBounds();void 0===N.startx&&(N.startx=0),void 0===N.starty&&(N.starty=0),void 0===N.stopx&&(N.stopx=0),void 0===N.stopy&&(N.stopy=0);let M=N.stopy-N.starty;M<v.maxHeight&&(M=v.maxHeight);let D=M+2*_t.diagramMarginY;_t.mirrorActors&&(D=D-_t.boxMargin+_t.bottomMarginAdj);let O=N.stopx-N.startx;O<v.maxWidth&&(O=v.maxWidth);const S=O+2*_t.diagramMarginX;b&&h.append("text").text(b).attr("x",(N.stopx-N.startx)/2-2*_t.diagramMarginX).attr("y",-25),(0,n.a$)(h,D,S,_t.useMaxWidth);const K=b?40:0;h.attr("viewBox",N.startx-_t.diagramMarginX+" -"+(_t.diagramMarginY+K)+" "+S+" "+(D+K)),n.Rm.debug("models:",Pt.models)}),"draw");async function Ft(t,e,a){const r={};for(const s of e)if(t.get(s.to)&&t.get(s.from)){const e=t.get(s.to);if(s.placement===a.db.PLACEMENT.LEFTOF&&!e.prevActor)continue;if(s.placement===a.db.PLACEMENT.RIGHTOF&&!e.nextActor)continue;const o=void 0!==s.placement,c=!o,l=o?vt(_t):At(_t),d=s.wrap?i._K.wrapLabel(s.message,_t.width-2*_t.wrapPadding,l):s.message,h=((0,n.Wi)(d)?await(0,n.Dl)(s.message,(0,n.D7)()):i._K.calculateTextDimensions(d,l)).width+2*_t.wrapPadding;c&&s.from===e.nextActor?r[s.to]=n.Y2.getMax(r[s.to]||0,h):c&&s.from===e.prevActor?r[s.from]=n.Y2.getMax(r[s.from]||0,h):c&&s.from===s.to?(r[s.from]=n.Y2.getMax(r[s.from]||0,h/2),r[s.to]=n.Y2.getMax(r[s.to]||0,h/2)):s.placement===a.db.PLACEMENT.RIGHTOF?r[s.from]=n.Y2.getMax(r[s.from]||0,h):s.placement===a.db.PLACEMENT.LEFTOF?r[e.prevActor]=n.Y2.getMax(r[e.prevActor]||0,h):s.placement===a.db.PLACEMENT.OVER&&(e.prevActor&&(r[e.prevActor]=n.Y2.getMax(r[e.prevActor]||0,h/2)),e.nextActor&&(r[s.from]=n.Y2.getMax(r[s.from]||0,h/2)))}return n.Rm.debug("maxMessageWidthPerActor:",r),r}(0,n.K2)(Ft,"getMaxMessageWidthPerActor");var Wt=(0,n.K2)((function(t){let e=0;const a=Nt(_t);for(const r in t.links){const t=i._K.calculateTextDimensions(r,a).width+2*_t.wrapPadding+2*_t.boxMargin;e<t&&(e=t)}return e}),"getRequiredPopupWidth");async function qt(t,e,a){let r=0;for(const o of t.keys()){const e=t.get(o);e.wrap&&(e.description=i._K.wrapLabel(e.description,_t.width-2*_t.wrapPadding,Nt(_t)));const a=(0,n.Wi)(e.description)?await(0,n.Dl)(e.description,(0,n.D7)()):i._K.calculateTextDimensions(e.description,Nt(_t));e.width=e.wrap?_t.width:n.Y2.getMax(_t.width,a.width+2*_t.wrapPadding),e.height=e.wrap?n.Y2.getMax(a.height,_t.height):_t.height,r=n.Y2.getMax(r,e.height)}for(const i in e){const a=t.get(i);if(!a)continue;const r=t.get(a.nextActor);if(!r){const t=e[i]+_t.actorMargin-a.width/2;a.margin=n.Y2.getMax(t,_t.actorMargin);continue}const s=e[i]+_t.actorMargin-a.width/2-r.width/2;a.margin=n.Y2.getMax(s,_t.actorMargin)}let s=0;return a.forEach((e=>{const a=At(_t);let r=e.actorKeys.reduce(((e,a)=>e+(t.get(a).width+(t.get(a).margin||0))),0);r-=2*_t.boxTextMargin,e.wrap&&(e.name=i._K.wrapLabel(e.name,r-2*_t.wrapPadding,a));const o=i._K.calculateTextDimensions(e.name,a);s=n.Y2.getMax(o.height,s);const c=n.Y2.getMax(r,o.width+2*_t.wrapPadding);if(e.margin=_t.boxTextMargin,r<c){const t=(c-r)/2;e.margin+=t}})),a.forEach((t=>t.textMaxHeight=s)),n.Y2.getMax(r,_t.height)}(0,n.K2)(qt,"calculateActorMargins");var zt=(0,n.K2)((async function(t,e,a){const r=e.get(t.from),s=e.get(t.to),o=r.x,c=s.x,l=t.wrap&&t.message;let d=(0,n.Wi)(t.message)?await(0,n.Dl)(t.message,(0,n.D7)()):i._K.calculateTextDimensions(l?i._K.wrapLabel(t.message,_t.width,vt(_t)):t.message,vt(_t));const h={width:l?_t.width:n.Y2.getMax(_t.width,d.width+2*_t.noteMargin),height:0,startx:r.x,stopx:0,starty:0,stopy:0,message:t.message};return t.placement===a.db.PLACEMENT.RIGHTOF?(h.width=l?n.Y2.getMax(_t.width,d.width):n.Y2.getMax(r.width/2+s.width/2,d.width+2*_t.noteMargin),h.startx=o+(r.width+_t.actorMargin)/2):t.placement===a.db.PLACEMENT.LEFTOF?(h.width=l?n.Y2.getMax(_t.width,d.width+2*_t.noteMargin):n.Y2.getMax(r.width/2+s.width/2,d.width+2*_t.noteMargin),h.startx=o-h.width+(r.width-_t.actorMargin)/2):t.to===t.from?(d=i._K.calculateTextDimensions(l?i._K.wrapLabel(t.message,n.Y2.getMax(_t.width,r.width),vt(_t)):t.message,vt(_t)),h.width=l?n.Y2.getMax(_t.width,r.width):n.Y2.getMax(r.width,_t.width,d.width+2*_t.noteMargin),h.startx=o+(r.width-h.width)/2):(h.width=Math.abs(o+r.width/2-(c+s.width/2))+_t.actorMargin,h.startx=o<c?o+r.width/2-_t.actorMargin/2:c+s.width/2-_t.actorMargin/2),l&&(h.message=i._K.wrapLabel(t.message,h.width-2*_t.wrapPadding,vt(_t))),n.Rm.debug(`NM:[${h.startx},${h.stopx},${h.starty},${h.stopy}:${h.width},${h.height}=${t.message}]`),h}),"buildNoteModel"),Ht=(0,n.K2)((function(t,e,a){if(![a.db.LINETYPE.SOLID_OPEN,a.db.LINETYPE.DOTTED_OPEN,a.db.LINETYPE.SOLID,a.db.LINETYPE.DOTTED,a.db.LINETYPE.SOLID_CROSS,a.db.LINETYPE.DOTTED_CROSS,a.db.LINETYPE.SOLID_POINT,a.db.LINETYPE.DOTTED_POINT,a.db.LINETYPE.BIDIRECTIONAL_SOLID,a.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(t.type))return{};const[r,s]=Ct(t.from,e),[o,c]=Ct(t.to,e),l=r<=o;let d=l?s:r,h=l?o:c;const p=Math.abs(o-c)>2,g=(0,n.K2)((t=>l?-t:t),"adjustValue");t.from===t.to?h=d:(t.activate&&!p&&(h+=g(_t.activationWidth/2-1)),[a.db.LINETYPE.SOLID_OPEN,a.db.LINETYPE.DOTTED_OPEN].includes(t.type)||(h+=g(3)),[a.db.LINETYPE.BIDIRECTIONAL_SOLID,a.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(t.type)&&(d-=g(3)));const u=[r,s,o,c],x=Math.abs(d-h);t.wrap&&t.message&&(t.message=i._K.wrapLabel(t.message,n.Y2.getMax(x+2*_t.wrapPadding,_t.width),At(_t)));const y=i._K.calculateTextDimensions(t.message,At(_t));return{width:n.Y2.getMax(t.wrap?0:y.width+2*_t.wrapPadding,x+2*_t.wrapPadding,_t.width),height:0,startx:d,stopx:h,starty:0,stopy:0,message:t.message,type:t.type,wrap:t.wrap,fromBounds:Math.min.apply(null,u),toBounds:Math.max.apply(null,u)}}),"buildMessageModel"),jt=(0,n.K2)((async function(t,e,a,r){const s={},o=[];let c,l,d;for(const h of t){switch(h.id=i._K.random({length:10}),h.type){case r.db.LINETYPE.LOOP_START:case r.db.LINETYPE.ALT_START:case r.db.LINETYPE.OPT_START:case r.db.LINETYPE.PAR_START:case r.db.LINETYPE.PAR_OVER_START:case r.db.LINETYPE.CRITICAL_START:case r.db.LINETYPE.BREAK_START:o.push({id:h.id,msg:h.message,from:Number.MAX_SAFE_INTEGER,to:Number.MIN_SAFE_INTEGER,width:0});break;case r.db.LINETYPE.ALT_ELSE:case r.db.LINETYPE.PAR_AND:case r.db.LINETYPE.CRITICAL_OPTION:h.message&&(c=o.pop(),s[c.id]=c,s[h.id]=c,o.push(c));break;case r.db.LINETYPE.LOOP_END:case r.db.LINETYPE.ALT_END:case r.db.LINETYPE.OPT_END:case r.db.LINETYPE.PAR_END:case r.db.LINETYPE.CRITICAL_END:case r.db.LINETYPE.BREAK_END:c=o.pop(),s[c.id]=c;break;case r.db.LINETYPE.ACTIVE_START:{const t=e.get(h.from?h.from:h.to.actor),a=Yt(h.from?h.from:h.to.actor).length,r=t.x+t.width/2+(a-1)*_t.activationWidth/2,s={startx:r,stopx:r+_t.activationWidth,actor:h.from,enabled:!0};Pt.activations.push(s)}break;case r.db.LINETYPE.ACTIVE_END:{const t=Pt.activations.map((t=>t.actor)).lastIndexOf(h.from);Pt.activations.splice(t,1).splice(0,1)}}void 0!==h.placement?(l=await zt(h,e,r),h.noteModel=l,o.forEach((t=>{c=t,c.from=n.Y2.getMin(c.from,l.startx),c.to=n.Y2.getMax(c.to,l.startx+l.width),c.width=n.Y2.getMax(c.width,Math.abs(c.from-c.to))-_t.labelBoxWidth}))):(d=Ht(h,e,r),h.msgModel=d,d.startx&&d.stopx&&o.length>0&&o.forEach((t=>{if(c=t,d.startx===d.stopx){const t=e.get(h.from),a=e.get(h.to);c.from=n.Y2.getMin(t.x-d.width/2,t.x-t.width/2,c.from),c.to=n.Y2.getMax(a.x+d.width/2,a.x+t.width/2,c.to),c.width=n.Y2.getMax(c.width,Math.abs(c.to-c.from))-_t.labelBoxWidth}else c.from=n.Y2.getMin(d.startx,c.from),c.to=n.Y2.getMax(d.stopx,c.to),c.width=n.Y2.getMax(c.width,d.width)-_t.labelBoxWidth})))}return Pt.activations=[],n.Rm.debug("Loop type widths:",s),s}),"calculateLoopBounds"),Ut={parser:d,db:H,renderer:{bounds:Pt,drawActors:St,drawActorsPopup:Kt,setConf:Rt,draw:Vt},styles:j,init:(0,n.K2)((({wrap:t})=>{H.setWrap(t)}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8731.9d83d3f0.js b/pr-preview/pr-1071/assets/js/8731.9d83d3f0.js deleted file mode 100644 index 8b0b9cc66d..0000000000 --- a/pr-preview/pr-1071/assets/js/8731.9d83d3f0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8731],{59850:(e,t,n)=>{t.Qi=t.XO=void 0;const r=n(69590),i=n(78585),s=n(62676);var o;!function(e){e.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:s.Event.None}),e.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:s.Event.None}),e.is=function(t){const n=t;return n&&(n===e.None||n===e.Cancelled||i.boolean(n.isCancellationRequested)&&!!n.onCancellationRequested)}}(o||(t.XO=o={}));const a=Object.freeze((function(e,t){const n=(0,r.default)().timer.setTimeout(e.bind(t),0);return{dispose(){n.dispose()}}}));class c{constructor(){this._isCancelled=!1}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?a:(this._emitter||(this._emitter=new s.Emitter),this._emitter.event)}dispose(){this._emitter&&(this._emitter.dispose(),this._emitter=void 0)}}t.Qi=class{get token(){return this._token||(this._token=new c),this._token}cancel(){this._token?this._token.cancel():this._token=o.Cancelled}dispose(){this._token?this._token instanceof c&&this._token.dispose():this._token=o.None}}},62676:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Emitter=t.Event=void 0;const r=n(69590);var i;!function(e){const t={dispose(){}};e.None=function(){return t}}(i||(t.Event=i={}));class s{add(e,t=null,n){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(e),this._contexts.push(t),Array.isArray(n)&&n.push({dispose:()=>this.remove(e,t)})}remove(e,t=null){if(!this._callbacks)return;let n=!1;for(let r=0,i=this._callbacks.length;r<i;r++)if(this._callbacks[r]===e){if(this._contexts[r]===t)return this._callbacks.splice(r,1),void this._contexts.splice(r,1);n=!0}if(n)throw new Error("When adding a listener with a context, you should remove it with the same context")}invoke(...e){if(!this._callbacks)return[];const t=[],n=this._callbacks.slice(0),i=this._contexts.slice(0);for(let o=0,a=n.length;o<a;o++)try{t.push(n[o].apply(i[o],e))}catch(s){(0,r.default)().console.error(s)}return t}isEmpty(){return!this._callbacks||0===this._callbacks.length}dispose(){this._callbacks=void 0,this._contexts=void 0}}class o{constructor(e){this._options=e}get event(){return this._event||(this._event=(e,t,n)=>{this._callbacks||(this._callbacks=new s),this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(e,t);const r={dispose:()=>{this._callbacks&&(this._callbacks.remove(e,t),r.dispose=o._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))}};return Array.isArray(n)&&n.push(r),r}),this._event}fire(e){this._callbacks&&this._callbacks.invoke.call(this._callbacks,e)}dispose(){this._callbacks&&(this._callbacks.dispose(),this._callbacks=void 0)}}t.Emitter=o,o._noop=function(){}},78585:(e,t)=>{function n(e){return"string"==typeof e||e instanceof String}function r(e){return Array.isArray(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.stringArray=t.array=t.func=t.error=t.number=t.string=t.boolean=void 0,t.boolean=function(e){return!0===e||!1===e},t.string=n,t.number=function(e){return"number"==typeof e||e instanceof Number},t.error=function(e){return e instanceof Error},t.func=function(e){return"function"==typeof e},t.array=r,t.stringArray=function(e){return r(e)&&e.every((e=>n(e)))}},69590:(e,t)=>{let n;function r(){if(void 0===n)throw new Error("No runtime abstraction layer installed");return n}Object.defineProperty(t,"__esModule",{value:!0}),function(e){e.install=function(e){if(void 0===e)throw new Error("No runtime abstraction layer provided");n=e}}(r||(r={})),t.default=r},97021:(e,t,n)=>{n.d(t,{v:()=>a});var r=n(19369),i=n(33394),s=class extends r.mR{static{(0,r.K2)(this,"InfoTokenBuilder")}constructor(){super(["info","showInfo"])}},o={parser:{TokenBuilder:(0,r.K2)((()=>new s),"TokenBuilder"),ValueConverter:(0,r.K2)((()=>new r.Tm),"ValueConverter")}};function a(e=i.DD){const t=(0,i.WQ)((0,i.uM)(e),r.sr),n=(0,i.WQ)((0,i.tG)({shared:t}),r.e5,o);return t.ServiceRegistry.register(n),{shared:t,Info:n}}(0,r.K2)(a,"createInfoServices")},88685:(e,t,n)=>{n.d(t,{f:()=>c});var r=n(19369),i=n(33394),s=class extends r.mR{static{(0,r.K2)(this,"PieTokenBuilder")}constructor(){super(["pie","showData"])}},o=class extends r.dg{static{(0,r.K2)(this,"PieValueConverter")}runCustomConverter(e,t,n){if("PIE_SECTION_LABEL"===e.name)return t.replace(/"/g,"").trim()}},a={parser:{TokenBuilder:(0,r.K2)((()=>new s),"TokenBuilder"),ValueConverter:(0,r.K2)((()=>new o),"ValueConverter")}};function c(e=i.DD){const t=(0,i.WQ)((0,i.uM)(e),r.sr),n=(0,i.WQ)((0,i.tG)({shared:t}),r.KX,a);return t.ServiceRegistry.register(n),{shared:t,Pie:n}}(0,r.K2)(c,"createPieServices")},71609:(e,t,n)=>{n.d(t,{$:()=>a});var r=n(19369),i=n(33394),s=class extends r.mR{static{(0,r.K2)(this,"PacketTokenBuilder")}constructor(){super(["packet-beta"])}},o={parser:{TokenBuilder:(0,r.K2)((()=>new s),"TokenBuilder"),ValueConverter:(0,r.K2)((()=>new r.Tm),"ValueConverter")}};function a(e=i.DD){const t=(0,i.WQ)((0,i.uM)(e),r.sr),n=(0,i.WQ)((0,i.tG)({shared:t}),r.AM,o);return t.ServiceRegistry.register(n),{shared:t,Packet:n}}(0,r.K2)(a,"createPacketServices")},49936:(e,t,n)=>{n.d(t,{S:()=>c});var r=n(19369),i=n(33394),s=class extends r.mR{static{(0,r.K2)(this,"ArchitectureTokenBuilder")}constructor(){super(["architecture"])}},o=class extends r.dg{static{(0,r.K2)(this,"ArchitectureValueConverter")}runCustomConverter(e,t,n){return"ARCH_ICON"===e.name?t.replace(/[()]/g,"").trim():"ARCH_TEXT_ICON"===e.name?t.replace(/["()]/g,""):"ARCH_TITLE"===e.name?t.replace(/[[\]]/g,"").trim():void 0}},a={parser:{TokenBuilder:(0,r.K2)((()=>new s),"TokenBuilder"),ValueConverter:(0,r.K2)((()=>new o),"ValueConverter")}};function c(e=i.DD){const t=(0,i.WQ)((0,i.uM)(e),r.sr),n=(0,i.WQ)((0,i.tG)({shared:t}),r.jE,a);return t.ServiceRegistry.register(n),{shared:t,Architecture:n}}(0,r.K2)(c,"createArchitectureServices")},82785:(e,t,n)=>{n.d(t,{b:()=>a});var r=n(19369),i=n(33394),s=class extends r.mR{static{(0,r.K2)(this,"GitGraphTokenBuilder")}constructor(){super(["gitGraph"])}},o={parser:{TokenBuilder:(0,r.K2)((()=>new s),"TokenBuilder"),ValueConverter:(0,r.K2)((()=>new r.Tm),"ValueConverter")}};function a(e=i.DD){const t=(0,i.WQ)((0,i.uM)(e),r.sr),n=(0,i.WQ)((0,i.tG)({shared:t}),r.eZ,o);return t.ServiceRegistry.register(n),{shared:t,GitGraph:n}}(0,r.K2)(a,"createGitGraphServices")},19369:(e,t,n)=>{n.d(t,{AM:()=>$,K2:()=>s,KX:()=>w,Tm:()=>P,dg:()=>_,e5:()=>C,eZ:()=>O,jE:()=>L,mR:()=>M,sr:()=>N});var r=n(33394),i=Object.defineProperty,s=(e,t)=>i(e,"name",{value:t,configurable:!0});s((function(e){return g.isInstance(e,"Architecture")}),"isArchitecture");var o="Branch";s((function(e){return g.isInstance(e,o)}),"isBranch");var a="Commit";s((function(e){return g.isInstance(e,a)}),"isCommit");s((function(e){return g.isInstance(e,"Common")}),"isCommon");var c="GitGraph";s((function(e){return g.isInstance(e,c)}),"isGitGraph");s((function(e){return g.isInstance(e,"Info")}),"isInfo");var l="Merge";s((function(e){return g.isInstance(e,l)}),"isMerge");s((function(e){return g.isInstance(e,"Packet")}),"isPacket");s((function(e){return g.isInstance(e,"PacketBlock")}),"isPacketBlock");s((function(e){return g.isInstance(e,"Pie")}),"isPie");s((function(e){return g.isInstance(e,"PieSection")}),"isPieSection");var u,d,h,f,p,m=class extends r.kD{static{s(this,"MermaidAstReflection")}getAllTypes(){return["Architecture","Branch","Checkout","CherryPicking","Commit","Common","Direction","Edge","GitGraph","Group","Info","Junction","Merge","Packet","PacketBlock","Pie","PieSection","Service","Statement"]}computeIsSubtype(e,t){switch(e){case o:case"Checkout":case"CherryPicking":case a:case l:return this.isSubtype("Statement",t);case"Direction":return this.isSubtype(c,t);default:return!1}}getReferenceType(e){const t=`${e.container.$type}:${e.property}`;throw new Error(`${t} is not a valid reference id.`)}getTypeMetaData(e){switch(e){case"Architecture":return{name:"Architecture",properties:[{name:"accDescr"},{name:"accTitle"},{name:"edges",defaultValue:[]},{name:"groups",defaultValue:[]},{name:"junctions",defaultValue:[]},{name:"services",defaultValue:[]},{name:"title"}]};case"Branch":return{name:"Branch",properties:[{name:"name"},{name:"order"}]};case"Checkout":return{name:"Checkout",properties:[{name:"branch"}]};case"CherryPicking":return{name:"CherryPicking",properties:[{name:"id"},{name:"parent"},{name:"tags",defaultValue:[]}]};case"Commit":return{name:"Commit",properties:[{name:"id"},{name:"message"},{name:"tags",defaultValue:[]},{name:"type"}]};case"Common":return{name:"Common",properties:[{name:"accDescr"},{name:"accTitle"},{name:"title"}]};case"Edge":return{name:"Edge",properties:[{name:"lhsDir"},{name:"lhsGroup",defaultValue:!1},{name:"lhsId"},{name:"lhsInto",defaultValue:!1},{name:"rhsDir"},{name:"rhsGroup",defaultValue:!1},{name:"rhsId"},{name:"rhsInto",defaultValue:!1},{name:"title"}]};case"GitGraph":return{name:"GitGraph",properties:[{name:"accDescr"},{name:"accTitle"},{name:"statements",defaultValue:[]},{name:"title"}]};case"Group":return{name:"Group",properties:[{name:"icon"},{name:"id"},{name:"in"},{name:"title"}]};case"Info":return{name:"Info",properties:[{name:"accDescr"},{name:"accTitle"},{name:"title"}]};case"Junction":return{name:"Junction",properties:[{name:"id"},{name:"in"}]};case"Merge":return{name:"Merge",properties:[{name:"branch"},{name:"id"},{name:"tags",defaultValue:[]},{name:"type"}]};case"Packet":return{name:"Packet",properties:[{name:"accDescr"},{name:"accTitle"},{name:"blocks",defaultValue:[]},{name:"title"}]};case"PacketBlock":return{name:"PacketBlock",properties:[{name:"end"},{name:"label"},{name:"start"}]};case"Pie":return{name:"Pie",properties:[{name:"accDescr"},{name:"accTitle"},{name:"sections",defaultValue:[]},{name:"showData",defaultValue:!1},{name:"title"}]};case"PieSection":return{name:"PieSection",properties:[{name:"label"},{name:"value"}]};case"Service":return{name:"Service",properties:[{name:"icon"},{name:"iconText"},{name:"id"},{name:"in"},{name:"title"}]};case"Direction":return{name:"Direction",properties:[{name:"accDescr"},{name:"accTitle"},{name:"dir"},{name:"statements",defaultValue:[]},{name:"title"}]};default:return{name:e,properties:[]}}}},g=new m,y=s((()=>u??(u=(0,r.y0)('{"$type":"Grammar","isDeclared":true,"name":"Info","imports":[],"rules":[{"$type":"ParserRule","name":"Info","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"info"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"showInfo"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"*"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"?"}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}'))),"InfoGrammar"),A=s((()=>d??(d=(0,r.y0)('{"$type":"Grammar","isDeclared":true,"name":"Packet","imports":[],"rules":[{"$type":"ParserRule","name":"Packet","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"packet-beta"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"blocks","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"Assignment","feature":"blocks","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"+"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"PacketBlock","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"start","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"end","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"?"},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|\'[^\']*\'/"},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}'))),"PacketGrammar"),T=s((()=>h??(h=(0,r.y0)('{"$type":"Grammar","isDeclared":true,"name":"Pie","imports":[],"rules":[{"$type":"ParserRule","name":"Pie","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"pie"},{"$type":"Assignment","feature":"showData","operator":"?=","terminal":{"$type":"Keyword","value":"showData"},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"sections","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"Assignment","feature":"sections","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},"cardinality":"+"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"PieSection","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"PIE_SECTION_LABEL","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]+\\"/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"PIE_SECTION_VALUE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/(0|[1-9][0-9]*)(\\\\.[0-9]+)?/"},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}'))),"PieGrammar"),v=s((()=>f??(f=(0,r.y0)('{"$type":"Grammar","isDeclared":true,"name":"Architecture","imports":[],"rules":[{"$type":"ParserRule","name":"Architecture","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"architecture-beta"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"*"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Statement","fragment":true,"definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"groups","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"services","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"junctions","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"edges","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"LeftPort","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"lhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"RightPort","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"rhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Keyword","value":":"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Arrow","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]},{"$type":"Assignment","feature":"lhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"--"},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Keyword","value":"-"}]}]},{"$type":"Assignment","feature":"rhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Group","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"group"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Service","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"service"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"iconText","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Junction","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"junction"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Edge","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"lhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"lhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"rhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"rhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"ARROW_DIRECTION","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"L"}},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"R"}}]},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"T"}}]},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"B"}}]},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_ID","definition":{"$type":"RegexToken","regex":"/[\\\\w]+/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_TEXT_ICON","definition":{"$type":"RegexToken","regex":"/\\\\(\\"[^\\"]+\\"\\\\)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_ICON","definition":{"$type":"RegexToken","regex":"/\\\\([\\\\w-:]+\\\\)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_TITLE","definition":{"$type":"RegexToken","regex":"/\\\\[[\\\\w ]+\\\\]/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_GROUP","definition":{"$type":"RegexToken","regex":"/\\\\{group\\\\}/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_INTO","definition":{"$type":"RegexToken","regex":"/<|>/"},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false}],"definesHiddenTokens":false,"hiddenTokens":[],"interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"types":[],"usedGrammars":[]}'))),"ArchitectureGrammar"),R=s((()=>p??(p=(0,r.y0)('{"$type":"Grammar","isDeclared":true,"name":"GitGraph","interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"rules":[{"$type":"ParserRule","name":"TitleAndAccessibilities","fragment":true,"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"+"},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"EOL","fragment":true,"dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"definesHiddenTokens":false,"entry":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/"},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/"},"fragment":false},{"$type":"ParserRule","name":"GitGraph","entry":true,"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Keyword","value":":"}]},{"$type":"Keyword","value":"gitGraph:"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},{"$type":"Keyword","value":":"}]}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]},{"$type":"Assignment","feature":"statements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}],"cardinality":"*"}]}]},"definesHiddenTokens":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Direction","definition":{"$type":"Assignment","feature":"dir","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"LR"},{"$type":"Keyword","value":"TB"},{"$type":"Keyword","value":"BT"}]}},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Commit","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"commit"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"msg:","cardinality":"?"},{"$type":"Assignment","feature":"message","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Branch","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"branch"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"order:"},{"$type":"Assignment","feature":"order","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Merge","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"merge"},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]}},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"Checkout","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"checkout"},{"$type":"Keyword","value":"switch"}]},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"ParserRule","name":"CherryPicking","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"cherry-pick"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"parent:"},{"$type":"Assignment","feature":"parent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}]},"definesHiddenTokens":false,"entry":false,"fragment":false,"hiddenTokens":[],"parameters":[],"wildcard":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+(?=\\\\s)/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\\\w([-\\\\./\\\\w]*[-\\\\w])?/"},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|\'[^\']*\'/"},"fragment":false,"hidden":false}],"definesHiddenTokens":false,"hiddenTokens":[],"imports":[],"types":[],"usedGrammars":[]}'))),"GitGraphGrammar"),E={languageId:"info",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},k={languageId:"packet",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},x={languageId:"pie",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},I={languageId:"architecture",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},S={languageId:"gitGraph",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1},N={AstReflection:s((()=>new m),"AstReflection")},C={Grammar:s((()=>y()),"Grammar"),LanguageMetaData:s((()=>E),"LanguageMetaData"),parser:{}},$={Grammar:s((()=>A()),"Grammar"),LanguageMetaData:s((()=>k),"LanguageMetaData"),parser:{}},w={Grammar:s((()=>T()),"Grammar"),LanguageMetaData:s((()=>x),"LanguageMetaData"),parser:{}},L={Grammar:s((()=>v()),"Grammar"),LanguageMetaData:s((()=>I),"LanguageMetaData"),parser:{}},O={Grammar:s((()=>R()),"Grammar"),LanguageMetaData:s((()=>S),"LanguageMetaData"),parser:{}},b={ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/accTitle[\t ]*:([^\n\r]*)/,TITLE:/title([\t ][^\n\r]*|)/},_=class extends r.dM{static{s(this,"AbstractMermaidValueConverter")}runConverter(e,t,n){let r=this.runCommonConverter(e,t,n);return void 0===r&&(r=this.runCustomConverter(e,t,n)),void 0===r?super.runConverter(e,t,n):r}runCommonConverter(e,t,n){const r=b[e.name];if(void 0===r)return;const i=r.exec(t);return null!==i?void 0!==i[1]?i[1].trim().replace(/[\t ]{2,}/gm," "):void 0!==i[2]?i[2].replace(/^\s*/gm,"").replace(/\s+$/gm,"").replace(/[\t ]{2,}/gm," ").replace(/[\n\r]{2,}/gm,"\n"):void 0:void 0}},P=class extends _{static{s(this,"CommonValueConverter")}runCustomConverter(e,t,n){}},M=class extends r.QU{static{s(this,"AbstractMermaidTokenBuilder")}constructor(e){super(),this.keywords=new Set(e)}buildKeywordTokens(e,t,n){const r=super.buildKeywordTokens(e,t,n);return r.forEach((e=>{this.keywords.has(e.name)&&void 0!==e.PATTERN&&(e.PATTERN=new RegExp(e.PATTERN.toString()+"(?:(?=%%)|(?!\\S))"))})),r}};(class extends M{static{s(this,"CommonTokenBuilder")}})},78731:(e,t,n)=>{n.d(t,{qg:()=>o});n(82785),n(97021),n(71609),n(88685),n(49936);var r=n(19369),i={},s={info:(0,r.K2)((async()=>{const{createInfoServices:e}=await n.e(890).then(n.bind(n,10890)),t=e().Info.parser.LangiumParser;i.info=t}),"info"),packet:(0,r.K2)((async()=>{const{createPacketServices:e}=await n.e(6452).then(n.bind(n,6452)),t=e().Packet.parser.LangiumParser;i.packet=t}),"packet"),pie:(0,r.K2)((async()=>{const{createPieServices:e}=await n.e(7723).then(n.bind(n,57723)),t=e().Pie.parser.LangiumParser;i.pie=t}),"pie"),architecture:(0,r.K2)((async()=>{const{createArchitectureServices:e}=await n.e(9720).then(n.bind(n,39720)),t=e().Architecture.parser.LangiumParser;i.architecture=t}),"architecture"),gitGraph:(0,r.K2)((async()=>{const{createGitGraphServices:e}=await n.e(2387).then(n.bind(n,82387)),t=e().GitGraph.parser.LangiumParser;i.gitGraph=t}),"gitGraph")};async function o(e,t){const n=s[e];if(!n)throw new Error(`Unknown diagram type: ${e}`);i[e]||await n();const r=i[e].parse(t);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new a(r);return r.value}(0,r.K2)(o,"parse");var a=class extends Error{constructor(e){super(`Parsing failed: ${e.lexerErrors.map((e=>e.message)).join("\n")} ${e.parserErrors.map((e=>e.message)).join("\n")}`),this.result=e}static{(0,r.K2)(this,"MermaidParseError")}}},33394:(e,t,n)=>{function r(e){return"object"==typeof e&&null!==e&&"string"==typeof e.$type}function i(e){return"object"==typeof e&&null!==e&&"string"==typeof e.$refText}function s(e){return"object"==typeof e&&null!==e&&r(e.container)&&i(e.reference)&&"string"==typeof e.message}n.d(t,{kD:()=>o,QU:()=>Hc,dM:()=>Wc,DD:()=>Lu,tG:()=>Eu,uM:()=>ku,WQ:()=>xu,y0:()=>_u});class o{constructor(){this.subtypes={},this.allSubtypes={}}isInstance(e,t){return r(e)&&this.isSubtype(e.$type,t)}isSubtype(e,t){if(e===t)return!0;let n=this.subtypes[e];n||(n=this.subtypes[e]={});const r=n[t];if(void 0!==r)return r;{const r=this.computeIsSubtype(e,t);return n[t]=r,r}}getAllSubTypes(e){const t=this.allSubtypes[e];if(t)return t;{const t=this.getAllTypes(),n=[];for(const r of t)this.isSubtype(r,e)&&n.push(r);return this.allSubtypes[e]=n,n}}}function a(e){return"object"==typeof e&&null!==e&&Array.isArray(e.content)}function c(e){return"object"==typeof e&&null!==e&&"object"==typeof e.tokenType}function l(e){return a(e)&&"string"==typeof e.fullText}class u{constructor(e,t){this.startFn=e,this.nextFn=t}iterator(){const e={state:this.startFn(),next:()=>this.nextFn(e.state),[Symbol.iterator]:()=>e};return e}[Symbol.iterator](){return this.iterator()}isEmpty(){const e=this.iterator();return Boolean(e.next().done)}count(){const e=this.iterator();let t=0,n=e.next();for(;!n.done;)t++,n=e.next();return t}toArray(){const e=[],t=this.iterator();let n;do{n=t.next(),void 0!==n.value&&e.push(n.value)}while(!n.done);return e}toSet(){return new Set(this)}toMap(e,t){const n=this.map((n=>[e?e(n):n,t?t(n):n]));return new Map(n)}toString(){return this.join()}concat(e){const t=e[Symbol.iterator]();return new u((()=>({first:this.startFn(),firstDone:!1})),(e=>{let n;if(!e.firstDone){do{if(n=this.nextFn(e.first),!n.done)return n}while(!n.done);e.firstDone=!0}do{if(n=t.next(),!n.done)return n}while(!n.done);return p}))}join(e=","){const t=this.iterator();let n,r="",i=!1;do{n=t.next(),n.done||(i&&(r+=e),r+=d(n.value)),i=!0}while(!n.done);return r}indexOf(e,t=0){const n=this.iterator();let r=0,i=n.next();for(;!i.done;){if(r>=t&&i.value===e)return r;i=n.next(),r++}return-1}every(e){const t=this.iterator();let n=t.next();for(;!n.done;){if(!e(n.value))return!1;n=t.next()}return!0}some(e){const t=this.iterator();let n=t.next();for(;!n.done;){if(e(n.value))return!0;n=t.next()}return!1}forEach(e){const t=this.iterator();let n=0,r=t.next();for(;!r.done;)e(r.value,n),r=t.next(),n++}map(e){return new u(this.startFn,(t=>{const{done:n,value:r}=this.nextFn(t);return n?p:{done:!1,value:e(r)}}))}filter(e){return new u(this.startFn,(t=>{let n;do{if(n=this.nextFn(t),!n.done&&e(n.value))return n}while(!n.done);return p}))}nonNullable(){return this.filter((e=>null!=e))}reduce(e,t){const n=this.iterator();let r=t,i=n.next();for(;!i.done;)r=void 0===r?i.value:e(r,i.value),i=n.next();return r}reduceRight(e,t){return this.recursiveReduce(this.iterator(),e,t)}recursiveReduce(e,t,n){const r=e.next();if(r.done)return n;const i=this.recursiveReduce(e,t,n);return void 0===i?r.value:t(i,r.value)}find(e){const t=this.iterator();let n=t.next();for(;!n.done;){if(e(n.value))return n.value;n=t.next()}}findIndex(e){const t=this.iterator();let n=0,r=t.next();for(;!r.done;){if(e(r.value))return n;r=t.next(),n++}return-1}includes(e){const t=this.iterator();let n=t.next();for(;!n.done;){if(n.value===e)return!0;n=t.next()}return!1}flatMap(e){return new u((()=>({this:this.startFn()})),(t=>{do{if(t.iterator){const e=t.iterator.next();if(!e.done)return e;t.iterator=void 0}const{done:n,value:r}=this.nextFn(t.this);if(!n){const n=e(r);if(!h(n))return{done:!1,value:n};t.iterator=n[Symbol.iterator]()}}while(t.iterator);return p}))}flat(e){if(void 0===e&&(e=1),e<=0)return this;const t=e>1?this.flat(e-1):this;return new u((()=>({this:t.startFn()})),(e=>{do{if(e.iterator){const t=e.iterator.next();if(!t.done)return t;e.iterator=void 0}const{done:n,value:r}=t.nextFn(e.this);if(!n){if(!h(r))return{done:!1,value:r};e.iterator=r[Symbol.iterator]()}}while(e.iterator);return p}))}head(){const e=this.iterator().next();if(!e.done)return e.value}tail(e=1){return new u((()=>{const t=this.startFn();for(let n=0;n<e;n++){if(this.nextFn(t).done)return t}return t}),this.nextFn)}limit(e){return new u((()=>({size:0,state:this.startFn()})),(t=>(t.size++,t.size>e?p:this.nextFn(t.state))))}distinct(e){const t=new Set;return this.filter((n=>{const r=e?e(n):n;return!t.has(r)&&(t.add(r),!0)}))}exclude(e,t){const n=new Set;for(const r of e){const e=t?t(r):r;n.add(e)}return this.filter((e=>{const r=t?t(e):e;return!n.has(r)}))}}function d(e){return"string"==typeof e?e:void 0===e?"undefined":"function"==typeof e.toString?e.toString():Object.prototype.toString.call(e)}function h(e){return!!e&&"function"==typeof e[Symbol.iterator]}const f=new u((()=>{}),(()=>p)),p=Object.freeze({done:!0,value:void 0});function m(...e){if(1===e.length){const t=e[0];if(t instanceof u)return t;if(h(t))return new u((()=>t[Symbol.iterator]()),(e=>e.next()));if("number"==typeof t.length)return new u((()=>({index:0})),(e=>e.index<t.length?{done:!1,value:t[e.index++]}:p))}return e.length>1?new u((()=>({collIndex:0,arrIndex:0})),(t=>{do{if(t.iterator){const e=t.iterator.next();if(!e.done)return e;t.iterator=void 0}if(t.array){if(t.arrIndex<t.array.length)return{done:!1,value:t.array[t.arrIndex++]};t.array=void 0,t.arrIndex=0}if(t.collIndex<e.length){const n=e[t.collIndex++];h(n)?t.iterator=n[Symbol.iterator]():n&&"number"==typeof n.length&&(t.array=n)}}while(t.iterator||t.array||t.collIndex<e.length);return p})):f}class g extends u{constructor(e,t,n){super((()=>({iterators:(null==n?void 0:n.includeRoot)?[[e][Symbol.iterator]()]:[t(e)[Symbol.iterator]()],pruned:!1})),(e=>{for(e.pruned&&(e.iterators.pop(),e.pruned=!1);e.iterators.length>0;){const n=e.iterators[e.iterators.length-1].next();if(!n.done)return e.iterators.push(t(n.value)[Symbol.iterator]()),n;e.iterators.pop()}return p}))}iterator(){const e={state:this.startFn(),next:()=>this.nextFn(e.state),prune:()=>{e.state.pruned=!0},[Symbol.iterator]:()=>e};return e}}var y,A;function T(e){return new g(e,(e=>a(e)?e.content:[]),{includeRoot:!0})}function v(e){return{start:{character:e.startColumn-1,line:e.startLine-1},end:{character:e.endColumn,line:e.endLine-1}}}function R(e){if(!e)return;const{offset:t,end:n,range:r}=e;return{range:r,offset:t,end:n,length:n-t}}function E(e,t){const n=function(e,t){if(e.end.line<t.start.line||e.end.line===t.start.line&&e.end.character<e.start.character)return A.Before;if(e.start.line>t.end.line||e.start.line===t.end.line&&e.start.character>t.end.character)return A.After;const n=e.start.line>t.start.line||e.start.line===t.start.line&&e.start.character>=t.start.character,r=e.end.line<t.end.line||e.end.line===t.end.line&&e.end.character<=t.end.character;return n&&r?A.Inside:n?A.OverlapBack:A.OverlapFront}(e,t);return n>A.After}!function(e){e.sum=function(e){return e.reduce(((e,t)=>e+t),0)},e.product=function(e){return e.reduce(((e,t)=>e*t),0)},e.min=function(e){return e.reduce(((e,t)=>Math.min(e,t)))},e.max=function(e){return e.reduce(((e,t)=>Math.max(e,t)))}}(y||(y={})),function(e){e[e.Before=0]="Before",e[e.After=1]="After",e[e.OverlapFront=2]="OverlapFront",e[e.OverlapBack=3]="OverlapBack",e[e.Inside=4]="Inside"}(A||(A={}));const k=/^[\w\p{L}]$/u;function x(e,t){if(e){const n=function(e,t=!0){for(;e.container;){const n=e.container;let r=n.content.indexOf(e);for(;r>0;){r--;const e=n.content[r];if(t||!e.hidden)return e}e=n}return}(e,!0);if(n&&I(n,t))return n;if(l(e)){for(let n=e.content.findIndex((e=>!e.hidden))-1;n>=0;n--){const r=e.content[n];if(I(r,t))return r}}}}function I(e,t){return c(e)&&t.includes(e.tokenType.name)}class S extends Error{constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}}function N(e){throw new Error("Error! The input value was not handled.")}const C="AbstractRule";const $="AbstractType";const w="Condition";const L="TypeDefinition";const O="ValueLiteral";const b="AbstractElement";const _="ArrayLiteral";const P="ArrayType";const M="BooleanLiteral";const D="Conjunction";const U="Disjunction";const F="Grammar";const G="InferredType";function K(e){return Oe.isInstance(e,G)}const B="Interface";function j(e){return Oe.isInstance(e,B)}const V="Negation";const H="NumberLiteral";const W="Parameter";const z="ParameterReference";const Y="ParserRule";function X(e){return Oe.isInstance(e,Y)}const q="ReferenceType";const Q="ReturnType";const J="SimpleType";const Z="StringLiteral";const ee="TerminalRule";function te(e){return Oe.isInstance(e,ee)}const ne="Type";function re(e){return Oe.isInstance(e,ne)}const ie="UnionType";const se="Action";function oe(e){return Oe.isInstance(e,se)}const ae="Alternatives";function ce(e){return Oe.isInstance(e,ae)}const le="Assignment";function ue(e){return Oe.isInstance(e,le)}const de="CharacterRange";const he="CrossReference";function fe(e){return Oe.isInstance(e,he)}const pe="EndOfFile";const me="Group";function ge(e){return Oe.isInstance(e,me)}const ye="Keyword";function Ae(e){return Oe.isInstance(e,ye)}const Te="NegatedToken";const ve="RegexToken";const Re="RuleCall";function Ee(e){return Oe.isInstance(e,Re)}const ke="TerminalAlternatives";const xe="TerminalGroup";const Ie="TerminalRuleCall";function Se(e){return Oe.isInstance(e,Ie)}const Ne="UnorderedGroup";function Ce(e){return Oe.isInstance(e,Ne)}const $e="UntilToken";const we="Wildcard";class Le extends o{getAllTypes(){return["AbstractElement","AbstractRule","AbstractType","Action","Alternatives","ArrayLiteral","ArrayType","Assignment","BooleanLiteral","CharacterRange","Condition","Conjunction","CrossReference","Disjunction","EndOfFile","Grammar","GrammarImport","Group","InferredType","Interface","Keyword","NamedArgument","NegatedToken","Negation","NumberLiteral","Parameter","ParameterReference","ParserRule","ReferenceType","RegexToken","ReturnType","RuleCall","SimpleType","StringLiteral","TerminalAlternatives","TerminalGroup","TerminalRule","TerminalRuleCall","Type","TypeAttribute","TypeDefinition","UnionType","UnorderedGroup","UntilToken","ValueLiteral","Wildcard"]}computeIsSubtype(e,t){switch(e){case se:case ae:case le:case de:case he:case pe:case me:case ye:case Te:case ve:case Re:case ke:case xe:case Ie:case Ne:case $e:case we:return this.isSubtype(b,t);case _:case H:case Z:return this.isSubtype(O,t);case P:case q:case J:case ie:return this.isSubtype(L,t);case M:return this.isSubtype(w,t)||this.isSubtype(O,t);case D:case U:case V:case z:return this.isSubtype(w,t);case G:case B:case ne:return this.isSubtype($,t);case Y:return this.isSubtype(C,t)||this.isSubtype($,t);case ee:return this.isSubtype(C,t);default:return!1}}getReferenceType(e){const t=`${e.container.$type}:${e.property}`;switch(t){case"Action:type":case"CrossReference:type":case"Interface:superTypes":case"ParserRule:returnType":case"SimpleType:typeRef":return $;case"Grammar:hiddenTokens":case"ParserRule:hiddenTokens":case"RuleCall:rule":return C;case"Grammar:usedGrammars":return F;case"NamedArgument:parameter":case"ParameterReference:parameter":return W;case"TerminalRuleCall:rule":return ee;default:throw new Error(`${t} is not a valid reference id.`)}}getTypeMetaData(e){switch(e){case"AbstractElement":return{name:"AbstractElement",properties:[{name:"cardinality"},{name:"lookahead"}]};case"ArrayLiteral":return{name:"ArrayLiteral",properties:[{name:"elements",defaultValue:[]}]};case"ArrayType":return{name:"ArrayType",properties:[{name:"elementType"}]};case"BooleanLiteral":return{name:"BooleanLiteral",properties:[{name:"true",defaultValue:!1}]};case"Conjunction":return{name:"Conjunction",properties:[{name:"left"},{name:"right"}]};case"Disjunction":return{name:"Disjunction",properties:[{name:"left"},{name:"right"}]};case"Grammar":return{name:"Grammar",properties:[{name:"definesHiddenTokens",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"imports",defaultValue:[]},{name:"interfaces",defaultValue:[]},{name:"isDeclared",defaultValue:!1},{name:"name"},{name:"rules",defaultValue:[]},{name:"types",defaultValue:[]},{name:"usedGrammars",defaultValue:[]}]};case"GrammarImport":return{name:"GrammarImport",properties:[{name:"path"}]};case"InferredType":return{name:"InferredType",properties:[{name:"name"}]};case"Interface":return{name:"Interface",properties:[{name:"attributes",defaultValue:[]},{name:"name"},{name:"superTypes",defaultValue:[]}]};case"NamedArgument":return{name:"NamedArgument",properties:[{name:"calledByName",defaultValue:!1},{name:"parameter"},{name:"value"}]};case"Negation":return{name:"Negation",properties:[{name:"value"}]};case"NumberLiteral":return{name:"NumberLiteral",properties:[{name:"value"}]};case"Parameter":return{name:"Parameter",properties:[{name:"name"}]};case"ParameterReference":return{name:"ParameterReference",properties:[{name:"parameter"}]};case"ParserRule":return{name:"ParserRule",properties:[{name:"dataType"},{name:"definesHiddenTokens",defaultValue:!1},{name:"definition"},{name:"entry",defaultValue:!1},{name:"fragment",defaultValue:!1},{name:"hiddenTokens",defaultValue:[]},{name:"inferredType"},{name:"name"},{name:"parameters",defaultValue:[]},{name:"returnType"},{name:"wildcard",defaultValue:!1}]};case"ReferenceType":return{name:"ReferenceType",properties:[{name:"referenceType"}]};case"ReturnType":return{name:"ReturnType",properties:[{name:"name"}]};case"SimpleType":return{name:"SimpleType",properties:[{name:"primitiveType"},{name:"stringType"},{name:"typeRef"}]};case"StringLiteral":return{name:"StringLiteral",properties:[{name:"value"}]};case"TerminalRule":return{name:"TerminalRule",properties:[{name:"definition"},{name:"fragment",defaultValue:!1},{name:"hidden",defaultValue:!1},{name:"name"},{name:"type"}]};case"Type":return{name:"Type",properties:[{name:"name"},{name:"type"}]};case"TypeAttribute":return{name:"TypeAttribute",properties:[{name:"defaultValue"},{name:"isOptional",defaultValue:!1},{name:"name"},{name:"type"}]};case"UnionType":return{name:"UnionType",properties:[{name:"types",defaultValue:[]}]};case"Action":return{name:"Action",properties:[{name:"cardinality"},{name:"feature"},{name:"inferredType"},{name:"lookahead"},{name:"operator"},{name:"type"}]};case"Alternatives":return{name:"Alternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"Assignment":return{name:"Assignment",properties:[{name:"cardinality"},{name:"feature"},{name:"lookahead"},{name:"operator"},{name:"terminal"}]};case"CharacterRange":return{name:"CharacterRange",properties:[{name:"cardinality"},{name:"left"},{name:"lookahead"},{name:"right"}]};case"CrossReference":return{name:"CrossReference",properties:[{name:"cardinality"},{name:"deprecatedSyntax",defaultValue:!1},{name:"lookahead"},{name:"terminal"},{name:"type"}]};case"EndOfFile":return{name:"EndOfFile",properties:[{name:"cardinality"},{name:"lookahead"}]};case"Group":return{name:"Group",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"guardCondition"},{name:"lookahead"}]};case"Keyword":return{name:"Keyword",properties:[{name:"cardinality"},{name:"lookahead"},{name:"value"}]};case"NegatedToken":return{name:"NegatedToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"RegexToken":return{name:"RegexToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"regex"}]};case"RuleCall":return{name:"RuleCall",properties:[{name:"arguments",defaultValue:[]},{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"TerminalAlternatives":return{name:"TerminalAlternatives",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalGroup":return{name:"TerminalGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"TerminalRuleCall":return{name:"TerminalRuleCall",properties:[{name:"cardinality"},{name:"lookahead"},{name:"rule"}]};case"UnorderedGroup":return{name:"UnorderedGroup",properties:[{name:"cardinality"},{name:"elements",defaultValue:[]},{name:"lookahead"}]};case"UntilToken":return{name:"UntilToken",properties:[{name:"cardinality"},{name:"lookahead"},{name:"terminal"}]};case"Wildcard":return{name:"Wildcard",properties:[{name:"cardinality"},{name:"lookahead"}]};default:return{name:e,properties:[]}}}}const Oe=new Le;function be(e){for(const[t,n]of Object.entries(e))t.startsWith("$")||(Array.isArray(n)?n.forEach(((n,i)=>{r(n)&&(n.$container=e,n.$containerProperty=t,n.$containerIndex=i)})):r(n)&&(n.$container=e,n.$containerProperty=t))}function _e(e,t){let n=e;for(;n;){if(t(n))return n;n=n.$container}}function Pe(e){const t=function(e){for(;e.$container;)e=e.$container;return e}(e),n=t.$document;if(!n)throw new Error("AST node has no document.");return n}function Me(e,t){if(!e)throw new Error("Node must be an AstNode.");const n=null==t?void 0:t.range;return new u((()=>({keys:Object.keys(e),keyIndex:0,arrayIndex:0})),(t=>{for(;t.keyIndex<t.keys.length;){const i=t.keys[t.keyIndex];if(!i.startsWith("$")){const s=e[i];if(r(s)){if(t.keyIndex++,Fe(s,n))return{done:!1,value:s}}else if(Array.isArray(s)){for(;t.arrayIndex<s.length;){const e=s[t.arrayIndex++];if(r(e)&&Fe(e,n))return{done:!1,value:e}}t.arrayIndex=0}}t.keyIndex++}return p}))}function De(e,t){if(!e)throw new Error("Root node must be an AstNode.");return new g(e,(e=>Me(e,t)))}function Ue(e,t){if(!e)throw new Error("Root node must be an AstNode.");return(null==t?void 0:t.range)&&!Fe(e,t.range)?new g(e,(()=>[])):new g(e,(e=>Me(e,t)),{includeRoot:!0})}function Fe(e,t){var n;if(!t)return!0;const r=null===(n=e.$cstNode)||void 0===n?void 0:n.range;return!!r&&E(r,t)}function Ge(e){return new u((()=>({keys:Object.keys(e),keyIndex:0,arrayIndex:0})),(t=>{for(;t.keyIndex<t.keys.length;){const n=t.keys[t.keyIndex];if(!n.startsWith("$")){const r=e[n];if(i(r))return t.keyIndex++,{done:!1,value:{reference:r,container:e,property:n}};if(Array.isArray(r)){for(;t.arrayIndex<r.length;){const s=t.arrayIndex++,o=r[s];if(i(o))return{done:!1,value:{reference:o,container:e,property:n,index:s}}}t.arrayIndex=0}}t.keyIndex++}return p}))}function Ke(e){return Array.isArray(e)?[...e.map(Ke)]:e}function Be(e){return e.charCodeAt(0)}function je(e,t){Array.isArray(e)?e.forEach((function(e){t.push(e)})):t.push(e)}function Ve(e,t){if(!0===e[t])throw"duplicate flag "+t;e[t];e[t]=!0}function He(e){if(void 0===e)throw Error("Internal Error - Should never get here!");return!0}function We(){throw Error("Internal Error - Should never get here!")}function ze(e){return"Character"===e.type}const Ye=[];for(let Pu=Be("0");Pu<=Be("9");Pu++)Ye.push(Pu);const Xe=[Be("_")].concat(Ye);for(let Pu=Be("a");Pu<=Be("z");Pu++)Xe.push(Pu);for(let Pu=Be("A");Pu<=Be("Z");Pu++)Xe.push(Pu);const qe=[Be(" "),Be("\f"),Be("\n"),Be("\r"),Be("\t"),Be("\v"),Be("\t"),Be("\xa0"),Be("\u1680"),Be("\u2000"),Be("\u2001"),Be("\u2002"),Be("\u2003"),Be("\u2004"),Be("\u2005"),Be("\u2006"),Be("\u2007"),Be("\u2008"),Be("\u2009"),Be("\u200a"),Be("\u2028"),Be("\u2029"),Be("\u202f"),Be("\u205f"),Be("\u3000"),Be("\ufeff")],Qe=/[0-9a-fA-F]/,Je=/[0-9]/,Ze=/[1-9]/;class et{constructor(){this.idx=0,this.input="",this.groupIdx=0}saveState(){return{idx:this.idx,input:this.input,groupIdx:this.groupIdx}}restoreState(e){this.idx=e.idx,this.input=e.input,this.groupIdx=e.groupIdx}pattern(e){this.idx=0,this.input=e,this.groupIdx=0,this.consumeChar("/");const t=this.disjunction();this.consumeChar("/");const n={type:"Flags",loc:{begin:this.idx,end:e.length},global:!1,ignoreCase:!1,multiLine:!1,unicode:!1,sticky:!1};for(;this.isRegExpFlag();)switch(this.popChar()){case"g":Ve(n,"global");break;case"i":Ve(n,"ignoreCase");break;case"m":Ve(n,"multiLine");break;case"u":Ve(n,"unicode");break;case"y":Ve(n,"sticky")}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:n,value:t,loc:this.loc(0)}}disjunction(){const e=[],t=this.idx;for(e.push(this.alternative());"|"===this.peekChar();)this.consumeChar("|"),e.push(this.alternative());return{type:"Disjunction",value:e,loc:this.loc(t)}}alternative(){const e=[],t=this.idx;for(;this.isTerm();)e.push(this.term());return{type:"Alternative",value:e,loc:this.loc(t)}}term(){return this.isAssertion()?this.assertion():this.atom()}assertion(){const e=this.idx;switch(this.popChar()){case"^":return{type:"StartAnchor",loc:this.loc(e)};case"$":return{type:"EndAnchor",loc:this.loc(e)};case"\\":switch(this.popChar()){case"b":return{type:"WordBoundary",loc:this.loc(e)};case"B":return{type:"NonWordBoundary",loc:this.loc(e)}}throw Error("Invalid Assertion Escape");case"(":let t;switch(this.consumeChar("?"),this.popChar()){case"=":t="Lookahead";break;case"!":t="NegativeLookahead"}He(t);const n=this.disjunction();return this.consumeChar(")"),{type:t,value:n,loc:this.loc(e)}}return We()}quantifier(e=!1){let t;const n=this.idx;switch(this.popChar()){case"*":t={atLeast:0,atMost:1/0};break;case"+":t={atLeast:1,atMost:1/0};break;case"?":t={atLeast:0,atMost:1};break;case"{":const n=this.integerIncludingZero();switch(this.popChar()){case"}":t={atLeast:n,atMost:n};break;case",":let e;this.isDigit()?(e=this.integerIncludingZero(),t={atLeast:n,atMost:e}):t={atLeast:n,atMost:1/0},this.consumeChar("}")}if(!0===e&&void 0===t)return;He(t)}if(!0!==e||void 0!==t)return He(t)?("?"===this.peekChar(0)?(this.consumeChar("?"),t.greedy=!1):t.greedy=!0,t.type="Quantifier",t.loc=this.loc(n),t):void 0}atom(){let e;const t=this.idx;switch(this.peekChar()){case".":e=this.dotAll();break;case"\\":e=this.atomEscape();break;case"[":e=this.characterClass();break;case"(":e=this.group()}return void 0===e&&this.isPatternCharacter()&&(e=this.patternCharacter()),He(e)?(e.loc=this.loc(t),this.isQuantifier()&&(e.quantifier=this.quantifier()),e):We()}dotAll(){return this.consumeChar("."),{type:"Set",complement:!0,value:[Be("\n"),Be("\r"),Be("\u2028"),Be("\u2029")]}}atomEscape(){switch(this.consumeChar("\\"),this.peekChar()){case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":return this.decimalEscapeAtom();case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}}decimalEscapeAtom(){return{type:"GroupBackReference",value:this.positiveInteger()}}characterClassEscape(){let e,t=!1;switch(this.popChar()){case"d":e=Ye;break;case"D":e=Ye,t=!0;break;case"s":e=qe;break;case"S":e=qe,t=!0;break;case"w":e=Xe;break;case"W":e=Xe,t=!0}return He(e)?{type:"Set",value:e,complement:t}:We()}controlEscapeAtom(){let e;switch(this.popChar()){case"f":e=Be("\f");break;case"n":e=Be("\n");break;case"r":e=Be("\r");break;case"t":e=Be("\t");break;case"v":e=Be("\v")}return He(e)?{type:"Character",value:e}:We()}controlLetterEscapeAtom(){this.consumeChar("c");const e=this.popChar();if(!1===/[a-zA-Z]/.test(e))throw Error("Invalid ");return{type:"Character",value:e.toUpperCase().charCodeAt(0)-64}}nulCharacterAtom(){return this.consumeChar("0"),{type:"Character",value:Be("\0")}}hexEscapeSequenceAtom(){return this.consumeChar("x"),this.parseHexDigits(2)}regExpUnicodeEscapeSequenceAtom(){return this.consumeChar("u"),this.parseHexDigits(4)}identityEscapeAtom(){return{type:"Character",value:Be(this.popChar())}}classPatternCharacterAtom(){switch(this.peekChar()){case"\n":case"\r":case"\u2028":case"\u2029":case"\\":case"]":throw Error("TBD");default:return{type:"Character",value:Be(this.popChar())}}}characterClass(){const e=[];let t=!1;for(this.consumeChar("["),"^"===this.peekChar(0)&&(this.consumeChar("^"),t=!0);this.isClassAtom();){const t=this.classAtom();t.type;if(ze(t)&&this.isRangeDash()){this.consumeChar("-");const n=this.classAtom();n.type;if(ze(n)){if(n.value<t.value)throw Error("Range out of order in character class");e.push({from:t.value,to:n.value})}else je(t.value,e),e.push(Be("-")),je(n.value,e)}else je(t.value,e)}return this.consumeChar("]"),{type:"Set",complement:t,value:e}}classAtom(){switch(this.peekChar()){case"]":case"\n":case"\r":case"\u2028":case"\u2029":throw Error("TBD");case"\\":return this.classEscape();default:return this.classPatternCharacterAtom()}}classEscape(){switch(this.consumeChar("\\"),this.peekChar()){case"b":return this.consumeChar("b"),{type:"Character",value:Be("\b")};case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}}group(){let e=!0;if(this.consumeChar("("),"?"===this.peekChar(0))this.consumeChar("?"),this.consumeChar(":"),e=!1;else this.groupIdx++;const t=this.disjunction();this.consumeChar(")");const n={type:"Group",capturing:e,value:t};return e&&(n.idx=this.groupIdx),n}positiveInteger(){let e=this.popChar();if(!1===Ze.test(e))throw Error("Expecting a positive integer");for(;Je.test(this.peekChar(0));)e+=this.popChar();return parseInt(e,10)}integerIncludingZero(){let e=this.popChar();if(!1===Je.test(e))throw Error("Expecting an integer");for(;Je.test(this.peekChar(0));)e+=this.popChar();return parseInt(e,10)}patternCharacter(){const e=this.popChar();switch(e){case"\n":case"\r":case"\u2028":case"\u2029":case"^":case"$":case"\\":case".":case"*":case"+":case"?":case"(":case")":case"[":case"|":throw Error("TBD");default:return{type:"Character",value:Be(e)}}}isRegExpFlag(){switch(this.peekChar(0)){case"g":case"i":case"m":case"u":case"y":return!0;default:return!1}}isRangeDash(){return"-"===this.peekChar()&&this.isClassAtom(1)}isDigit(){return Je.test(this.peekChar(0))}isClassAtom(e=0){switch(this.peekChar(e)){case"]":case"\n":case"\r":case"\u2028":case"\u2029":return!1;default:return!0}}isTerm(){return this.isAtom()||this.isAssertion()}isAtom(){if(this.isPatternCharacter())return!0;switch(this.peekChar(0)){case".":case"\\":case"[":case"(":return!0;default:return!1}}isAssertion(){switch(this.peekChar(0)){case"^":case"$":return!0;case"\\":switch(this.peekChar(1)){case"b":case"B":return!0;default:return!1}case"(":return"?"===this.peekChar(1)&&("="===this.peekChar(2)||"!"===this.peekChar(2));default:return!1}}isQuantifier(){const e=this.saveState();try{return void 0!==this.quantifier(!0)}catch(t){return!1}finally{this.restoreState(e)}}isPatternCharacter(){switch(this.peekChar()){case"^":case"$":case"\\":case".":case"*":case"+":case"?":case"(":case")":case"[":case"|":case"/":case"\n":case"\r":case"\u2028":case"\u2029":return!1;default:return!0}}parseHexDigits(e){let t="";for(let n=0;n<e;n++){const e=this.popChar();if(!1===Qe.test(e))throw Error("Expecting a HexDecimal digits");t+=e}return{type:"Character",value:parseInt(t,16)}}peekChar(e=0){return this.input[this.idx+e]}popChar(){const e=this.peekChar(0);return this.consumeChar(void 0),e}consumeChar(e){if(void 0!==e&&this.input[this.idx]!==e)throw Error("Expected: '"+e+"' but found: '"+this.input[this.idx]+"' at offset: "+this.idx);if(this.idx>=this.input.length)throw Error("Unexpected end of input");this.idx++}loc(e){return{begin:e,end:this.idx}}}class tt{visitChildren(e){for(const t in e){const n=e[t];e.hasOwnProperty(t)&&(void 0!==n.type?this.visit(n):Array.isArray(n)&&n.forEach((e=>{this.visit(e)}),this))}}visit(e){switch(e.type){case"Pattern":this.visitPattern(e);break;case"Flags":this.visitFlags(e);break;case"Disjunction":this.visitDisjunction(e);break;case"Alternative":this.visitAlternative(e);break;case"StartAnchor":this.visitStartAnchor(e);break;case"EndAnchor":this.visitEndAnchor(e);break;case"WordBoundary":this.visitWordBoundary(e);break;case"NonWordBoundary":this.visitNonWordBoundary(e);break;case"Lookahead":this.visitLookahead(e);break;case"NegativeLookahead":this.visitNegativeLookahead(e);break;case"Character":this.visitCharacter(e);break;case"Set":this.visitSet(e);break;case"Group":this.visitGroup(e);break;case"GroupBackReference":this.visitGroupBackReference(e);break;case"Quantifier":this.visitQuantifier(e)}this.visitChildren(e)}visitPattern(e){}visitFlags(e){}visitDisjunction(e){}visitAlternative(e){}visitStartAnchor(e){}visitEndAnchor(e){}visitWordBoundary(e){}visitNonWordBoundary(e){}visitLookahead(e){}visitNegativeLookahead(e){}visitCharacter(e){}visitSet(e){}visitGroup(e){}visitGroupBackReference(e){}visitQuantifier(e){}}const nt=/\r?\n/gm,rt=new et;const it=new class extends tt{constructor(){super(...arguments),this.isStarting=!0,this.endRegexpStack=[],this.multiline=!1}get endRegex(){return this.endRegexpStack.join("")}reset(e){this.multiline=!1,this.regex=e,this.startRegexp="",this.isStarting=!0,this.endRegexpStack=[]}visitGroup(e){e.quantifier&&(this.isStarting=!1,this.endRegexpStack=[])}visitCharacter(e){const t=String.fromCharCode(e.value);if(this.multiline||"\n"!==t||(this.multiline=!0),e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const e=at(t);this.endRegexpStack.push(e),this.isStarting&&(this.startRegexp+=e)}}visitSet(e){if(!this.multiline){const t=this.regex.substring(e.loc.begin,e.loc.end),n=new RegExp(t);this.multiline=Boolean("\n".match(n))}if(e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const t=this.regex.substring(e.loc.begin,e.loc.end);this.endRegexpStack.push(t),this.isStarting&&(this.startRegexp+=t)}}visitChildren(e){if("Group"===e.type){if(e.quantifier)return}super.visitChildren(e)}};function st(e){try{return"string"==typeof e&&(e=new RegExp(e)),e=e.toString(),it.reset(e),it.visit(rt.pattern(e)),it.multiline}catch(t){return!1}}function ot(e){return("string"==typeof e?new RegExp(e):e).test(" ")}function at(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ct(e,t){const n=function(e){"string"==typeof e&&(e=new RegExp(e));const t=e,n=e.source;let r=0;function i(){let e,s="";function o(e){s+=n.substr(r,e),r+=e}function a(e){s+="(?:"+n.substr(r,e)+"|$)",r+=e}for(;r<n.length;)switch(n[r]){case"\\":switch(n[r+1]){case"c":a(3);break;case"x":a(4);break;case"u":t.unicode?"{"===n[r+2]?a(n.indexOf("}",r)-r+1):a(6):a(2);break;case"p":case"P":t.unicode?a(n.indexOf("}",r)-r+1):a(2);break;case"k":a(n.indexOf(">",r)-r+1);break;default:a(2)}break;case"[":e=/\[(?:\\.|.)*?\]/g,e.lastIndex=r,e=e.exec(n)||[],a(e[0].length);break;case"|":case"^":case"$":case"*":case"+":case"?":o(1);break;case"{":e=/\{\d+,?\d*\}/g,e.lastIndex=r,e=e.exec(n),e?o(e[0].length):a(1);break;case"(":if("?"===n[r+1])switch(n[r+2]){case":":s+="(?:",r+=3,s+=i()+"|$)";break;case"=":s+="(?=",r+=3,s+=i()+")";break;case"!":e=r,r+=3,i(),s+=n.substr(e,r-e);break;case"<":switch(n[r+3]){case"=":case"!":e=r,r+=4,i(),s+=n.substr(e,r-e);break;default:o(n.indexOf(">",r)-r+1),s+=i()+"|$)"}}else o(1),s+=i()+"|$)";break;case")":return++r,s;default:a(1)}return s}return new RegExp(i(),e.flags)}(e),r=t.match(n);return!!r&&r[0].length>0}function lt(e,t){const n=new Set,r=function(e){return e.rules.find((e=>X(e)&&e.entry))}(e);if(!r)return new Set(e.rules);const i=[r].concat(function(e){return e.rules.filter((e=>te(e)&&e.hidden))}(e));for(const o of i)ut(o,n,t);const s=new Set;for(const o of e.rules)(n.has(o.name)||te(o)&&o.hidden)&&s.add(o);return s}function ut(e,t,n){t.add(e.name),De(e).forEach((e=>{if(Ee(e)||n&&Se(e)){const r=e.rule.ref;r&&!t.has(r.name)&&ut(r,t,n)}}))}function dt(e,t,n){if(!e||!t)return;const r=ht(e,t,e.astNode,!0);return 0!==r.length?r[n=void 0!==n?Math.max(0,Math.min(n,r.length-1)):0]:void 0}function ht(e,t,n,r){if(!r){const n=_e(e.grammarSource,ue);if(n&&n.feature===t)return[e]}return a(e)&&e.astNode===n?e.content.flatMap((e=>ht(e,t,n,!1))):[]}function ft(e,t,n){if(e.astNode!==n)return[];if(Ae(e.grammarSource)&&e.grammarSource.value===t)return[e];const r=T(e).iterator();let i;const s=[];do{if(i=r.next(),!i.done){const e=i.value;e.astNode===n?Ae(e.grammarSource)&&e.grammarSource.value===t&&s.push(e):r.prune()}}while(!i.done);return s}function pt(e){let t=e;return K(t)&&(oe(t.$container)?t=t.$container.$container:X(t.$container)?t=t.$container:N(t.$container)),mt(e,t,new Map)}function mt(e,t,n){var r,i;function s(t,r){let i;return _e(t,ue)||(i=mt(r,r,n)),n.set(e,i),i}if(n.has(e))return n.get(e);n.set(e,void 0);for(const o of De(t)){if(ue(o)&&"name"===o.feature.toLowerCase())return n.set(e,o),o;if(Ee(o)&&X(o.rule.ref))return s(o,o.rule.ref);if(i=o,Oe.isInstance(i,J)&&(null===(r=o.typeRef)||void 0===r?void 0:r.ref))return s(o,o.typeRef.ref)}}function gt(e){return yt(e,new Set)}function yt(e,t){if(t.has(e))return!0;t.add(e);for(const n of De(e))if(Ee(n)){if(!n.rule.ref)return!1;if(X(n.rule.ref)&&!yt(n.rule.ref,t))return!1}else{if(ue(n))return!1;if(oe(n))return!1}return Boolean(e.definition)}function At(e){if(e.inferredType)return e.inferredType.name;if(e.dataType)return e.dataType;if(e.returnType){const t=e.returnType.ref;if(t){if(X(t))return t.name;if(j(t)||re(t))return t.name}}}function Tt(e){var t,n;if(X(e))return gt(e)?e.name:null!==(t=At(e))&&void 0!==t?t:e.name;if(j(e)||re(e)||(n=e,Oe.isInstance(n,Q)))return e.name;if(oe(e)){const t=function(e){var t;if(e.inferredType)return e.inferredType.name;if(null===(t=e.type)||void 0===t?void 0:t.ref)return Tt(e.type.ref);return}(e);if(t)return t}else if(K(e))return e.name;throw new Error("Cannot get name of Unknown Type")}function vt(e){const t={s:!1,i:!1,u:!1},n=Et(e.definition,t),r=Object.entries(t).filter((([,e])=>e)).map((([e])=>e)).join("");return new RegExp(n,r)}const Rt=/[\s\S]/.source;function Et(e,t){if(s=e,Oe.isInstance(s,ke))return xt((i=e).elements.map((e=>Et(e))).join("|"),{cardinality:i.cardinality,lookahead:i.lookahead});if(function(e){return Oe.isInstance(e,xe)}(e))return xt((r=e).elements.map((e=>Et(e))).join(""),{cardinality:r.cardinality,lookahead:r.lookahead});if(function(e){return Oe.isInstance(e,de)}(e))return function(e){if(e.right)return xt(`[${kt(e.left)}-${kt(e.right)}]`,{cardinality:e.cardinality,lookahead:e.lookahead,wrap:!1});return xt(kt(e.left),{cardinality:e.cardinality,lookahead:e.lookahead,wrap:!1})}(e);if(Se(e)){const t=e.rule.ref;if(!t)throw new Error("Missing rule reference.");return xt(Et(t.definition),{cardinality:e.cardinality,lookahead:e.lookahead})}if(function(e){return Oe.isInstance(e,Te)}(e))return function(e){return xt(`(?!${Et(e.terminal)})${Rt}*?`,{cardinality:e.cardinality,lookahead:e.lookahead})}(e);if(function(e){return Oe.isInstance(e,$e)}(e))return xt(`${Rt}*?${Et((n=e).terminal)}`,{cardinality:n.cardinality,lookahead:n.lookahead});if(function(e){return Oe.isInstance(e,ve)}(e)){const n=e.regex.lastIndexOf("/"),r=e.regex.substring(1,n),i=e.regex.substring(n+1);return t&&(t.i=i.includes("i"),t.s=i.includes("s"),t.u=i.includes("u")),xt(r,{cardinality:e.cardinality,lookahead:e.lookahead,wrap:!1})}if(function(e){return Oe.isInstance(e,we)}(e))return xt(Rt,{cardinality:e.cardinality,lookahead:e.lookahead});throw new Error(`Invalid terminal element: ${null==e?void 0:e.$type}`);var n,r,i,s}function kt(e){return at(e.value)}function xt(e,t){var n;return(!1!==t.wrap||t.lookahead)&&(e=`(${null!==(n=t.lookahead)&&void 0!==n?n:""}${e})`),t.cardinality?`${e}${t.cardinality}`:e}var It=n(8058),St=n(38207),Nt=n(66401),Ct=n(74722),$t=n(48585),wt=n(50053);function Lt(e){function t(){}t.prototype=e;const n=new t;function r(){return typeof n.bar}return r(),r(),e}const Ot=function(e,t,n){var r=-1,i=e.length;t<0&&(t=-t>i?0:i+t),(n=n>i?i:n)<0&&(n+=i),i=t>n?0:n-t>>>0,t>>>=0;for(var s=Array(i);++r<i;)s[r]=e[r+t];return s};var bt=n(18593);const _t=function(e,t,n){var r=null==e?0:e.length;return r?(t=n||void 0===t?1:(0,bt.A)(t),Ot(e,t<0?0:t,r)):[]};var Pt=n(9703),Mt=n(52851),Dt=n(22031),Ut=n(3767),Ft=n(38446),Gt=n(97271),Kt=n(27422),Bt=Object.prototype.hasOwnProperty;const jt=(0,Ut.A)((function(e,t){if((0,Gt.A)(t)||(0,Ft.A)(t))(0,Dt.A)(t,(0,Kt.A)(t),e);else for(var n in t)Bt.call(t,n)&&(0,Mt.A)(e,n,t[n])}));var Vt=n(45572),Ht=n(23958),Wt=n(99354),zt=n(83973);const Yt=function(e,t){if(null==e)return{};var n=(0,Vt.A)((0,zt.A)(e),(function(e){return[e]}));return t=(0,Ht.A)(t),(0,Wt.A)(e,n,(function(e,n){return t(e,n[0])}))};var Xt=n(88496),qt=n(53098);const Qt=function(e){return(0,qt.A)(e)&&"[object RegExp]"==(0,Xt.A)(e)};var Jt=n(52789),Zt=n(64841),en=Zt.A&&Zt.A.isRegExp;const tn=en?(0,Jt.A)(en):Qt;function nn(e){return t=e,(0,Pt.A)(t.LABEL)&&""!==t.LABEL?e.LABEL:e.name;var t}class rn{get definition(){return this._definition}set definition(e){this._definition=e}constructor(e){this._definition=e}accept(e){e.visit(this),(0,It.A)(this.definition,(t=>{t.accept(e)}))}}class sn extends rn{constructor(e){super([]),this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}set definition(e){}get definition(){return void 0!==this.referencedRule?this.referencedRule.definition:[]}accept(e){e.visit(this)}}class on extends rn{constructor(e){super(e.definition),this.orgText="",jt(this,Yt(e,(e=>void 0!==e)))}}class an extends rn{constructor(e){super(e.definition),this.ignoreAmbiguities=!1,jt(this,Yt(e,(e=>void 0!==e)))}}class cn extends rn{constructor(e){super(e.definition),this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}}class ln extends rn{constructor(e){super(e.definition),this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}}class un extends rn{constructor(e){super(e.definition),this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}}class dn extends rn{constructor(e){super(e.definition),this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}}class hn extends rn{constructor(e){super(e.definition),this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}}class fn extends rn{get definition(){return this._definition}set definition(e){this._definition=e}constructor(e){super(e.definition),this.idx=1,this.ignoreAmbiguities=!1,this.hasPredicates=!1,jt(this,Yt(e,(e=>void 0!==e)))}}class pn{constructor(e){this.idx=1,jt(this,Yt(e,(e=>void 0!==e)))}accept(e){e.visit(this)}}function mn(e){function t(e){return(0,Ct.A)(e,mn)}if(e instanceof sn){const t={type:"NonTerminal",name:e.nonTerminalName,idx:e.idx};return(0,Pt.A)(e.label)&&(t.label=e.label),t}if(e instanceof an)return{type:"Alternative",definition:t(e.definition)};if(e instanceof cn)return{type:"Option",idx:e.idx,definition:t(e.definition)};if(e instanceof ln)return{type:"RepetitionMandatory",idx:e.idx,definition:t(e.definition)};if(e instanceof un)return{type:"RepetitionMandatoryWithSeparator",idx:e.idx,separator:mn(new pn({terminalType:e.separator})),definition:t(e.definition)};if(e instanceof hn)return{type:"RepetitionWithSeparator",idx:e.idx,separator:mn(new pn({terminalType:e.separator})),definition:t(e.definition)};if(e instanceof dn)return{type:"Repetition",idx:e.idx,definition:t(e.definition)};if(e instanceof fn)return{type:"Alternation",idx:e.idx,definition:t(e.definition)};if(e instanceof pn){const t={type:"Terminal",name:e.terminalType.name,label:nn(e.terminalType),idx:e.idx};(0,Pt.A)(e.label)&&(t.terminalLabel=e.label);const n=e.terminalType.PATTERN;return e.terminalType.PATTERN&&(t.pattern=tn(n)?n.source:n),t}if(e instanceof on)return{type:"Rule",name:e.name,orgText:e.orgText,definition:t(e.definition)};throw Error("non exhaustive match")}class gn{visit(e){const t=e;switch(t.constructor){case sn:return this.visitNonTerminal(t);case an:return this.visitAlternative(t);case cn:return this.visitOption(t);case ln:return this.visitRepetitionMandatory(t);case un:return this.visitRepetitionMandatoryWithSeparator(t);case hn:return this.visitRepetitionWithSeparator(t);case dn:return this.visitRepetition(t);case fn:return this.visitAlternation(t);case pn:return this.visitTerminal(t);case on:return this.visitRule(t);default:throw Error("non exhaustive match")}}visitNonTerminal(e){}visitAlternative(e){}visitOption(e){}visitRepetition(e){}visitRepetitionMandatory(e){}visitRepetitionMandatoryWithSeparator(e){}visitRepetitionWithSeparator(e){}visitAlternation(e){}visitTerminal(e){}visitRule(e){}}var yn=n(63736),An=n(6240);const Tn=function(e,t){var n;return(0,An.A)(e,(function(e,r,i){return!(n=t(e,r,i))})),!!n};var vn=n(92049),Rn=n(6832);const En=function(e,t,n){var r=(0,vn.A)(e)?yn.A:Tn;return n&&(0,Rn.A)(e,t,n)&&(t=void 0),r(e,(0,Ht.A)(t,3))};var kn=n(60818),xn=Math.max;const In=function(e,t,n,r){e=(0,Ft.A)(e)?e:(0,St.A)(e),n=n&&!r?(0,bt.A)(n):0;var i=e.length;return n<0&&(n=xn(i+n,0)),(0,Pt.A)(e)?n<=i&&e.indexOf(t,n)>-1:!!i&&(0,kn.A)(e,t,n)>-1};const Sn=function(e,t){for(var n=-1,r=null==e?0:e.length;++n<r;)if(!t(e[n],n,e))return!1;return!0};const Nn=function(e,t){var n=!0;return(0,An.A)(e,(function(e,r,i){return n=!!t(e,r,i)})),n};const Cn=function(e,t,n){var r=(0,vn.A)(e)?Sn:Nn;return n&&(0,Rn.A)(e,t,n)&&(t=void 0),r(e,(0,Ht.A)(t,3))};function $n(e,t=[]){return!!(e instanceof cn||e instanceof dn||e instanceof hn)||(e instanceof fn?En(e.definition,(e=>$n(e,t))):!(e instanceof sn&&In(t,e))&&(e instanceof rn&&(e instanceof sn&&t.push(e),Cn(e.definition,(e=>$n(e,t))))))}function wn(e){if(e instanceof sn)return"SUBRULE";if(e instanceof cn)return"OPTION";if(e instanceof fn)return"OR";if(e instanceof ln)return"AT_LEAST_ONE";if(e instanceof un)return"AT_LEAST_ONE_SEP";if(e instanceof hn)return"MANY_SEP";if(e instanceof dn)return"MANY";if(e instanceof pn)return"CONSUME";throw Error("non exhaustive match")}class Ln{walk(e,t=[]){(0,It.A)(e.definition,((n,r)=>{const i=_t(e.definition,r+1);if(n instanceof sn)this.walkProdRef(n,i,t);else if(n instanceof pn)this.walkTerminal(n,i,t);else if(n instanceof an)this.walkFlat(n,i,t);else if(n instanceof cn)this.walkOption(n,i,t);else if(n instanceof ln)this.walkAtLeastOne(n,i,t);else if(n instanceof un)this.walkAtLeastOneSep(n,i,t);else if(n instanceof hn)this.walkManySep(n,i,t);else if(n instanceof dn)this.walkMany(n,i,t);else{if(!(n instanceof fn))throw Error("non exhaustive match");this.walkOr(n,i,t)}}))}walkTerminal(e,t,n){}walkProdRef(e,t,n){}walkFlat(e,t,n){const r=t.concat(n);this.walk(e,r)}walkOption(e,t,n){const r=t.concat(n);this.walk(e,r)}walkAtLeastOne(e,t,n){const r=[new cn({definition:e.definition})].concat(t,n);this.walk(e,r)}walkAtLeastOneSep(e,t,n){const r=On(e,t,n);this.walk(e,r)}walkMany(e,t,n){const r=[new cn({definition:e.definition})].concat(t,n);this.walk(e,r)}walkManySep(e,t,n){const r=On(e,t,n);this.walk(e,r)}walkOr(e,t,n){const r=t.concat(n);(0,It.A)(e.definition,(e=>{const t=new an({definition:[e]});this.walk(t,r)}))}}function On(e,t,n){return[new cn({definition:[new pn({terminalType:e.separator})].concat(e.definition)})].concat(t,n)}var bn=n(99902);const _n=function(e){return e&&e.length?(0,bn.A)(e):[]};var Pn=n(34098);function Mn(e){if(e instanceof sn)return Mn(e.referencedRule);if(e instanceof pn)return[e.terminalType];if(function(e){return e instanceof an||e instanceof cn||e instanceof dn||e instanceof ln||e instanceof un||e instanceof hn||e instanceof pn||e instanceof on}(e))return function(e){let t=[];const n=e.definition;let r,i=0,s=n.length>i,o=!0;for(;s&&o;)r=n[i],o=$n(r),t=t.concat(Mn(r)),i+=1,s=n.length>i;return _n(t)}(e);if(function(e){return e instanceof fn}(e))return function(e){const t=(0,Ct.A)(e.definition,(e=>Mn(e)));return _n((0,Pn.A)(t))}(e);throw Error("non exhaustive match")}const Dn="_~IN~_";class Un extends Ln{constructor(e){super(),this.topProd=e,this.follows={}}startWalking(){return this.walk(this.topProd),this.follows}walkTerminal(e,t,n){}walkProdRef(e,t,n){const r=(i=e.referencedRule,s=e.idx,i.name+s+Dn+this.topProd.name);var i,s;const o=t.concat(n),a=Mn(new an({definition:o}));this.follows[r]=a}}var Fn=n(69592),Gn=n(23068),Kn=n(2634),Bn=n(51790);const jn=function(e){if("function"!=typeof e)throw new TypeError("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}};const Vn=function(e,t){return((0,vn.A)(e)?Kn.A:Bn.A)(e,jn((0,Ht.A)(t,3)))};var Hn=n(89610),Wn=Math.max;const zn=function(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var i=null==n?0:(0,bt.A)(n);return i<0&&(i=Wn(r+i,0)),(0,kn.A)(e,t,i)};var Yn=n(89463),Xn=n(94092),qn=n(62062),Qn=n(83149),Jn=n(87809),Zn=n(64099);const er=function(e,t,n,r){var i=-1,s=Qn.A,o=!0,a=e.length,c=[],l=t.length;if(!a)return c;n&&(t=(0,Vt.A)(t,(0,Jt.A)(n))),r?(s=Jn.A,o=!1):t.length>=200&&(s=Zn.A,o=!1,t=new qn.A(t));e:for(;++i<a;){var u=e[i],d=null==n?u:n(u);if(u=r||0!==u?u:0,o&&d==d){for(var h=l;h--;)if(t[h]===d)continue e;c.push(u)}else s(t,d,r)||c.push(u)}return c};var tr=n(13588),nr=n(24326),rr=n(53533);const ir=(0,nr.A)((function(e,t){return(0,rr.A)(e)?er(e,(0,tr.A)(t,1,rr.A,!0)):[]}));const sr=function(e){for(var t=-1,n=null==e?0:e.length,r=0,i=[];++t<n;){var s=e[t];s&&(i[r++]=s)}return i};const or=function(e){return e&&e.length?e[0]:void 0};var ar=n(16145);function cr(e){console&&console.error&&console.error(`Error: ${e}`)}function lr(e){console&&console.warn&&console.warn(`Warning: ${e}`)}let ur={};const dr=new et;function hr(e){const t=e.toString();if(ur.hasOwnProperty(t))return ur[t];{const e=dr.pattern(t);return ur[t]=e,e}}const fr="Complement Sets are not supported for first char optimization",pr='Unable to use "first char" lexer optimizations:\n';function mr(e,t=!1){try{const t=hr(e);return gr(t.value,{},t.flags.ignoreCase)}catch(n){if(n.message===fr)t&&lr(`${pr}\tUnable to optimize: < ${e.toString()} >\n\tComplement Sets cannot be automatically optimized.\n\tThis will disable the lexer's first char optimizations.\n\tSee: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.`);else{let n="";t&&(n="\n\tThis will disable the lexer's first char optimizations.\n\tSee: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details."),cr(`${pr}\n\tFailed parsing: < ${e.toString()} >\n\tUsing the @chevrotain/regexp-to-ast library\n\tPlease open an issue at: https://github.com/chevrotain/chevrotain/issues`+n)}}return[]}function gr(e,t,n){switch(e.type){case"Disjunction":for(let i=0;i<e.value.length;i++)gr(e.value[i],t,n);break;case"Alternative":const r=e.value;for(let e=0;e<r.length;e++){const i=r[e];switch(i.type){case"EndAnchor":case"GroupBackReference":case"Lookahead":case"NegativeLookahead":case"StartAnchor":case"WordBoundary":case"NonWordBoundary":continue}const s=i;switch(s.type){case"Character":yr(s.value,t,n);break;case"Set":if(!0===s.complement)throw Error(fr);(0,It.A)(s.value,(e=>{if("number"==typeof e)yr(e,t,n);else{const r=e;if(!0===n)for(let e=r.from;e<=r.to;e++)yr(e,t,n);else{for(let e=r.from;e<=r.to&&e<Fr;e++)yr(e,t,n);if(r.to>=Fr){const e=r.from>=Fr?r.from:Fr,n=r.to,i=Kr(e),s=Kr(n);for(let r=i;r<=s;r++)t[r]=r}}}}));break;case"Group":gr(s.value,t,n);break;default:throw Error("Non Exhaustive Match")}const o=void 0!==s.quantifier&&0===s.quantifier.atLeast;if("Group"===s.type&&!1===Tr(s)||"Group"!==s.type&&!1===o)break}break;default:throw Error("non exhaustive match!")}return(0,St.A)(t)}function yr(e,t,n){const r=Kr(e);t[r]=r,!0===n&&function(e,t){const n=String.fromCharCode(e),r=n.toUpperCase();if(r!==n){const e=Kr(r.charCodeAt(0));t[e]=e}else{const e=n.toLowerCase();if(e!==n){const n=Kr(e.charCodeAt(0));t[n]=n}}}(e,t)}function Ar(e,t){return(0,ar.A)(e.value,(e=>{if("number"==typeof e)return In(t,e);{const n=e;return void 0!==(0,ar.A)(t,(e=>n.from<=e&&e<=n.to))}}))}function Tr(e){const t=e.quantifier;return!(!t||0!==t.atLeast)||!!e.value&&((0,vn.A)(e.value)?Cn(e.value,Tr):Tr(e.value))}class vr extends tt{constructor(e){super(),this.targetCharCodes=e,this.found=!1}visitChildren(e){if(!0!==this.found){switch(e.type){case"Lookahead":return void this.visitLookahead(e);case"NegativeLookahead":return void this.visitNegativeLookahead(e)}super.visitChildren(e)}}visitCharacter(e){In(this.targetCharCodes,e.value)&&(this.found=!0)}visitSet(e){e.complement?void 0===Ar(e,this.targetCharCodes)&&(this.found=!0):void 0!==Ar(e,this.targetCharCodes)&&(this.found=!0)}}function Rr(e,t){if(t instanceof RegExp){const n=hr(t),r=new vr(e);return r.visit(n),r.found}return void 0!==(0,ar.A)(t,(t=>In(e,t.charCodeAt(0))))}const Er="PATTERN",kr="defaultMode",xr="modes";let Ir="boolean"==typeof new RegExp("(?:)").sticky;function Sr(e,t){const n=(t=(0,Gn.A)(t,{useSticky:Ir,debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r","\n"],tracer:(e,t)=>t()})).tracer;let r;n("initCharCodeToOptimizedIndexMap",(()=>{!function(){if((0,Nt.A)(Gr)){Gr=new Array(65536);for(let e=0;e<65536;e++)Gr[e]=e>255?255+~~(e/255):e}}()})),n("Reject Lexer.NA",(()=>{r=Vn(e,(e=>e[Er]===ii.NA))}));let i,s,o,a,c,l,u,d,h,f,p,m=!1;n("Transform Patterns",(()=>{m=!1,i=(0,Ct.A)(r,(e=>{const n=e[Er];if(tn(n)){const e=n.source;return 1!==e.length||"^"===e||"$"===e||"."===e||n.ignoreCase?2!==e.length||"\\"!==e[0]||In(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],e[1])?t.useSticky?Lr(n):wr(n):e[1]:e}if((0,Hn.A)(n))return m=!0,{exec:n};if("object"==typeof n)return m=!0,n;if("string"==typeof n){if(1===n.length)return n;{const e=n.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),r=new RegExp(e);return t.useSticky?Lr(r):wr(r)}}throw Error("non exhaustive match")}))})),n("misc mapping",(()=>{s=(0,Ct.A)(r,(e=>e.tokenTypeIdx)),o=(0,Ct.A)(r,(e=>{const t=e.GROUP;if(t!==ii.SKIPPED){if((0,Pt.A)(t))return t;if((0,Fn.A)(t))return!1;throw Error("non exhaustive match")}})),a=(0,Ct.A)(r,(e=>{const t=e.LONGER_ALT;if(t){return(0,vn.A)(t)?(0,Ct.A)(t,(e=>zn(r,e))):[zn(r,t)]}})),c=(0,Ct.A)(r,(e=>e.PUSH_MODE)),l=(0,Ct.A)(r,(e=>(0,$t.A)(e,"POP_MODE")))})),n("Line Terminator Handling",(()=>{const e=Dr(t.lineTerminatorCharacters);u=(0,Ct.A)(r,(e=>!1)),"onlyOffset"!==t.positionTracking&&(u=(0,Ct.A)(r,(t=>(0,$t.A)(t,"LINE_BREAKS")?!!t.LINE_BREAKS:!1===Mr(t,e)&&Rr(e,t.PATTERN))))})),n("Misc Mapping #2",(()=>{d=(0,Ct.A)(r,br),h=(0,Ct.A)(i,_r),f=(0,Yn.A)(r,((e,t)=>{const n=t.GROUP;return(0,Pt.A)(n)&&n!==ii.SKIPPED&&(e[n]=[]),e}),{}),p=(0,Ct.A)(i,((e,t)=>({pattern:i[t],longerAlt:a[t],canLineTerminator:u[t],isCustom:d[t],short:h[t],group:o[t],push:c[t],pop:l[t],tokenTypeIdx:s[t],tokenType:r[t]})))}));let g=!0,y=[];return t.safeMode||n("First Char Optimization",(()=>{y=(0,Yn.A)(r,((e,n,r)=>{if("string"==typeof n.PATTERN){const t=Kr(n.PATTERN.charCodeAt(0));Ur(e,t,p[r])}else if((0,vn.A)(n.START_CHARS_HINT)){let t;(0,It.A)(n.START_CHARS_HINT,(n=>{const i=Kr("string"==typeof n?n.charCodeAt(0):n);t!==i&&(t=i,Ur(e,i,p[r]))}))}else if(tn(n.PATTERN))if(n.PATTERN.unicode)g=!1,t.ensureOptimizations&&cr(`${pr}\tUnable to analyze < ${n.PATTERN.toString()} > pattern.\n\tThe regexp unicode flag is not currently supported by the regexp-to-ast library.\n\tThis will disable the lexer's first char optimizations.\n\tFor details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNICODE_OPTIMIZE`);else{const i=mr(n.PATTERN,t.ensureOptimizations);(0,Nt.A)(i)&&(g=!1),(0,It.A)(i,(t=>{Ur(e,t,p[r])}))}else t.ensureOptimizations&&cr(`${pr}\tTokenType: <${n.name}> is using a custom token pattern without providing <start_chars_hint> parameter.\n\tThis will disable the lexer's first char optimizations.\n\tFor details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),g=!1;return e}),[])})),{emptyGroups:f,patternIdxToConfig:p,charCodeToPatternIdxToConfig:y,hasCustom:m,canBeOptimized:g}}function Nr(e,t){let n=[];const r=function(e){const t=(0,Xn.A)(e,(e=>!(0,$t.A)(e,Er))),n=(0,Ct.A)(t,(e=>({message:"Token Type: ->"+e.name+"<- missing static 'PATTERN' property",type:ni.MISSING_PATTERN,tokenTypes:[e]}))),r=ir(e,t);return{errors:n,valid:r}}(e);n=n.concat(r.errors);const i=function(e){const t=(0,Xn.A)(e,(e=>{const t=e[Er];return!(tn(t)||(0,Hn.A)(t)||(0,$t.A)(t,"exec")||(0,Pt.A)(t))})),n=(0,Ct.A)(t,(e=>({message:"Token Type: ->"+e.name+"<- static 'PATTERN' can only be a RegExp, a Function matching the {CustomPatternMatcherFunc} type or an Object matching the {ICustomPattern} interface.",type:ni.INVALID_PATTERN,tokenTypes:[e]}))),r=ir(e,t);return{errors:n,valid:r}}(r.valid),s=i.valid;return n=n.concat(i.errors),n=n.concat(function(e){let t=[];const n=(0,Xn.A)(e,(e=>tn(e[Er])));return t=t.concat(function(e){class t extends tt{constructor(){super(...arguments),this.found=!1}visitEndAnchor(e){this.found=!0}}const n=(0,Xn.A)(e,(e=>{const n=e.PATTERN;try{const e=hr(n),r=new t;return r.visit(e),r.found}catch(r){return Cr.test(n.source)}})),r=(0,Ct.A)(n,(e=>({message:"Unexpected RegExp Anchor Error:\n\tToken Type: ->"+e.name+"<- static 'PATTERN' cannot contain end of input anchor '$'\n\tSee chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS\tfor details.",type:ni.EOI_ANCHOR_FOUND,tokenTypes:[e]})));return r}(n)),t=t.concat(function(e){class t extends tt{constructor(){super(...arguments),this.found=!1}visitStartAnchor(e){this.found=!0}}const n=(0,Xn.A)(e,(e=>{const n=e.PATTERN;try{const e=hr(n),r=new t;return r.visit(e),r.found}catch(r){return $r.test(n.source)}})),r=(0,Ct.A)(n,(e=>({message:"Unexpected RegExp Anchor Error:\n\tToken Type: ->"+e.name+"<- static 'PATTERN' cannot contain start of input anchor '^'\n\tSee https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS\tfor details.",type:ni.SOI_ANCHOR_FOUND,tokenTypes:[e]})));return r}(n)),t=t.concat(function(e){const t=(0,Xn.A)(e,(e=>{const t=e[Er];return t instanceof RegExp&&(t.multiline||t.global)})),n=(0,Ct.A)(t,(e=>({message:"Token Type: ->"+e.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:ni.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[e]})));return n}(n)),t=t.concat(function(e){const t=[];let n=(0,Ct.A)(e,(n=>(0,Yn.A)(e,((e,r)=>(n.PATTERN.source!==r.PATTERN.source||In(t,r)||r.PATTERN===ii.NA||(t.push(r),e.push(r)),e)),[])));n=sr(n);const r=(0,Xn.A)(n,(e=>e.length>1)),i=(0,Ct.A)(r,(e=>{const t=(0,Ct.A)(e,(e=>e.name));return{message:`The same RegExp pattern ->${or(e).PATTERN}<-has been used in all of the following Token Types: ${t.join(", ")} <-`,type:ni.DUPLICATE_PATTERNS_FOUND,tokenTypes:e}}));return i}(n)),t=t.concat(function(e){const t=(0,Xn.A)(e,(e=>e.PATTERN.test(""))),n=(0,Ct.A)(t,(e=>({message:"Token Type: ->"+e.name+"<- static 'PATTERN' must not match an empty string",type:ni.EMPTY_MATCH_PATTERN,tokenTypes:[e]})));return n}(n)),t}(s)),n=n.concat(function(e){const t=(0,Xn.A)(e,(e=>{if(!(0,$t.A)(e,"GROUP"))return!1;const t=e.GROUP;return t!==ii.SKIPPED&&t!==ii.NA&&!(0,Pt.A)(t)})),n=(0,Ct.A)(t,(e=>({message:"Token Type: ->"+e.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:ni.INVALID_GROUP_TYPE_FOUND,tokenTypes:[e]})));return n}(s)),n=n.concat(function(e,t){const n=(0,Xn.A)(e,(e=>void 0!==e.PUSH_MODE&&!In(t,e.PUSH_MODE))),r=(0,Ct.A)(n,(e=>({message:`Token Type: ->${e.name}<- static 'PUSH_MODE' value cannot refer to a Lexer Mode ->${e.PUSH_MODE}<-which does not exist`,type:ni.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[e]})));return r}(s,t)),n=n.concat(function(e){const t=[],n=(0,Yn.A)(e,((e,t,n)=>{const r=t.PATTERN;return r===ii.NA||((0,Pt.A)(r)?e.push({str:r,idx:n,tokenType:t}):tn(r)&&function(e){const t=[".","\\","[","]","|","^","$","(",")","?","*","+","{"];return void 0===(0,ar.A)(t,(t=>-1!==e.source.indexOf(t)))}(r)&&e.push({str:r.source,idx:n,tokenType:t})),e}),[]);return(0,It.A)(e,((e,r)=>{(0,It.A)(n,(({str:n,idx:i,tokenType:s})=>{if(r<i&&function(e,t){if(tn(t)){const n=t.exec(e);return null!==n&&0===n.index}if((0,Hn.A)(t))return t(e,0,[],{});if((0,$t.A)(t,"exec"))return t.exec(e,0,[],{});if("string"==typeof t)return t===e;throw Error("non exhaustive match")}(n,e.PATTERN)){const n=`Token: ->${s.name}<- can never be matched.\nBecause it appears AFTER the Token Type ->${e.name}<-in the lexer's definition.\nSee https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;t.push({message:n,type:ni.UNREACHABLE_PATTERN,tokenTypes:[e,s]})}}))})),t}(s)),n}const Cr=/[^\\][$]/;const $r=/[^\\[][\^]|^\^/;function wr(e){const t=e.ignoreCase?"i":"";return new RegExp(`^(?:${e.source})`,t)}function Lr(e){const t=e.ignoreCase?"iy":"y";return new RegExp(`${e.source}`,t)}function Or(e,t,n){const r=[];let i=!1;const s=sr((0,Pn.A)((0,St.A)(e.modes))),o=Vn(s,(e=>e[Er]===ii.NA)),a=Dr(n);return t&&(0,It.A)(o,(e=>{const t=Mr(e,a);if(!1!==t){const n=function(e,t){if(t.issue===ni.IDENTIFY_TERMINATOR)return`Warning: unable to identify line terminator usage in pattern.\n\tThe problem is in the <${e.name}> Token Type\n\t Root cause: ${t.errMsg}.\n\tFor details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR`;if(t.issue===ni.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the <line_breaks> option.\n\tThe problem is in the <${e.name}> Token Type\n\tFor details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK`;throw Error("non exhaustive match")}(e,t),i={message:n,type:t.issue,tokenType:e};r.push(i)}else(0,$t.A)(e,"LINE_BREAKS")?!0===e.LINE_BREAKS&&(i=!0):Rr(a,e.PATTERN)&&(i=!0)})),t&&!i&&r.push({message:"Warning: No LINE_BREAKS Found.\n\tThis Lexer has been defined to track line and column information,\n\tBut none of the Token Types can be identified as matching a line terminator.\n\tSee https://chevrotain.io/docs/guide/resolving_lexer_errors.html#LINE_BREAKS \n\tfor details.",type:ni.NO_LINE_BREAKS_FLAGS}),r}function br(e){const t=e.PATTERN;if(tn(t))return!1;if((0,Hn.A)(t))return!0;if((0,$t.A)(t,"exec"))return!0;if((0,Pt.A)(t))return!1;throw Error("non exhaustive match")}function _r(e){return!(!(0,Pt.A)(e)||1!==e.length)&&e.charCodeAt(0)}const Pr={test:function(e){const t=e.length;for(let n=this.lastIndex;n<t;n++){const t=e.charCodeAt(n);if(10===t)return this.lastIndex=n+1,!0;if(13===t)return 10===e.charCodeAt(n+1)?this.lastIndex=n+2:this.lastIndex=n+1,!0}return!1},lastIndex:0};function Mr(e,t){if((0,$t.A)(e,"LINE_BREAKS"))return!1;if(tn(e.PATTERN)){try{Rr(t,e.PATTERN)}catch(n){return{issue:ni.IDENTIFY_TERMINATOR,errMsg:n.message}}return!1}if((0,Pt.A)(e.PATTERN))return!1;if(br(e))return{issue:ni.CUSTOM_LINE_BREAK};throw Error("non exhaustive match")}function Dr(e){return(0,Ct.A)(e,(e=>(0,Pt.A)(e)?e.charCodeAt(0):e))}function Ur(e,t,n){void 0===e[t]?e[t]=[n]:e[t].push(n)}const Fr=256;let Gr=[];function Kr(e){return e<Fr?e:Gr[e]}var Br=n(29008),jr=n(42302),Vr=n(26666);function Hr(e){const t=(new Date).getTime(),n=e();return{time:(new Date).getTime()-t,value:n}}function Wr(e,t){const n=e.tokenTypeIdx;return n===t.tokenTypeIdx||!0===t.isParent&&!0===t.categoryMatchesMap[n]}function zr(e,t){return e.tokenTypeIdx===t.tokenTypeIdx}let Yr=1;const Xr={};function qr(e){const t=function(e){let t=(0,wt.A)(e),n=e,r=!0;for(;r;){n=sr((0,Pn.A)((0,Ct.A)(n,(e=>e.CATEGORIES))));const e=ir(n,t);t=t.concat(e),(0,Nt.A)(e)?r=!1:n=e}return t}(e);!function(e){(0,It.A)(e,(e=>{var t;Jr(e)||(Xr[Yr]=e,e.tokenTypeIdx=Yr++),Zr(e)&&!(0,vn.A)(e.CATEGORIES)&&(e.CATEGORIES=[e.CATEGORIES]),Zr(e)||(e.CATEGORIES=[]),t=e,(0,$t.A)(t,"categoryMatches")||(e.categoryMatches=[]),function(e){return(0,$t.A)(e,"categoryMatchesMap")}(e)||(e.categoryMatchesMap={})}))}(t),function(e){(0,It.A)(e,(e=>{Qr([],e)}))}(t),function(e){(0,It.A)(e,(e=>{e.categoryMatches=[],(0,It.A)(e.categoryMatchesMap,((t,n)=>{e.categoryMatches.push(Xr[n].tokenTypeIdx)}))}))}(t),(0,It.A)(t,(e=>{e.isParent=e.categoryMatches.length>0}))}function Qr(e,t){(0,It.A)(e,(e=>{t.categoryMatchesMap[e.tokenTypeIdx]=!0})),(0,It.A)(t.CATEGORIES,(n=>{const r=e.concat(t);In(r,n)||Qr(r,n)}))}function Jr(e){return(0,$t.A)(e,"tokenTypeIdx")}function Zr(e){return(0,$t.A)(e,"CATEGORIES")}function ei(e){return(0,$t.A)(e,"tokenTypeIdx")}const ti={buildUnableToPopLexerModeMessage:e=>`Unable to pop Lexer Mode after encountering Token ->${e.image}<- The Mode Stack is empty`,buildUnexpectedCharactersMessage:(e,t,n,r,i)=>`unexpected character: ->${e.charAt(t)}<- at offset: ${t}, skipped ${n} characters.`};var ni;!function(e){e[e.MISSING_PATTERN=0]="MISSING_PATTERN",e[e.INVALID_PATTERN=1]="INVALID_PATTERN",e[e.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",e[e.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",e[e.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",e[e.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",e[e.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",e[e.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",e[e.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",e[e.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",e[e.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",e[e.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",e[e.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",e[e.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",e[e.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",e[e.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",e[e.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK",e[e.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE=17]="MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE"}(ni||(ni={}));const ri={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:["\n","\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:ti,traceInitPerf:!1,skipValidations:!1,recoveryEnabled:!0};Object.freeze(ri);class ii{constructor(e,t=ri){if(this.lexerDefinition=e,this.lexerDefinitionErrors=[],this.lexerDefinitionWarning=[],this.patternIdxToConfig={},this.charCodeToPatternIdxToConfig={},this.modes=[],this.emptyGroups={},this.trackStartLines=!0,this.trackEndLines=!0,this.hasCustom=!1,this.canModeBeOptimized={},this.TRACE_INIT=(e,t)=>{if(!0===this.traceInitPerf){this.traceInitIndent++;const n=new Array(this.traceInitIndent+1).join("\t");this.traceInitIndent<this.traceInitMaxIdent&&console.log(`${n}--\x3e <${e}>`);const{time:r,value:i}=Hr(t),s=r>10?console.warn:console.log;return this.traceInitIndent<this.traceInitMaxIdent&&s(`${n}<-- <${e}> time: ${r}ms`),this.traceInitIndent--,i}return t()},"boolean"==typeof t)throw Error("The second argument to the Lexer constructor is now an ILexerConfig Object.\na boolean 2nd argument is no longer supported");this.config=jt({},ri,t);const n=this.config.traceInitPerf;!0===n?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):"number"==typeof n&&(this.traceInitMaxIdent=n,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",(()=>{let n,r=!0;this.TRACE_INIT("Lexer Config handling",(()=>{if(this.config.lineTerminatorsPattern===ri.lineTerminatorsPattern)this.config.lineTerminatorsPattern=Pr;else if(this.config.lineTerminatorCharacters===ri.lineTerminatorCharacters)throw Error("Error: Missing <lineTerminatorCharacters> property on the Lexer config.\n\tFor details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS");if(t.safeMode&&t.ensureOptimizations)throw Error('"safeMode" and "ensureOptimizations" flags are mutually exclusive.');this.trackStartLines=/full|onlyStart/i.test(this.config.positionTracking),this.trackEndLines=/full/i.test(this.config.positionTracking),(0,vn.A)(e)?n={modes:{defaultMode:(0,wt.A)(e)},defaultMode:kr}:(r=!1,n=(0,wt.A)(e))})),!1===this.config.skipValidations&&(this.TRACE_INIT("performRuntimeChecks",(()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(function(e){const t=[];return(0,$t.A)(e,kr)||t.push({message:"A MultiMode Lexer cannot be initialized without a <"+kr+"> property in its definition\n",type:ni.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),(0,$t.A)(e,xr)||t.push({message:"A MultiMode Lexer cannot be initialized without a <modes> property in its definition\n",type:ni.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),(0,$t.A)(e,xr)&&(0,$t.A)(e,kr)&&!(0,$t.A)(e.modes,e.defaultMode)&&t.push({message:`A MultiMode Lexer cannot be initialized with a ${kr}: <${e.defaultMode}>which does not exist\n`,type:ni.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),(0,$t.A)(e,xr)&&(0,It.A)(e.modes,((e,n)=>{(0,It.A)(e,((r,i)=>{if((0,Fn.A)(r))t.push({message:`A Lexer cannot be initialized using an undefined Token Type. Mode:<${n}> at index: <${i}>\n`,type:ni.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED});else if((0,$t.A)(r,"LONGER_ALT")){const i=(0,vn.A)(r.LONGER_ALT)?r.LONGER_ALT:[r.LONGER_ALT];(0,It.A)(i,(i=>{(0,Fn.A)(i)||In(e,i)||t.push({message:`A MultiMode Lexer cannot be initialized with a longer_alt <${i.name}> on token <${r.name}> outside of mode <${n}>\n`,type:ni.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE})}))}}))})),t}(n,this.trackStartLines,this.config.lineTerminatorCharacters))})),this.TRACE_INIT("performWarningRuntimeChecks",(()=>{this.lexerDefinitionWarning=this.lexerDefinitionWarning.concat(Or(n,this.trackStartLines,this.config.lineTerminatorCharacters))}))),n.modes=n.modes?n.modes:{},(0,It.A)(n.modes,((e,t)=>{n.modes[t]=Vn(e,(e=>(0,Fn.A)(e)))}));const i=(0,Kt.A)(n.modes);if((0,It.A)(n.modes,((e,n)=>{this.TRACE_INIT(`Mode: <${n}> processing`,(()=>{if(this.modes.push(n),!1===this.config.skipValidations&&this.TRACE_INIT("validatePatterns",(()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(Nr(e,i))})),(0,Nt.A)(this.lexerDefinitionErrors)){let r;qr(e),this.TRACE_INIT("analyzeTokenTypes",(()=>{r=Sr(e,{lineTerminatorCharacters:this.config.lineTerminatorCharacters,positionTracking:t.positionTracking,ensureOptimizations:t.ensureOptimizations,safeMode:t.safeMode,tracer:this.TRACE_INIT})})),this.patternIdxToConfig[n]=r.patternIdxToConfig,this.charCodeToPatternIdxToConfig[n]=r.charCodeToPatternIdxToConfig,this.emptyGroups=jt({},this.emptyGroups,r.emptyGroups),this.hasCustom=r.hasCustom||this.hasCustom,this.canModeBeOptimized[n]=r.canBeOptimized}}))})),this.defaultMode=n.defaultMode,!(0,Nt.A)(this.lexerDefinitionErrors)&&!this.config.deferDefinitionErrorsHandling){const e=(0,Ct.A)(this.lexerDefinitionErrors,(e=>e.message)).join("-----------------------\n");throw new Error("Errors detected in definition of Lexer:\n"+e)}(0,It.A)(this.lexerDefinitionWarning,(e=>{lr(e.message)})),this.TRACE_INIT("Choosing sub-methods implementations",(()=>{if(Ir?(this.chopInput=Br.A,this.match=this.matchWithTest):(this.updateLastIndex=jr.A,this.match=this.matchWithExec),r&&(this.handleModes=jr.A),!1===this.trackStartLines&&(this.computeNewColumn=Br.A),!1===this.trackEndLines&&(this.updateTokenEndLineColumnLocation=jr.A),/full/i.test(this.config.positionTracking))this.createTokenInstance=this.createFullToken;else if(/onlyStart/i.test(this.config.positionTracking))this.createTokenInstance=this.createStartOnlyToken;else{if(!/onlyOffset/i.test(this.config.positionTracking))throw Error(`Invalid <positionTracking> config option: "${this.config.positionTracking}"`);this.createTokenInstance=this.createOffsetOnlyToken}this.hasCustom?(this.addToken=this.addTokenUsingPush,this.handlePayload=this.handlePayloadWithCustom):(this.addToken=this.addTokenUsingMemberAccess,this.handlePayload=this.handlePayloadNoCustom)})),this.TRACE_INIT("Failed Optimization Warnings",(()=>{const e=(0,Yn.A)(this.canModeBeOptimized,((e,t,n)=>(!1===t&&e.push(n),e)),[]);if(t.ensureOptimizations&&!(0,Nt.A)(e))throw Error(`Lexer Modes: < ${e.join(", ")} > cannot be optimized.\n\t Disable the "ensureOptimizations" lexer config flag to silently ignore this and run the lexer in an un-optimized mode.\n\t Or inspect the console log for details on how to resolve these issues.`)})),this.TRACE_INIT("clearRegExpParserCache",(()=>{ur={}})),this.TRACE_INIT("toFastProperties",(()=>{Lt(this)}))}))}tokenize(e,t=this.defaultMode){if(!(0,Nt.A)(this.lexerDefinitionErrors)){const e=(0,Ct.A)(this.lexerDefinitionErrors,(e=>e.message)).join("-----------------------\n");throw new Error("Unable to Tokenize because Errors detected in definition of Lexer:\n"+e)}return this.tokenizeInternal(e,t)}tokenizeInternal(e,t){let n,r,i,s,o,a,c,l,u,d,h,f,p,m,g;const y=e,A=y.length;let T=0,v=0;const R=this.hasCustom?0:Math.floor(e.length/10),E=new Array(R),k=[];let x=this.trackStartLines?1:void 0,I=this.trackStartLines?1:void 0;const S=function(e){const t={},n=(0,Kt.A)(e);return(0,It.A)(n,(n=>{const r=e[n];if(!(0,vn.A)(r))throw Error("non exhaustive match");t[n]=[]})),t}(this.emptyGroups),N=this.trackStartLines,C=this.config.lineTerminatorsPattern;let $=0,w=[],L=[];const O=[],b=[];let _;function P(){return w}function M(e){const t=Kr(e),n=L[t];return void 0===n?b:n}Object.freeze(b);const D=e=>{if(1===O.length&&void 0===e.tokenType.PUSH_MODE){const t=this.config.errorMessageProvider.buildUnableToPopLexerModeMessage(e);k.push({offset:e.startOffset,line:e.startLine,column:e.startColumn,length:e.image.length,message:t})}else{O.pop();const e=(0,Vr.A)(O);w=this.patternIdxToConfig[e],L=this.charCodeToPatternIdxToConfig[e],$=w.length;const t=this.canModeBeOptimized[e]&&!1===this.config.safeMode;_=L&&t?M:P}};function U(e){O.push(e),L=this.charCodeToPatternIdxToConfig[e],w=this.patternIdxToConfig[e],$=w.length,$=w.length;const t=this.canModeBeOptimized[e]&&!1===this.config.safeMode;_=L&&t?M:P}let F;U.call(this,t);const G=this.config.recoveryEnabled;for(;T<A;){a=null;const t=y.charCodeAt(T),R=_(t),L=R.length;for(n=0;n<L;n++){F=R[n];const r=F.pattern;c=null;const u=F.short;if(!1!==u?t===u&&(a=r):!0===F.isCustom?(g=r.exec(y,T,E,S),null!==g?(a=g[0],void 0!==g.payload&&(c=g.payload)):a=null):(this.updateLastIndex(r,T),a=this.match(r,e,T)),null!==a){if(o=F.longerAlt,void 0!==o){const t=o.length;for(i=0;i<t;i++){const t=w[o[i]],n=t.pattern;if(l=null,!0===t.isCustom?(g=n.exec(y,T,E,S),null!==g?(s=g[0],void 0!==g.payload&&(l=g.payload)):s=null):(this.updateLastIndex(n,T),s=this.match(n,e,T)),s&&s.length>a.length){a=s,c=l,F=t;break}}}break}}if(null!==a){if(u=a.length,d=F.group,void 0!==d&&(h=F.tokenTypeIdx,f=this.createTokenInstance(a,T,h,F.tokenType,x,I,u),this.handlePayload(f,c),!1===d?v=this.addToken(E,v,f):S[d].push(f)),e=this.chopInput(e,u),T+=u,I=this.computeNewColumn(I,u),!0===N&&!0===F.canLineTerminator){let e,t,n=0;C.lastIndex=0;do{e=C.test(a),!0===e&&(t=C.lastIndex-1,n++)}while(!0===e);0!==n&&(x+=n,I=u-t,this.updateTokenEndLineColumnLocation(f,d,t,n,x,I,u))}this.handleModes(F,D,U,f)}else{const t=T,n=x,i=I;let s=!1===G;for(;!1===s&&T<A;)for(e=this.chopInput(e,1),T++,r=0;r<$;r++){const t=w[r],n=t.pattern,i=t.short;if(!1!==i?y.charCodeAt(T)===i&&(s=!0):!0===t.isCustom?s=null!==n.exec(y,T,E,S):(this.updateLastIndex(n,T),s=null!==n.exec(e)),!0===s)break}if(p=T-t,I=this.computeNewColumn(I,p),m=this.config.errorMessageProvider.buildUnexpectedCharactersMessage(y,t,p,n,i),k.push({offset:t,line:n,column:i,length:p,message:m}),!1===G)break}}return this.hasCustom||(E.length=v),{tokens:E,groups:S,errors:k}}handleModes(e,t,n,r){if(!0===e.pop){const i=e.push;t(r),void 0!==i&&n.call(this,i)}else void 0!==e.push&&n.call(this,e.push)}chopInput(e,t){return e.substring(t)}updateLastIndex(e,t){e.lastIndex=t}updateTokenEndLineColumnLocation(e,t,n,r,i,s,o){let a,c;void 0!==t&&(a=n===o-1,c=a?-1:0,1===r&&!0===a||(e.endLine=i+c,e.endColumn=s-1-c))}computeNewColumn(e,t){return e+t}createOffsetOnlyToken(e,t,n,r){return{image:e,startOffset:t,tokenTypeIdx:n,tokenType:r}}createStartOnlyToken(e,t,n,r,i,s){return{image:e,startOffset:t,startLine:i,startColumn:s,tokenTypeIdx:n,tokenType:r}}createFullToken(e,t,n,r,i,s,o){return{image:e,startOffset:t,endOffset:t+o-1,startLine:i,endLine:i,startColumn:s,endColumn:s+o-1,tokenTypeIdx:n,tokenType:r}}addTokenUsingPush(e,t,n){return e.push(n),t}addTokenUsingMemberAccess(e,t,n){return e[t]=n,++t}handlePayloadNoCustom(e,t){}handlePayloadWithCustom(e,t){null!==t&&(e.payload=t)}matchWithTest(e,t,n){return!0===e.test(t)?t.substring(n,e.lastIndex):null}matchWithExec(e,t){const n=e.exec(t);return null!==n?n[0]:null}}function si(e){return oi(e)?e.LABEL:e.name}function oi(e){return(0,Pt.A)(e.LABEL)&&""!==e.LABEL}ii.SKIPPED="This marks a skipped Token pattern, this means each token identified by it willbe consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.",ii.NA=/NOT_APPLICABLE/;const ai="parent",ci="categories",li="label",ui="group",di="push_mode",hi="pop_mode",fi="longer_alt",pi="line_breaks",mi="start_chars_hint";function gi(e){return function(e){const t=e.pattern,n={};n.name=e.name,(0,Fn.A)(t)||(n.PATTERN=t);if((0,$t.A)(e,ai))throw"The parent property is no longer supported.\nSee: https://github.com/chevrotain/chevrotain/issues/564#issuecomment-349062346 for details.";(0,$t.A)(e,ci)&&(n.CATEGORIES=e[ci]);qr([n]),(0,$t.A)(e,li)&&(n.LABEL=e[li]);(0,$t.A)(e,ui)&&(n.GROUP=e[ui]);(0,$t.A)(e,hi)&&(n.POP_MODE=e[hi]);(0,$t.A)(e,di)&&(n.PUSH_MODE=e[di]);(0,$t.A)(e,fi)&&(n.LONGER_ALT=e[fi]);(0,$t.A)(e,pi)&&(n.LINE_BREAKS=e[pi]);(0,$t.A)(e,mi)&&(n.START_CHARS_HINT=e[mi]);return n}(e)}const yi=gi({name:"EOF",pattern:ii.NA});function Ai(e,t,n,r,i,s,o,a){return{image:t,startOffset:n,endOffset:r,startLine:i,endLine:s,startColumn:o,endColumn:a,tokenTypeIdx:e.tokenTypeIdx,tokenType:e}}function Ti(e,t){return Wr(e,t)}qr([yi]);const vi={buildMismatchTokenMessage:({expected:e,actual:t,previous:n,ruleName:r})=>`Expecting ${oi(e)?`--\x3e ${si(e)} <--`:`token of type --\x3e ${e.name} <--`} but found --\x3e '${t.image}' <--`,buildNotAllInputParsedMessage:({firstRedundant:e,ruleName:t})=>"Redundant input, expecting EOF but found: "+e.image,buildNoViableAltMessage({expectedPathsPerAlt:e,actual:t,previous:n,customUserDescription:r,ruleName:i}){const s="Expecting: ",o="\nbut found: '"+or(t).image+"'";if(r)return s+r+o;{const t=(0,Yn.A)(e,((e,t)=>e.concat(t)),[]),n=(0,Ct.A)(t,(e=>`[${(0,Ct.A)(e,(e=>si(e))).join(", ")}]`));return s+`one of these possible Token sequences:\n${(0,Ct.A)(n,((e,t)=>` ${t+1}. ${e}`)).join("\n")}`+o}},buildEarlyExitMessage({expectedIterationPaths:e,actual:t,customUserDescription:n,ruleName:r}){const i="Expecting: ",s="\nbut found: '"+or(t).image+"'";if(n)return i+n+s;return i+`expecting at least one iteration which starts with one of these possible Token sequences::\n <${(0,Ct.A)(e,(e=>`[${(0,Ct.A)(e,(e=>si(e))).join(",")}]`)).join(" ,")}>`+s}};Object.freeze(vi);const Ri={buildRuleNotFoundError:(e,t)=>"Invalid grammar, reference to a rule which is not defined: ->"+t.nonTerminalName+"<-\ninside top level rule: ->"+e.name+"<-"},Ei={buildDuplicateFoundError(e,t){const n=e.name,r=or(t),i=r.idx,s=wn(r),o=(a=r)instanceof pn?a.terminalType.name:a instanceof sn?a.nonTerminalName:"";var a;let c=`->${s}${i>0?i:""}<- ${o?`with argument: ->${o}<-`:""}\n appears more than once (${t.length} times) in the top level rule: ->${n}<-. \n For further details see: https://chevrotain.io/docs/FAQ.html#NUMERICAL_SUFFIXES \n `;return c=c.replace(/[ \t]+/g," "),c=c.replace(/\s\s+/g,"\n"),c},buildNamespaceConflictError:e=>`Namespace conflict found in grammar.\nThe grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <${e.name}>.\nTo resolve this make sure each Terminal and Non-Terminal names are unique\nThis is easy to accomplish by using the convention that Terminal names start with an uppercase letter\nand Non-Terminal names start with a lower case letter.`,buildAlternationPrefixAmbiguityError(e){const t=(0,Ct.A)(e.prefixPath,(e=>si(e))).join(", "),n=0===e.alternation.idx?"":e.alternation.idx;return`Ambiguous alternatives: <${e.ambiguityIndices.join(" ,")}> due to common lookahead prefix\nin <OR${n}> inside <${e.topLevelRule.name}> Rule,\n<${t}> may appears as a prefix path in all these alternatives.\nSee: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#COMMON_PREFIX\nFor Further details.`},buildAlternationAmbiguityError(e){const t=(0,Ct.A)(e.prefixPath,(e=>si(e))).join(", "),n=0===e.alternation.idx?"":e.alternation.idx;let r=`Ambiguous Alternatives Detected: <${e.ambiguityIndices.join(" ,")}> in <OR${n}> inside <${e.topLevelRule.name}> Rule,\n<${t}> may appears as a prefix path in all these alternatives.\n`;return r+="See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES\nFor Further details.",r},buildEmptyRepetitionError(e){let t=wn(e.repetition);0!==e.repetition.idx&&(t+=e.repetition.idx);return`The repetition <${t}> within Rule <${e.topLevelRule.name}> can never consume any tokens.\nThis could lead to an infinite loop.`},buildTokenNameError:e=>"deprecated",buildEmptyAlternationError:e=>`Ambiguous empty alternative: <${e.emptyChoiceIdx+1}> in <OR${e.alternation.idx}> inside <${e.topLevelRule.name}> Rule.\nOnly the last alternative may be an empty alternative.`,buildTooManyAlternativesError:e=>`An Alternation cannot have more than 256 alternatives:\n<OR${e.alternation.idx}> inside <${e.topLevelRule.name}> Rule.\n has ${e.alternation.definition.length+1} alternatives.`,buildLeftRecursionError(e){const t=e.topLevelRule.name;return`Left Recursion found in grammar.\nrule: <${t}> can be invoked from itself (directly or indirectly)\nwithout consuming any Tokens. The grammar path that causes this is: \n ${`${t} --\x3e ${(0,Ct.A)(e.leftRecursionPath,(e=>e.name)).concat([t]).join(" --\x3e ")}`}\n To fix this refactor your grammar to remove the left recursion.\nsee: https://en.wikipedia.org/wiki/LL_parser#Left_factoring.`},buildInvalidRuleNameError:e=>"deprecated",buildDuplicateRuleNameError(e){let t;t=e.topLevelRule instanceof on?e.topLevelRule.name:e.topLevelRule;return`Duplicate definition, rule: ->${t}<- is already defined in the grammar: ->${e.grammarName}<-`}};class ki extends gn{constructor(e,t){super(),this.nameToTopRule=e,this.errMsgProvider=t,this.errors=[]}resolveRefs(){(0,It.A)((0,St.A)(this.nameToTopRule),(e=>{this.currTopLevel=e,e.accept(this)}))}visitNonTerminal(e){const t=this.nameToTopRule[e.nonTerminalName];if(t)e.referencedRule=t;else{const t=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,e);this.errors.push({message:t,type:eo.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:e.nonTerminalName})}}}const xi=function(e,t){return(0,tr.A)((0,Ct.A)(e,t),1)};var Ii=n(52528);const Si=function(e,t,n,r){for(var i=-1,s=null==e?0:e.length;++i<s;){var o=e[i];t(r,o,n(o),e)}return r};const Ni=function(e,t,n,r){return(0,An.A)(e,(function(e,i,s){t(r,e,n(e),s)})),r};const Ci=function(e,t){return function(n,r){var i=(0,vn.A)(n)?Si:Ni,s=t?t():{};return i(n,e,(0,Ht.A)(r,2),s)}};var $i=Object.prototype.hasOwnProperty;const wi=Ci((function(e,t,n){$i.call(e,n)?e[n].push(t):(0,Ii.A)(e,n,[t])}));const Li=function(e,t,n){var r=null==e?0:e.length;return r?(t=n||void 0===t?1:(0,bt.A)(t),Ot(e,0,(t=r-t)<0?0:t)):[]};class Oi extends Ln{constructor(e,t){super(),this.topProd=e,this.path=t,this.possibleTokTypes=[],this.nextProductionName="",this.nextProductionOccurrence=0,this.found=!1,this.isAtEndOfPath=!1}startWalking(){if(this.found=!1,this.path.ruleStack[0]!==this.topProd.name)throw Error("The path does not start with the walker's top Rule!");return this.ruleStack=(0,wt.A)(this.path.ruleStack).reverse(),this.occurrenceStack=(0,wt.A)(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes}walk(e,t=[]){this.found||super.walk(e,t)}walkProdRef(e,t,n){if(e.referencedRule.name===this.nextProductionName&&e.idx===this.nextProductionOccurrence){const r=t.concat(n);this.updateExpectedNext(),this.walk(e.referencedRule,r)}}updateExpectedNext(){(0,Nt.A)(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())}}class bi extends Oi{constructor(e,t){super(e,t),this.path=t,this.nextTerminalName="",this.nextTerminalOccurrence=0,this.nextTerminalName=this.path.lastTok.name,this.nextTerminalOccurrence=this.path.lastTokOccurrence}walkTerminal(e,t,n){if(this.isAtEndOfPath&&e.terminalType.name===this.nextTerminalName&&e.idx===this.nextTerminalOccurrence&&!this.found){const e=t.concat(n),r=new an({definition:e});this.possibleTokTypes=Mn(r),this.found=!0}}}class _i extends Ln{constructor(e,t){super(),this.topRule=e,this.occurrence=t,this.result={token:void 0,occurrence:void 0,isEndOfRule:void 0}}startWalking(){return this.walk(this.topRule),this.result}}class Pi extends _i{walkMany(e,t,n){if(e.idx===this.occurrence){const e=or(t.concat(n));this.result.isEndOfRule=void 0===e,e instanceof pn&&(this.result.token=e.terminalType,this.result.occurrence=e.idx)}else super.walkMany(e,t,n)}}class Mi extends _i{walkManySep(e,t,n){if(e.idx===this.occurrence){const e=or(t.concat(n));this.result.isEndOfRule=void 0===e,e instanceof pn&&(this.result.token=e.terminalType,this.result.occurrence=e.idx)}else super.walkManySep(e,t,n)}}class Di extends _i{walkAtLeastOne(e,t,n){if(e.idx===this.occurrence){const e=or(t.concat(n));this.result.isEndOfRule=void 0===e,e instanceof pn&&(this.result.token=e.terminalType,this.result.occurrence=e.idx)}else super.walkAtLeastOne(e,t,n)}}class Ui extends _i{walkAtLeastOneSep(e,t,n){if(e.idx===this.occurrence){const e=or(t.concat(n));this.result.isEndOfRule=void 0===e,e instanceof pn&&(this.result.token=e.terminalType,this.result.occurrence=e.idx)}else super.walkAtLeastOneSep(e,t,n)}}function Fi(e,t,n=[]){n=(0,wt.A)(n);let r=[],i=0;function s(s){const o=Fi(s.concat(_t(e,i+1)),t,n);return r.concat(o)}for(;n.length<t&&i<e.length;){const t=e[i];if(t instanceof an)return s(t.definition);if(t instanceof sn)return s(t.definition);if(t instanceof cn)r=s(t.definition);else{if(t instanceof ln){return s(t.definition.concat([new dn({definition:t.definition})]))}if(t instanceof un){return s([new an({definition:t.definition}),new dn({definition:[new pn({terminalType:t.separator})].concat(t.definition)})])}if(t instanceof hn){const e=t.definition.concat([new dn({definition:[new pn({terminalType:t.separator})].concat(t.definition)})]);r=s(e)}else if(t instanceof dn){const e=t.definition.concat([new dn({definition:t.definition})]);r=s(e)}else{if(t instanceof fn)return(0,It.A)(t.definition,(e=>{!1===(0,Nt.A)(e.definition)&&(r=s(e.definition))})),r;if(!(t instanceof pn))throw Error("non exhaustive match");n.push(t.terminalType)}}i++}return r.push({partialPath:n,suffixDef:_t(e,i)}),r}function Gi(e,t,n,r){const i="EXIT_NONE_TERMINAL",s=[i],o="EXIT_ALTERNATIVE";let a=!1;const c=t.length,l=c-r-1,u=[],d=[];for(d.push({idx:-1,def:e,ruleStack:[],occurrenceStack:[]});!(0,Nt.A)(d);){const e=d.pop();if(e===o){a&&(0,Vr.A)(d).idx<=l&&d.pop();continue}const r=e.def,h=e.idx,f=e.ruleStack,p=e.occurrenceStack;if((0,Nt.A)(r))continue;const m=r[0];if(m===i){const e={idx:h,def:_t(r),ruleStack:Li(f),occurrenceStack:Li(p)};d.push(e)}else if(m instanceof pn)if(h<c-1){const e=h+1;if(n(t[e],m.terminalType)){const t={idx:e,def:_t(r),ruleStack:f,occurrenceStack:p};d.push(t)}}else{if(h!==c-1)throw Error("non exhaustive match");u.push({nextTokenType:m.terminalType,nextTokenOccurrence:m.idx,ruleStack:f,occurrenceStack:p}),a=!0}else if(m instanceof sn){const e=(0,wt.A)(f);e.push(m.nonTerminalName);const t=(0,wt.A)(p);t.push(m.idx);const n={idx:h,def:m.definition.concat(s,_t(r)),ruleStack:e,occurrenceStack:t};d.push(n)}else if(m instanceof cn){const e={idx:h,def:_t(r),ruleStack:f,occurrenceStack:p};d.push(e),d.push(o);const t={idx:h,def:m.definition.concat(_t(r)),ruleStack:f,occurrenceStack:p};d.push(t)}else if(m instanceof ln){const e=new dn({definition:m.definition,idx:m.idx}),t={idx:h,def:m.definition.concat([e],_t(r)),ruleStack:f,occurrenceStack:p};d.push(t)}else if(m instanceof un){const e=new pn({terminalType:m.separator}),t=new dn({definition:[e].concat(m.definition),idx:m.idx}),n={idx:h,def:m.definition.concat([t],_t(r)),ruleStack:f,occurrenceStack:p};d.push(n)}else if(m instanceof hn){const e={idx:h,def:_t(r),ruleStack:f,occurrenceStack:p};d.push(e),d.push(o);const t=new pn({terminalType:m.separator}),n=new dn({definition:[t].concat(m.definition),idx:m.idx}),i={idx:h,def:m.definition.concat([n],_t(r)),ruleStack:f,occurrenceStack:p};d.push(i)}else if(m instanceof dn){const e={idx:h,def:_t(r),ruleStack:f,occurrenceStack:p};d.push(e),d.push(o);const t=new dn({definition:m.definition,idx:m.idx}),n={idx:h,def:m.definition.concat([t],_t(r)),ruleStack:f,occurrenceStack:p};d.push(n)}else if(m instanceof fn)for(let t=m.definition.length-1;t>=0;t--){const e={idx:h,def:m.definition[t].definition.concat(_t(r)),ruleStack:f,occurrenceStack:p};d.push(e),d.push(o)}else if(m instanceof an)d.push({idx:h,def:m.definition.concat(_t(r)),ruleStack:f,occurrenceStack:p});else{if(!(m instanceof on))throw Error("non exhaustive match");d.push(Ki(m,h,f,p))}}return u}function Ki(e,t,n,r){const i=(0,wt.A)(n);i.push(e.name);const s=(0,wt.A)(r);return s.push(1),{idx:t,def:e.definition,ruleStack:i,occurrenceStack:s}}var Bi;function ji(e){if(e instanceof cn||"Option"===e)return Bi.OPTION;if(e instanceof dn||"Repetition"===e)return Bi.REPETITION;if(e instanceof ln||"RepetitionMandatory"===e)return Bi.REPETITION_MANDATORY;if(e instanceof un||"RepetitionMandatoryWithSeparator"===e)return Bi.REPETITION_MANDATORY_WITH_SEPARATOR;if(e instanceof hn||"RepetitionWithSeparator"===e)return Bi.REPETITION_WITH_SEPARATOR;if(e instanceof fn||"Alternation"===e)return Bi.ALTERNATION;throw Error("non exhaustive match")}function Vi(e){const{occurrence:t,rule:n,prodType:r,maxLookahead:i}=e,s=ji(r);return s===Bi.ALTERNATION?Zi(t,n,i):es(t,n,s,i)}function Hi(e,t,n,r){const i=e.length,s=Cn(e,(e=>Cn(e,(e=>1===e.length))));if(t)return function(t){const r=(0,Ct.A)(t,(e=>e.GATE));for(let s=0;s<i;s++){const t=e[s],i=t.length,o=r[s];if(void 0===o||!1!==o.call(this))e:for(let e=0;e<i;e++){const r=t[e],i=r.length;for(let e=0;e<i;e++){const t=this.LA(e+1);if(!1===n(t,r[e]))continue e}return s}}};if(s&&!r){const t=(0,Ct.A)(e,(e=>(0,Pn.A)(e))),n=(0,Yn.A)(t,((e,t,n)=>((0,It.A)(t,(t=>{(0,$t.A)(e,t.tokenTypeIdx)||(e[t.tokenTypeIdx]=n),(0,It.A)(t.categoryMatches,(t=>{(0,$t.A)(e,t)||(e[t]=n)}))})),e)),{});return function(){const e=this.LA(1);return n[e.tokenTypeIdx]}}return function(){for(let t=0;t<i;t++){const r=e[t],i=r.length;e:for(let e=0;e<i;e++){const i=r[e],s=i.length;for(let e=0;e<s;e++){const t=this.LA(e+1);if(!1===n(t,i[e]))continue e}return t}}}}function Wi(e,t,n){const r=Cn(e,(e=>1===e.length)),i=e.length;if(r&&!n){const t=(0,Pn.A)(e);if(1===t.length&&(0,Nt.A)(t[0].categoryMatches)){const e=t[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===e}}{const e=(0,Yn.A)(t,((e,t,n)=>(e[t.tokenTypeIdx]=!0,(0,It.A)(t.categoryMatches,(t=>{e[t]=!0})),e)),[]);return function(){const t=this.LA(1);return!0===e[t.tokenTypeIdx]}}}return function(){e:for(let n=0;n<i;n++){const r=e[n],i=r.length;for(let e=0;e<i;e++){const n=this.LA(e+1);if(!1===t(n,r[e]))continue e}return!0}return!1}}!function(e){e[e.OPTION=0]="OPTION",e[e.REPETITION=1]="REPETITION",e[e.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",e[e.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",e[e.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",e[e.ALTERNATION=5]="ALTERNATION"}(Bi||(Bi={}));class zi extends Ln{constructor(e,t,n){super(),this.topProd=e,this.targetOccurrence=t,this.targetProdType=n}startWalking(){return this.walk(this.topProd),this.restDef}checkIsTarget(e,t,n,r){return e.idx===this.targetOccurrence&&this.targetProdType===t&&(this.restDef=n.concat(r),!0)}walkOption(e,t,n){this.checkIsTarget(e,Bi.OPTION,t,n)||super.walkOption(e,t,n)}walkAtLeastOne(e,t,n){this.checkIsTarget(e,Bi.REPETITION_MANDATORY,t,n)||super.walkOption(e,t,n)}walkAtLeastOneSep(e,t,n){this.checkIsTarget(e,Bi.REPETITION_MANDATORY_WITH_SEPARATOR,t,n)||super.walkOption(e,t,n)}walkMany(e,t,n){this.checkIsTarget(e,Bi.REPETITION,t,n)||super.walkOption(e,t,n)}walkManySep(e,t,n){this.checkIsTarget(e,Bi.REPETITION_WITH_SEPARATOR,t,n)||super.walkOption(e,t,n)}}class Yi extends gn{constructor(e,t,n){super(),this.targetOccurrence=e,this.targetProdType=t,this.targetRef=n,this.result=[]}checkIsTarget(e,t){e.idx!==this.targetOccurrence||this.targetProdType!==t||void 0!==this.targetRef&&e!==this.targetRef||(this.result=e.definition)}visitOption(e){this.checkIsTarget(e,Bi.OPTION)}visitRepetition(e){this.checkIsTarget(e,Bi.REPETITION)}visitRepetitionMandatory(e){this.checkIsTarget(e,Bi.REPETITION_MANDATORY)}visitRepetitionMandatoryWithSeparator(e){this.checkIsTarget(e,Bi.REPETITION_MANDATORY_WITH_SEPARATOR)}visitRepetitionWithSeparator(e){this.checkIsTarget(e,Bi.REPETITION_WITH_SEPARATOR)}visitAlternation(e){this.checkIsTarget(e,Bi.ALTERNATION)}}function Xi(e){const t=new Array(e);for(let n=0;n<e;n++)t[n]=[];return t}function qi(e){let t=[""];for(let n=0;n<e.length;n++){const r=e[n],i=[];for(let e=0;e<t.length;e++){const n=t[e];i.push(n+"_"+r.tokenTypeIdx);for(let e=0;e<r.categoryMatches.length;e++){const t="_"+r.categoryMatches[e];i.push(n+t)}}t=i}return t}function Qi(e,t,n){for(let r=0;r<e.length;r++){if(r===n)continue;const i=e[r];for(let e=0;e<t.length;e++){if(!0===i[t[e]])return!1}}return!0}function Ji(e,t){const n=(0,Ct.A)(e,(e=>Fi([e],1))),r=Xi(n.length),i=(0,Ct.A)(n,(e=>{const t={};return(0,It.A)(e,(e=>{const n=qi(e.partialPath);(0,It.A)(n,(e=>{t[e]=!0}))})),t}));let s=n;for(let o=1;o<=t;o++){const e=s;s=Xi(e.length);for(let n=0;n<e.length;n++){const a=e[n];for(let e=0;e<a.length;e++){const c=a[e].partialPath,l=a[e].suffixDef,u=qi(c);if(Qi(i,u,n)||(0,Nt.A)(l)||c.length===t){const e=r[n];if(!1===ts(e,c)){e.push(c);for(let e=0;e<u.length;e++){const t=u[e];i[n][t]=!0}}}else{const e=Fi(l,o+1,c);s[n]=s[n].concat(e),(0,It.A)(e,(e=>{const t=qi(e.partialPath);(0,It.A)(t,(e=>{i[n][e]=!0}))}))}}}}return r}function Zi(e,t,n,r){const i=new Yi(e,Bi.ALTERNATION,r);return t.accept(i),Ji(i.result,n)}function es(e,t,n,r){const i=new Yi(e,n);t.accept(i);const s=i.result,o=new zi(t,e,n).startWalking();return Ji([new an({definition:s}),new an({definition:o})],r)}function ts(e,t){e:for(let n=0;n<e.length;n++){const r=e[n];if(r.length===t.length){for(let e=0;e<r.length;e++){const n=t[e],i=r[e];if(!1===(n===i||void 0!==i.categoryMatchesMap[n.tokenTypeIdx]))continue e}return!0}}return!1}function ns(e){return Cn(e,(e=>Cn(e,(e=>Cn(e,(e=>(0,Nt.A)(e.categoryMatches)))))))}function rs(e,t,n,r){const i=xi(e,(e=>function(e,t){const n=new os;e.accept(n);const r=n.allProductions,i=wi(r,is),s=Yt(i,(e=>e.length>1)),o=(0,Ct.A)((0,St.A)(s),(n=>{const r=or(n),i=t.buildDuplicateFoundError(e,n),s=wn(r),o={message:i,type:eo.DUPLICATE_PRODUCTIONS,ruleName:e.name,dslName:s,occurrence:r.idx},a=ss(r);return a&&(o.parameter=a),o}));return o}(e,n))),s=function(e,t,n){const r=[],i=(0,Ct.A)(t,(e=>e.name));return(0,It.A)(e,(e=>{const t=e.name;if(In(i,t)){const i=n.buildNamespaceConflictError(e);r.push({message:i,type:eo.CONFLICT_TOKENS_RULES_NAMESPACE,ruleName:t})}})),r}(e,t,n),o=xi(e,(e=>function(e,t){const n=new ls;e.accept(n);const r=n.alternations,i=xi(r,(n=>n.definition.length>255?[{message:t.buildTooManyAlternativesError({topLevelRule:e,alternation:n}),type:eo.TOO_MANY_ALTS,ruleName:e.name,occurrence:n.idx}]:[]));return i}(e,n))),a=xi(e,(t=>function(e,t,n,r){const i=[],s=(0,Yn.A)(t,((t,n)=>n.name===e.name?t+1:t),0);if(s>1){const t=r.buildDuplicateRuleNameError({topLevelRule:e,grammarName:n});i.push({message:t,type:eo.DUPLICATE_RULE_NAME,ruleName:e.name})}return i}(t,e,r,n)));return i.concat(s,o,a)}function is(e){return`${wn(e)}_#_${e.idx}_#_${ss(e)}`}function ss(e){return e instanceof pn?e.terminalType.name:e instanceof sn?e.nonTerminalName:""}class os extends gn{constructor(){super(...arguments),this.allProductions=[]}visitNonTerminal(e){this.allProductions.push(e)}visitOption(e){this.allProductions.push(e)}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}visitAlternation(e){this.allProductions.push(e)}visitTerminal(e){this.allProductions.push(e)}}function as(e,t,n,r=[]){const i=[],s=cs(t.definition);if((0,Nt.A)(s))return[];{const t=e.name;In(s,e)&&i.push({message:n.buildLeftRecursionError({topLevelRule:e,leftRecursionPath:r}),type:eo.LEFT_RECURSION,ruleName:t});const o=ir(s,r.concat([e])),a=xi(o,(t=>{const i=(0,wt.A)(r);return i.push(t),as(e,t,n,i)}));return i.concat(a)}}function cs(e){let t=[];if((0,Nt.A)(e))return t;const n=or(e);if(n instanceof sn)t.push(n.referencedRule);else if(n instanceof an||n instanceof cn||n instanceof ln||n instanceof un||n instanceof hn||n instanceof dn)t=t.concat(cs(n.definition));else if(n instanceof fn)t=(0,Pn.A)((0,Ct.A)(n.definition,(e=>cs(e.definition))));else if(!(n instanceof pn))throw Error("non exhaustive match");const r=$n(n),i=e.length>1;if(r&&i){const n=_t(e);return t.concat(cs(n))}return t}class ls extends gn{constructor(){super(...arguments),this.alternations=[]}visitAlternation(e){this.alternations.push(e)}}function us(e,t,n){const r=new ls;e.accept(r);let i=r.alternations;i=Vn(i,(e=>!0===e.ignoreAmbiguities));const s=xi(i,(r=>{const i=r.idx,s=r.maxLookahead||t,o=Zi(i,e,s,r),a=function(e,t,n,r){const i=[],s=(0,Yn.A)(e,((n,r,s)=>(!0===t.definition[s].ignoreAmbiguities||(0,It.A)(r,(r=>{const o=[s];(0,It.A)(e,((e,n)=>{s!==n&&ts(e,r)&&!0!==t.definition[n].ignoreAmbiguities&&o.push(n)})),o.length>1&&!ts(i,r)&&(i.push(r),n.push({alts:o,path:r}))})),n)),[]),o=(0,Ct.A)(s,(e=>{const i=(0,Ct.A)(e.alts,(e=>e+1));return{message:r.buildAlternationAmbiguityError({topLevelRule:n,alternation:t,ambiguityIndices:i,prefixPath:e.path}),type:eo.AMBIGUOUS_ALTS,ruleName:n.name,occurrence:t.idx,alternatives:e.alts}}));return o}(o,r,e,n),c=function(e,t,n,r){const i=(0,Yn.A)(e,((e,t,n)=>{const r=(0,Ct.A)(t,(e=>({idx:n,path:e})));return e.concat(r)}),[]),s=sr(xi(i,(e=>{if(!0===t.definition[e.idx].ignoreAmbiguities)return[];const s=e.idx,o=e.path,a=(0,Xn.A)(i,(e=>{return!0!==t.definition[e.idx].ignoreAmbiguities&&e.idx<s&&(n=e.path,r=o,n.length<r.length&&Cn(n,((e,t)=>{const n=r[t];return e===n||n.categoryMatchesMap[e.tokenTypeIdx]})));var n,r}));return(0,Ct.A)(a,(e=>{const i=[e.idx+1,s+1],o=0===t.idx?"":t.idx;return{message:r.buildAlternationPrefixAmbiguityError({topLevelRule:n,alternation:t,ambiguityIndices:i,prefixPath:e.path}),type:eo.AMBIGUOUS_PREFIX_ALTS,ruleName:n.name,occurrence:o,alternatives:i}}))})));return s}(o,r,e,n);return a.concat(c)}));return s}class ds extends gn{constructor(){super(...arguments),this.allProductions=[]}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}}function hs(e){const t=(0,Gn.A)(e,{errMsgProvider:Ri}),n={};return(0,It.A)(e.rules,(e=>{n[e.name]=e})),function(e,t){const n=new ki(e,t);return n.resolveRefs(),n.errors}(n,t.errMsgProvider)}const fs="MismatchedTokenException",ps="NoViableAltException",ms="EarlyExitException",gs="NotAllInputParsedException",ys=[fs,ps,ms,gs];function As(e){return In(ys,e.name)}Object.freeze(ys);class Ts extends Error{constructor(e,t){super(e),this.token=t,this.resyncedTokens=[],Object.setPrototypeOf(this,new.target.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class vs extends Ts{constructor(e,t,n){super(e,t),this.previousToken=n,this.name=fs}}class Rs extends Ts{constructor(e,t,n){super(e,t),this.previousToken=n,this.name=ps}}class Es extends Ts{constructor(e,t){super(e,t),this.name=gs}}class ks extends Ts{constructor(e,t,n){super(e,t),this.previousToken=n,this.name=ms}}const xs={},Is="InRuleRecoveryException";class Ss extends Error{constructor(e){super(e),this.name=Is}}function Ns(e,t,n,r,i,s,o){const a=this.getKeyForAutomaticLookahead(r,i);let c=this.firstAfterRepMap[a];if(void 0===c){const e=this.getCurrRuleFullName();c=new s(this.getGAstProductions()[e],i).startWalking(),this.firstAfterRepMap[a]=c}let l=c.token,u=c.occurrence;const d=c.isEndOfRule;1===this.RULE_STACK.length&&d&&void 0===l&&(l=yi,u=1),void 0!==l&&void 0!==u&&this.shouldInRepetitionRecoveryBeTried(l,u,o)&&this.tryInRepetitionRecovery(e,t,n,l)}const Cs=1024,$s=1280,ws=1536;function Ls(e,t,n){return n|t|e}class Os{constructor(e){var t;this.maxLookahead=null!==(t=null==e?void 0:e.maxLookahead)&&void 0!==t?t:Js.maxLookahead}validate(e){const t=this.validateNoLeftRecursion(e.rules);if((0,Nt.A)(t)){const n=this.validateEmptyOrAlternatives(e.rules),r=this.validateAmbiguousAlternationAlternatives(e.rules,this.maxLookahead),i=this.validateSomeNonEmptyLookaheadPath(e.rules,this.maxLookahead);return[...t,...n,...r,...i]}return t}validateNoLeftRecursion(e){return xi(e,(e=>as(e,e,Ei)))}validateEmptyOrAlternatives(e){return xi(e,(e=>function(e,t){const n=new ls;e.accept(n);const r=n.alternations;return xi(r,(n=>{const r=Li(n.definition);return xi(r,((r,i)=>{const s=Gi([r],[],Wr,1);return(0,Nt.A)(s)?[{message:t.buildEmptyAlternationError({topLevelRule:e,alternation:n,emptyChoiceIdx:i}),type:eo.NONE_LAST_EMPTY_ALT,ruleName:e.name,occurrence:n.idx,alternative:i+1}]:[]}))}))}(e,Ei)))}validateAmbiguousAlternationAlternatives(e,t){return xi(e,(e=>us(e,t,Ei)))}validateSomeNonEmptyLookaheadPath(e,t){return function(e,t,n){const r=[];return(0,It.A)(e,(e=>{const i=new ds;e.accept(i);const s=i.allProductions;(0,It.A)(s,(i=>{const s=ji(i),o=i.maxLookahead||t,a=es(i.idx,e,s,o)[0];if((0,Nt.A)((0,Pn.A)(a))){const t=n.buildEmptyRepetitionError({topLevelRule:e,repetition:i});r.push({message:t,type:eo.NO_NON_EMPTY_LOOKAHEAD,ruleName:e.name})}}))})),r}(e,t,Ei)}buildLookaheadForAlternation(e){return function(e,t,n,r,i,s){const o=Zi(e,t,n);return s(o,r,ns(o)?zr:Wr,i)}(e.prodOccurrence,e.rule,e.maxLookahead,e.hasPredicates,e.dynamicTokensEnabled,Hi)}buildLookaheadForOptional(e){return function(e,t,n,r,i,s){const o=es(e,t,i,n),a=ns(o)?zr:Wr;return s(o[0],a,r)}(e.prodOccurrence,e.rule,e.maxLookahead,e.dynamicTokensEnabled,ji(e.prodType),Wi)}}const bs=new class extends gn{constructor(){super(...arguments),this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}reset(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}visitOption(e){this.dslMethods.option.push(e)}visitRepetitionWithSeparator(e){this.dslMethods.repetitionWithSeparator.push(e)}visitRepetitionMandatory(e){this.dslMethods.repetitionMandatory.push(e)}visitRepetitionMandatoryWithSeparator(e){this.dslMethods.repetitionMandatoryWithSeparator.push(e)}visitRepetition(e){this.dslMethods.repetition.push(e)}visitAlternation(e){this.dslMethods.alternation.push(e)}};function _s(e,t){!0===isNaN(e.startOffset)?(e.startOffset=t.startOffset,e.endOffset=t.endOffset):e.endOffset<t.endOffset==!0&&(e.endOffset=t.endOffset)}function Ps(e,t){!0===isNaN(e.startOffset)?(e.startOffset=t.startOffset,e.startColumn=t.startColumn,e.startLine=t.startLine,e.endOffset=t.endOffset,e.endColumn=t.endColumn,e.endLine=t.endLine):e.endOffset<t.endOffset==!0&&(e.endOffset=t.endOffset,e.endColumn=t.endColumn,e.endLine=t.endLine)}function Ms(e,t){Object.defineProperty(e,"name",{enumerable:!1,configurable:!0,writable:!1,value:t})}function Ds(e,t){const n=(0,Kt.A)(e),r=n.length;for(let i=0;i<r;i++){const r=e[n[i]],s=r.length;for(let e=0;e<s;e++){const n=r[e];void 0===n.tokenTypeIdx&&this[n.name](n.children,t)}}}function Us(e,t){const n=function(){};Ms(n,e+"BaseSemantics");const r={visit:function(e,t){if((0,vn.A)(e)&&(e=e[0]),!(0,Fn.A)(e))return this[e.name](e.children,t)},validateVisitor:function(){const e=function(e,t){const n=function(e,t){const n=(0,Xn.A)(t,(t=>!1===(0,Hn.A)(e[t]))),r=(0,Ct.A)(n,(t=>({msg:`Missing visitor method: <${t}> on ${e.constructor.name} CST Visitor.`,type:Fs.MISSING_METHOD,methodName:t})));return sr(r)}(e,t);return n}(this,t);if(!(0,Nt.A)(e)){const t=(0,Ct.A)(e,(e=>e.msg));throw Error(`Errors Detected in CST Visitor <${this.constructor.name}>:\n\t${t.join("\n\n").replace(/\n/g,"\n\t")}`)}}};return(n.prototype=r).constructor=n,n._RULE_NAMES=t,n}var Fs;!function(e){e[e.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",e[e.MISSING_METHOD=1]="MISSING_METHOD"}(Fs||(Fs={}));var Gs=n(23149);const Ks={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(Ks);const Bs=!0,js=Math.pow(2,8)-1,Vs=gi({name:"RECORDING_PHASE_TOKEN",pattern:ii.NA});qr([Vs]);const Hs=Ai(Vs,"This IToken indicates the Parser is in Recording Phase\n\tSee: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details",-1,-1,-1,-1,-1,-1);Object.freeze(Hs);const Ws={name:"This CSTNode indicates the Parser is in Recording Phase\n\tSee: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details",children:{}};function zs(e,t,n,r=!1){qs(n);const i=(0,Vr.A)(this.recordingProdStack),s=(0,Hn.A)(t)?t:t.DEF,o=new e({definition:[],idx:n});return r&&(o.separator=t.SEP),(0,$t.A)(t,"MAX_LOOKAHEAD")&&(o.maxLookahead=t.MAX_LOOKAHEAD),this.recordingProdStack.push(o),s.call(this),i.definition.push(o),this.recordingProdStack.pop(),Ks}function Ys(e,t){qs(t);const n=(0,Vr.A)(this.recordingProdStack),r=!1===(0,vn.A)(e),i=!1===r?e:e.DEF,s=new fn({definition:[],idx:t,ignoreAmbiguities:r&&!0===e.IGNORE_AMBIGUITIES});(0,$t.A)(e,"MAX_LOOKAHEAD")&&(s.maxLookahead=e.MAX_LOOKAHEAD);const o=En(i,(e=>(0,Hn.A)(e.GATE)));return s.hasPredicates=o,n.definition.push(s),(0,It.A)(i,(e=>{const t=new an({definition:[]});s.definition.push(t),(0,$t.A)(e,"IGNORE_AMBIGUITIES")?t.ignoreAmbiguities=e.IGNORE_AMBIGUITIES:(0,$t.A)(e,"GATE")&&(t.ignoreAmbiguities=!0),this.recordingProdStack.push(t),e.ALT.call(this),this.recordingProdStack.pop()})),Ks}function Xs(e){return 0===e?"":`${e}`}function qs(e){if(e<0||e>js){const t=new Error(`Invalid DSL Method idx value: <${e}>\n\tIdx value must be a none negative value smaller than ${js+1}`);throw t.KNOWN_RECORDER_ERROR=!0,t}}const Qs=Ai(yi,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(Qs);const Js=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:vi,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1}),Zs=Object.freeze({recoveryValueFunc:()=>{},resyncEnabled:!0});var eo,to,no;function ro(e=void 0){return function(){return e}}!function(e){e[e.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",e[e.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",e[e.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",e[e.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",e[e.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",e[e.LEFT_RECURSION=5]="LEFT_RECURSION",e[e.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",e[e.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",e[e.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",e[e.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",e[e.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",e[e.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",e[e.TOO_MANY_ALTS=12]="TOO_MANY_ALTS",e[e.CUSTOM_LOOKAHEAD_VALIDATION=13]="CUSTOM_LOOKAHEAD_VALIDATION"}(eo||(eo={}));class io{static performSelfAnalysis(e){throw Error("The **static** `performSelfAnalysis` method has been deprecated.\t\nUse the **instance** method with the same name instead.")}performSelfAnalysis(){this.TRACE_INIT("performSelfAnalysis",(()=>{let e;this.selfAnalysisDone=!0;const t=this.className;this.TRACE_INIT("toFastProps",(()=>{Lt(this)})),this.TRACE_INIT("Grammar Recording",(()=>{try{this.enableRecording(),(0,It.A)(this.definedRulesNames,(e=>{const t=this[e].originalGrammarAction;let n;this.TRACE_INIT(`${e} Rule`,(()=>{n=this.topLevelRuleRecord(e,t)})),this.gastProductionsCache[e]=n}))}finally{this.disableRecording()}}));let n=[];if(this.TRACE_INIT("Grammar Resolving",(()=>{n=hs({rules:(0,St.A)(this.gastProductionsCache)}),this.definitionErrors=this.definitionErrors.concat(n)})),this.TRACE_INIT("Grammar Validations",(()=>{if((0,Nt.A)(n)&&!1===this.skipValidations){const n=(e={rules:(0,St.A)(this.gastProductionsCache),tokenTypes:(0,St.A)(this.tokensMap),errMsgProvider:Ei,grammarName:t},rs((e=(0,Gn.A)(e,{errMsgProvider:Ei})).rules,e.tokenTypes,e.errMsgProvider,e.grammarName)),r=function(e){const t=e.lookaheadStrategy.validate({rules:e.rules,tokenTypes:e.tokenTypes,grammarName:e.grammarName});return(0,Ct.A)(t,(e=>Object.assign({type:eo.CUSTOM_LOOKAHEAD_VALIDATION},e)))}({lookaheadStrategy:this.lookaheadStrategy,rules:(0,St.A)(this.gastProductionsCache),tokenTypes:(0,St.A)(this.tokensMap),grammarName:t});this.definitionErrors=this.definitionErrors.concat(n,r)}var e})),(0,Nt.A)(this.definitionErrors)&&(this.recoveryEnabled&&this.TRACE_INIT("computeAllProdsFollows",(()=>{const e=function(e){const t={};return(0,It.A)(e,(e=>{const n=new Un(e).startWalking();jt(t,n)})),t}((0,St.A)(this.gastProductionsCache));this.resyncFollows=e})),this.TRACE_INIT("ComputeLookaheadFunctions",(()=>{var e,t;null===(t=(e=this.lookaheadStrategy).initialize)||void 0===t||t.call(e,{rules:(0,St.A)(this.gastProductionsCache)}),this.preComputeLookaheadFunctions((0,St.A)(this.gastProductionsCache))}))),!io.DEFER_DEFINITION_ERRORS_HANDLING&&!(0,Nt.A)(this.definitionErrors))throw e=(0,Ct.A)(this.definitionErrors,(e=>e.message)),new Error(`Parser Definition Errors detected:\n ${e.join("\n-------------------------------\n")}`)}))}constructor(e,t){this.definitionErrors=[],this.selfAnalysisDone=!1;const n=this;if(n.initErrorHandler(t),n.initLexerAdapter(),n.initLooksAhead(t),n.initRecognizerEngine(e,t),n.initRecoverable(t),n.initTreeBuilder(t),n.initContentAssist(),n.initGastRecorder(t),n.initPerformanceTracer(t),(0,$t.A)(t,"ignoredIssues"))throw new Error("The <ignoredIssues> IParserConfig property has been deprecated.\n\tPlease use the <IGNORE_AMBIGUITIES> flag on the relevant DSL method instead.\n\tSee: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES\n\tFor further details.");this.skipValidations=(0,$t.A)(t,"skipValidations")?t.skipValidations:Js.skipValidations}}io.DEFER_DEFINITION_ERRORS_HANDLING=!1,to=io,no=[class{initRecoverable(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=(0,$t.A)(e,"recoveryEnabled")?e.recoveryEnabled:Js.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=Ns)}getTokenToInsert(e){const t=Ai(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return t.isInsertedInRecovery=!0,t}canTokenTypeBeInsertedInRecovery(e){return!0}canTokenTypeBeDeletedInRecovery(e){return!0}tryInRepetitionRecovery(e,t,n,r){const i=this.findReSyncTokenType(),s=this.exportLexerState(),o=[];let a=!1;const c=this.LA(1);let l=this.LA(1);const u=()=>{const e=this.LA(0),t=this.errorMessageProvider.buildMismatchTokenMessage({expected:r,actual:c,previous:e,ruleName:this.getCurrRuleFullName()}),n=new vs(t,c,this.LA(0));n.resyncedTokens=Li(o),this.SAVE_ERROR(n)};for(;!a;){if(this.tokenMatcher(l,r))return void u();if(n.call(this))return u(),void e.apply(this,t);this.tokenMatcher(l,i)?a=!0:(l=this.SKIP_TOKEN(),this.addToResyncTokens(l,o))}this.importLexerState(s)}shouldInRepetitionRecoveryBeTried(e,t,n){return!1!==n&&!this.tokenMatcher(this.LA(1),e)&&!this.isBackTracking()&&!this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,t))}getFollowsForInRuleRecovery(e,t){const n=this.getCurrentGrammarPath(e,t);return this.getNextPossibleTokenTypes(n)}tryInRuleRecovery(e,t){if(this.canRecoverWithSingleTokenInsertion(e,t))return this.getTokenToInsert(e);if(this.canRecoverWithSingleTokenDeletion(e)){const e=this.SKIP_TOKEN();return this.consumeToken(),e}throw new Ss("sad sad panda")}canPerformInRuleRecovery(e,t){return this.canRecoverWithSingleTokenInsertion(e,t)||this.canRecoverWithSingleTokenDeletion(e)}canRecoverWithSingleTokenInsertion(e,t){if(!this.canTokenTypeBeInsertedInRecovery(e))return!1;if((0,Nt.A)(t))return!1;const n=this.LA(1);return void 0!==(0,ar.A)(t,(e=>this.tokenMatcher(n,e)))}canRecoverWithSingleTokenDeletion(e){return!!this.canTokenTypeBeDeletedInRecovery(e)&&this.tokenMatcher(this.LA(2),e)}isInCurrentRuleReSyncSet(e){const t=this.getCurrFollowKey(),n=this.getFollowSetFromFollowKey(t);return In(n,e)}findReSyncTokenType(){const e=this.flattenFollowSet();let t=this.LA(1),n=2;for(;;){const r=(0,ar.A)(e,(e=>Ti(t,e)));if(void 0!==r)return r;t=this.LA(n),n++}}getCurrFollowKey(){if(1===this.RULE_STACK.length)return xs;const e=this.getLastExplicitRuleShortName(),t=this.getLastExplicitRuleOccurrenceIndex(),n=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:t,inRule:this.shortRuleNameToFullName(n)}}buildFullFollowKeyStack(){const e=this.RULE_STACK,t=this.RULE_OCCURRENCE_STACK;return(0,Ct.A)(e,((n,r)=>0===r?xs:{ruleName:this.shortRuleNameToFullName(n),idxInCallingRule:t[r],inRule:this.shortRuleNameToFullName(e[r-1])}))}flattenFollowSet(){const e=(0,Ct.A)(this.buildFullFollowKeyStack(),(e=>this.getFollowSetFromFollowKey(e)));return(0,Pn.A)(e)}getFollowSetFromFollowKey(e){if(e===xs)return[yi];const t=e.ruleName+e.idxInCallingRule+Dn+e.inRule;return this.resyncFollows[t]}addToResyncTokens(e,t){return this.tokenMatcher(e,yi)||t.push(e),t}reSyncTo(e){const t=[];let n=this.LA(1);for(;!1===this.tokenMatcher(n,e);)n=this.SKIP_TOKEN(),this.addToResyncTokens(n,t);return Li(t)}attemptInRepetitionRecovery(e,t,n,r,i,s,o){}getCurrentGrammarPath(e,t){return{ruleStack:this.getHumanReadableRuleStack(),occurrenceStack:(0,wt.A)(this.RULE_OCCURRENCE_STACK),lastTok:e,lastTokOccurrence:t}}getHumanReadableRuleStack(){return(0,Ct.A)(this.RULE_STACK,(e=>this.shortRuleNameToFullName(e)))}},class{initLooksAhead(e){this.dynamicTokensEnabled=(0,$t.A)(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:Js.dynamicTokensEnabled,this.maxLookahead=(0,$t.A)(e,"maxLookahead")?e.maxLookahead:Js.maxLookahead,this.lookaheadStrategy=(0,$t.A)(e,"lookaheadStrategy")?e.lookaheadStrategy:new Os({maxLookahead:this.maxLookahead}),this.lookAheadFuncsCache=new Map}preComputeLookaheadFunctions(e){(0,It.A)(e,(e=>{this.TRACE_INIT(`${e.name} Rule Lookahead`,(()=>{const{alternation:t,repetition:n,option:r,repetitionMandatory:i,repetitionMandatoryWithSeparator:s,repetitionWithSeparator:o}=function(e){bs.reset(),e.accept(bs);const t=bs.dslMethods;return bs.reset(),t}(e);(0,It.A)(t,(t=>{const n=0===t.idx?"":t.idx;this.TRACE_INIT(`${wn(t)}${n}`,(()=>{const n=this.lookaheadStrategy.buildLookaheadForAlternation({prodOccurrence:t.idx,rule:e,maxLookahead:t.maxLookahead||this.maxLookahead,hasPredicates:t.hasPredicates,dynamicTokensEnabled:this.dynamicTokensEnabled}),r=Ls(this.fullRuleNameToShort[e.name],256,t.idx);this.setLaFuncCache(r,n)}))})),(0,It.A)(n,(t=>{this.computeLookaheadFunc(e,t.idx,768,"Repetition",t.maxLookahead,wn(t))})),(0,It.A)(r,(t=>{this.computeLookaheadFunc(e,t.idx,512,"Option",t.maxLookahead,wn(t))})),(0,It.A)(i,(t=>{this.computeLookaheadFunc(e,t.idx,Cs,"RepetitionMandatory",t.maxLookahead,wn(t))})),(0,It.A)(s,(t=>{this.computeLookaheadFunc(e,t.idx,ws,"RepetitionMandatoryWithSeparator",t.maxLookahead,wn(t))})),(0,It.A)(o,(t=>{this.computeLookaheadFunc(e,t.idx,$s,"RepetitionWithSeparator",t.maxLookahead,wn(t))}))}))}))}computeLookaheadFunc(e,t,n,r,i,s){this.TRACE_INIT(`${s}${0===t?"":t}`,(()=>{const s=this.lookaheadStrategy.buildLookaheadForOptional({prodOccurrence:t,rule:e,maxLookahead:i||this.maxLookahead,dynamicTokensEnabled:this.dynamicTokensEnabled,prodType:r}),o=Ls(this.fullRuleNameToShort[e.name],n,t);this.setLaFuncCache(o,s)}))}getKeyForAutomaticLookahead(e,t){return Ls(this.getLastExplicitRuleShortName(),e,t)}getLaFuncFromCache(e){return this.lookAheadFuncsCache.get(e)}setLaFuncCache(e,t){this.lookAheadFuncsCache.set(e,t)}},class{initTreeBuilder(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=(0,$t.A)(e,"nodeLocationTracking")?e.nodeLocationTracking:Js.nodeLocationTracking,this.outputCst)if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=Ps,this.setNodeLocationFromNode=Ps,this.cstPostRule=jr.A,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=jr.A,this.setNodeLocationFromNode=jr.A,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=_s,this.setNodeLocationFromNode=_s,this.cstPostRule=jr.A,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=jr.A,this.setNodeLocationFromNode=jr.A,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else{if(!/none/i.test(this.nodeLocationTracking))throw Error(`Invalid <nodeLocationTracking> config option: "${e.nodeLocationTracking}"`);this.setNodeLocationFromToken=jr.A,this.setNodeLocationFromNode=jr.A,this.cstPostRule=jr.A,this.setInitialNodeLocation=jr.A}else this.cstInvocationStateUpdate=jr.A,this.cstFinallyStateUpdate=jr.A,this.cstPostTerminal=jr.A,this.cstPostNonTerminal=jr.A,this.cstPostRule=jr.A}setInitialNodeLocationOnlyOffsetRecovery(e){e.location={startOffset:NaN,endOffset:NaN}}setInitialNodeLocationOnlyOffsetRegular(e){e.location={startOffset:this.LA(1).startOffset,endOffset:NaN}}setInitialNodeLocationFullRecovery(e){e.location={startOffset:NaN,startLine:NaN,startColumn:NaN,endOffset:NaN,endLine:NaN,endColumn:NaN}}setInitialNodeLocationFullRegular(e){const t=this.LA(1);e.location={startOffset:t.startOffset,startLine:t.startLine,startColumn:t.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}}cstInvocationStateUpdate(e){const t={name:e,children:Object.create(null)};this.setInitialNodeLocation(t),this.CST_STACK.push(t)}cstFinallyStateUpdate(){this.CST_STACK.pop()}cstPostRuleFull(e){const t=this.LA(0),n=e.location;n.startOffset<=t.startOffset==1?(n.endOffset=t.endOffset,n.endLine=t.endLine,n.endColumn=t.endColumn):(n.startOffset=NaN,n.startLine=NaN,n.startColumn=NaN)}cstPostRuleOnlyOffset(e){const t=this.LA(0),n=e.location;n.startOffset<=t.startOffset==1?n.endOffset=t.endOffset:n.startOffset=NaN}cstPostTerminal(e,t){const n=this.CST_STACK[this.CST_STACK.length-1];var r,i,s;i=t,s=e,void 0===(r=n).children[s]?r.children[s]=[i]:r.children[s].push(i),this.setNodeLocationFromToken(n.location,t)}cstPostNonTerminal(e,t){const n=this.CST_STACK[this.CST_STACK.length-1];!function(e,t,n){void 0===e.children[t]?e.children[t]=[n]:e.children[t].push(n)}(n,t,e),this.setNodeLocationFromNode(n.location,e.location)}getBaseCstVisitorConstructor(){if((0,Fn.A)(this.baseCstVisitorConstructor)){const e=Us(this.className,(0,Kt.A)(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor}getBaseCstVisitorConstructorWithDefaults(){if((0,Fn.A)(this.baseCstVisitorWithDefaultsConstructor)){const e=function(e,t,n){const r=function(){};Ms(r,e+"BaseSemanticsWithDefaults");const i=Object.create(n.prototype);return(0,It.A)(t,(e=>{i[e]=Ds})),(r.prototype=i).constructor=r,r}(this.className,(0,Kt.A)(this.gastProductionsCache),this.getBaseCstVisitorConstructor());return this.baseCstVisitorWithDefaultsConstructor=e,e}return this.baseCstVisitorWithDefaultsConstructor}getLastExplicitRuleShortName(){const e=this.RULE_STACK;return e[e.length-1]}getPreviousExplicitRuleShortName(){const e=this.RULE_STACK;return e[e.length-2]}getLastExplicitRuleOccurrenceIndex(){const e=this.RULE_OCCURRENCE_STACK;return e[e.length-1]}},class{initLexerAdapter(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1}set input(e){if(!0!==this.selfAnalysisDone)throw Error("Missing <performSelfAnalysis> invocation at the end of the Parser's constructor.");this.reset(),this.tokVector=e,this.tokVectorLength=e.length}get input(){return this.tokVector}SKIP_TOKEN(){return this.currIdx<=this.tokVector.length-2?(this.consumeToken(),this.LA(1)):Qs}LA(e){const t=this.currIdx+e;return t<0||this.tokVectorLength<=t?Qs:this.tokVector[t]}consumeToken(){this.currIdx++}exportLexerState(){return this.currIdx}importLexerState(e){this.currIdx=e}resetLexerState(){this.currIdx=-1}moveToTerminatedState(){this.currIdx=this.tokVector.length-1}getLexerPosition(){return this.exportLexerState()}},class{initRecognizerEngine(e,t){if(this.className=this.constructor.name,this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=zr,this.subruleIdx=0,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},(0,$t.A)(t,"serializedGrammar"))throw Error("The Parser's configuration can no longer contain a <serializedGrammar> property.\n\tSee: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0\n\tFor Further details.");if((0,vn.A)(e)){if((0,Nt.A)(e))throw Error("A Token Vocabulary cannot be empty.\n\tNote that the first argument for the parser constructor\n\tis no longer a Token vector (since v4.0).");if("number"==typeof e[0].startOffset)throw Error("The Parser constructor no longer accepts a token vector as the first argument.\n\tSee: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_4-0-0\n\tFor Further details.")}if((0,vn.A)(e))this.tokensMap=(0,Yn.A)(e,((e,t)=>(e[t.name]=t,e)),{});else if((0,$t.A)(e,"modes")&&Cn((0,Pn.A)((0,St.A)(e.modes)),ei)){const t=(0,Pn.A)((0,St.A)(e.modes)),n=_n(t);this.tokensMap=(0,Yn.A)(n,((e,t)=>(e[t.name]=t,e)),{})}else{if(!(0,Gs.A)(e))throw new Error("<tokensDictionary> argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap=(0,wt.A)(e)}this.tokensMap.EOF=yi;const n=(0,$t.A)(e,"modes")?(0,Pn.A)((0,St.A)(e.modes)):(0,St.A)(e),r=Cn(n,(e=>(0,Nt.A)(e.categoryMatches)));this.tokenMatcher=r?zr:Wr,qr((0,St.A)(this.tokensMap))}defineRule(e,t,n){if(this.selfAnalysisDone)throw Error(`Grammar rule <${e}> may not be defined after the 'performSelfAnalysis' method has been called'\nMake sure that all grammar rule definitions are done before 'performSelfAnalysis' is called.`);const r=(0,$t.A)(n,"resyncEnabled")?n.resyncEnabled:Zs.resyncEnabled,i=(0,$t.A)(n,"recoveryValueFunc")?n.recoveryValueFunc:Zs.recoveryValueFunc,s=this.ruleShortNameIdx<<12;let o;return this.ruleShortNameIdx++,this.shortRuleNameToFull[s]=e,this.fullRuleNameToShort[e]=s,o=!0===this.outputCst?function(...n){try{this.ruleInvocationStateUpdate(s,e,this.subruleIdx),t.apply(this,n);const r=this.CST_STACK[this.CST_STACK.length-1];return this.cstPostRule(r),r}catch(o){return this.invokeRuleCatch(o,r,i)}finally{this.ruleFinallyStateUpdate()}}:function(...n){try{return this.ruleInvocationStateUpdate(s,e,this.subruleIdx),t.apply(this,n)}catch(o){return this.invokeRuleCatch(o,r,i)}finally{this.ruleFinallyStateUpdate()}},Object.assign(o,{ruleName:e,originalGrammarAction:t})}invokeRuleCatch(e,t,n){const r=1===this.RULE_STACK.length,i=t&&!this.isBackTracking()&&this.recoveryEnabled;if(As(e)){const t=e;if(i){const r=this.findReSyncTokenType();if(this.isInCurrentRuleReSyncSet(r)){if(t.resyncedTokens=this.reSyncTo(r),this.outputCst){const e=this.CST_STACK[this.CST_STACK.length-1];return e.recoveredNode=!0,e}return n(e)}if(this.outputCst){const e=this.CST_STACK[this.CST_STACK.length-1];e.recoveredNode=!0,t.partialCstResult=e}throw t}if(r)return this.moveToTerminatedState(),n(e);throw t}throw e}optionInternal(e,t){const n=this.getKeyForAutomaticLookahead(512,t);return this.optionInternalLogic(e,t,n)}optionInternalLogic(e,t,n){let r,i=this.getLaFuncFromCache(n);if("function"!=typeof e){r=e.DEF;const t=e.GATE;if(void 0!==t){const e=i;i=()=>t.call(this)&&e.call(this)}}else r=e;if(!0===i.call(this))return r.call(this)}atLeastOneInternal(e,t){const n=this.getKeyForAutomaticLookahead(Cs,e);return this.atLeastOneInternalLogic(e,t,n)}atLeastOneInternalLogic(e,t,n){let r,i=this.getLaFuncFromCache(n);if("function"!=typeof t){r=t.DEF;const e=t.GATE;if(void 0!==e){const t=i;i=()=>e.call(this)&&t.call(this)}}else r=t;if(!0!==i.call(this))throw this.raiseEarlyExitException(e,Bi.REPETITION_MANDATORY,t.ERR_MSG);{let e=this.doSingleRepetition(r);for(;!0===i.call(this)&&!0===e;)e=this.doSingleRepetition(r)}this.attemptInRepetitionRecovery(this.atLeastOneInternal,[e,t],i,Cs,e,Di)}atLeastOneSepFirstInternal(e,t){const n=this.getKeyForAutomaticLookahead(ws,e);this.atLeastOneSepFirstInternalLogic(e,t,n)}atLeastOneSepFirstInternalLogic(e,t,n){const r=t.DEF,i=t.SEP;if(!0!==this.getLaFuncFromCache(n).call(this))throw this.raiseEarlyExitException(e,Bi.REPETITION_MANDATORY_WITH_SEPARATOR,t.ERR_MSG);{r.call(this);const t=()=>this.tokenMatcher(this.LA(1),i);for(;!0===this.tokenMatcher(this.LA(1),i);)this.CONSUME(i),r.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,i,t,r,Ui],t,ws,e,Ui)}}manyInternal(e,t){const n=this.getKeyForAutomaticLookahead(768,e);return this.manyInternalLogic(e,t,n)}manyInternalLogic(e,t,n){let r,i=this.getLaFuncFromCache(n);if("function"!=typeof t){r=t.DEF;const e=t.GATE;if(void 0!==e){const t=i;i=()=>e.call(this)&&t.call(this)}}else r=t;let s=!0;for(;!0===i.call(this)&&!0===s;)s=this.doSingleRepetition(r);this.attemptInRepetitionRecovery(this.manyInternal,[e,t],i,768,e,Pi,s)}manySepFirstInternal(e,t){const n=this.getKeyForAutomaticLookahead($s,e);this.manySepFirstInternalLogic(e,t,n)}manySepFirstInternalLogic(e,t,n){const r=t.DEF,i=t.SEP;if(!0===this.getLaFuncFromCache(n).call(this)){r.call(this);const t=()=>this.tokenMatcher(this.LA(1),i);for(;!0===this.tokenMatcher(this.LA(1),i);)this.CONSUME(i),r.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,i,t,r,Mi],t,$s,e,Mi)}}repetitionSepSecondInternal(e,t,n,r,i){for(;n();)this.CONSUME(t),r.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,t,n,r,i],n,ws,e,i)}doSingleRepetition(e){const t=this.getLexerPosition();return e.call(this),this.getLexerPosition()>t}orInternal(e,t){const n=this.getKeyForAutomaticLookahead(256,t),r=(0,vn.A)(e)?e:e.DEF,i=this.getLaFuncFromCache(n).call(this,r);if(void 0!==i)return r[i].ALT.call(this);this.raiseNoAltException(t,e.ERR_MSG)}ruleFinallyStateUpdate(){if(this.RULE_STACK.pop(),this.RULE_OCCURRENCE_STACK.pop(),this.cstFinallyStateUpdate(),0===this.RULE_STACK.length&&!1===this.isAtEndOfInput()){const e=this.LA(1),t=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new Es(t,e))}}subruleInternal(e,t,n){let r;try{const i=void 0!==n?n.ARGS:void 0;return this.subruleIdx=t,r=e.apply(this,i),this.cstPostNonTerminal(r,void 0!==n&&void 0!==n.LABEL?n.LABEL:e.ruleName),r}catch(i){throw this.subruleInternalError(i,n,e.ruleName)}}subruleInternalError(e,t,n){throw As(e)&&void 0!==e.partialCstResult&&(this.cstPostNonTerminal(e.partialCstResult,void 0!==t&&void 0!==t.LABEL?t.LABEL:n),delete e.partialCstResult),e}consumeInternal(e,t,n){let r;try{const t=this.LA(1);!0===this.tokenMatcher(t,e)?(this.consumeToken(),r=t):this.consumeInternalError(e,t,n)}catch(i){r=this.consumeInternalRecovery(e,t,i)}return this.cstPostTerminal(void 0!==n&&void 0!==n.LABEL?n.LABEL:e.name,r),r}consumeInternalError(e,t,n){let r;const i=this.LA(0);throw r=void 0!==n&&n.ERR_MSG?n.ERR_MSG:this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:t,previous:i,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new vs(r,t,i))}consumeInternalRecovery(e,t,n){if(!this.recoveryEnabled||"MismatchedTokenException"!==n.name||this.isBackTracking())throw n;{const i=this.getFollowsForInRuleRecovery(e,t);try{return this.tryInRuleRecovery(e,i)}catch(r){throw r.name===Is?n:r}}}saveRecogState(){const e=this.errors,t=(0,wt.A)(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:t,CST_STACK:this.CST_STACK}}reloadRecogState(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK}ruleInvocationStateUpdate(e,t,n){this.RULE_OCCURRENCE_STACK.push(n),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(t)}isBackTracking(){return 0!==this.isBackTrackingStack.length}getCurrRuleFullName(){const e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]}shortRuleNameToFullName(e){return this.shortRuleNameToFull[e]}isAtEndOfInput(){return this.tokenMatcher(this.LA(1),yi)}reset(){this.resetLexerState(),this.subruleIdx=0,this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]}},class{ACTION(e){return e.call(this)}consume(e,t,n){return this.consumeInternal(t,e,n)}subrule(e,t,n){return this.subruleInternal(t,e,n)}option(e,t){return this.optionInternal(t,e)}or(e,t){return this.orInternal(t,e)}many(e,t){return this.manyInternal(e,t)}atLeastOne(e,t){return this.atLeastOneInternal(e,t)}CONSUME(e,t){return this.consumeInternal(e,0,t)}CONSUME1(e,t){return this.consumeInternal(e,1,t)}CONSUME2(e,t){return this.consumeInternal(e,2,t)}CONSUME3(e,t){return this.consumeInternal(e,3,t)}CONSUME4(e,t){return this.consumeInternal(e,4,t)}CONSUME5(e,t){return this.consumeInternal(e,5,t)}CONSUME6(e,t){return this.consumeInternal(e,6,t)}CONSUME7(e,t){return this.consumeInternal(e,7,t)}CONSUME8(e,t){return this.consumeInternal(e,8,t)}CONSUME9(e,t){return this.consumeInternal(e,9,t)}SUBRULE(e,t){return this.subruleInternal(e,0,t)}SUBRULE1(e,t){return this.subruleInternal(e,1,t)}SUBRULE2(e,t){return this.subruleInternal(e,2,t)}SUBRULE3(e,t){return this.subruleInternal(e,3,t)}SUBRULE4(e,t){return this.subruleInternal(e,4,t)}SUBRULE5(e,t){return this.subruleInternal(e,5,t)}SUBRULE6(e,t){return this.subruleInternal(e,6,t)}SUBRULE7(e,t){return this.subruleInternal(e,7,t)}SUBRULE8(e,t){return this.subruleInternal(e,8,t)}SUBRULE9(e,t){return this.subruleInternal(e,9,t)}OPTION(e){return this.optionInternal(e,0)}OPTION1(e){return this.optionInternal(e,1)}OPTION2(e){return this.optionInternal(e,2)}OPTION3(e){return this.optionInternal(e,3)}OPTION4(e){return this.optionInternal(e,4)}OPTION5(e){return this.optionInternal(e,5)}OPTION6(e){return this.optionInternal(e,6)}OPTION7(e){return this.optionInternal(e,7)}OPTION8(e){return this.optionInternal(e,8)}OPTION9(e){return this.optionInternal(e,9)}OR(e){return this.orInternal(e,0)}OR1(e){return this.orInternal(e,1)}OR2(e){return this.orInternal(e,2)}OR3(e){return this.orInternal(e,3)}OR4(e){return this.orInternal(e,4)}OR5(e){return this.orInternal(e,5)}OR6(e){return this.orInternal(e,6)}OR7(e){return this.orInternal(e,7)}OR8(e){return this.orInternal(e,8)}OR9(e){return this.orInternal(e,9)}MANY(e){this.manyInternal(0,e)}MANY1(e){this.manyInternal(1,e)}MANY2(e){this.manyInternal(2,e)}MANY3(e){this.manyInternal(3,e)}MANY4(e){this.manyInternal(4,e)}MANY5(e){this.manyInternal(5,e)}MANY6(e){this.manyInternal(6,e)}MANY7(e){this.manyInternal(7,e)}MANY8(e){this.manyInternal(8,e)}MANY9(e){this.manyInternal(9,e)}MANY_SEP(e){this.manySepFirstInternal(0,e)}MANY_SEP1(e){this.manySepFirstInternal(1,e)}MANY_SEP2(e){this.manySepFirstInternal(2,e)}MANY_SEP3(e){this.manySepFirstInternal(3,e)}MANY_SEP4(e){this.manySepFirstInternal(4,e)}MANY_SEP5(e){this.manySepFirstInternal(5,e)}MANY_SEP6(e){this.manySepFirstInternal(6,e)}MANY_SEP7(e){this.manySepFirstInternal(7,e)}MANY_SEP8(e){this.manySepFirstInternal(8,e)}MANY_SEP9(e){this.manySepFirstInternal(9,e)}AT_LEAST_ONE(e){this.atLeastOneInternal(0,e)}AT_LEAST_ONE1(e){return this.atLeastOneInternal(1,e)}AT_LEAST_ONE2(e){this.atLeastOneInternal(2,e)}AT_LEAST_ONE3(e){this.atLeastOneInternal(3,e)}AT_LEAST_ONE4(e){this.atLeastOneInternal(4,e)}AT_LEAST_ONE5(e){this.atLeastOneInternal(5,e)}AT_LEAST_ONE6(e){this.atLeastOneInternal(6,e)}AT_LEAST_ONE7(e){this.atLeastOneInternal(7,e)}AT_LEAST_ONE8(e){this.atLeastOneInternal(8,e)}AT_LEAST_ONE9(e){this.atLeastOneInternal(9,e)}AT_LEAST_ONE_SEP(e){this.atLeastOneSepFirstInternal(0,e)}AT_LEAST_ONE_SEP1(e){this.atLeastOneSepFirstInternal(1,e)}AT_LEAST_ONE_SEP2(e){this.atLeastOneSepFirstInternal(2,e)}AT_LEAST_ONE_SEP3(e){this.atLeastOneSepFirstInternal(3,e)}AT_LEAST_ONE_SEP4(e){this.atLeastOneSepFirstInternal(4,e)}AT_LEAST_ONE_SEP5(e){this.atLeastOneSepFirstInternal(5,e)}AT_LEAST_ONE_SEP6(e){this.atLeastOneSepFirstInternal(6,e)}AT_LEAST_ONE_SEP7(e){this.atLeastOneSepFirstInternal(7,e)}AT_LEAST_ONE_SEP8(e){this.atLeastOneSepFirstInternal(8,e)}AT_LEAST_ONE_SEP9(e){this.atLeastOneSepFirstInternal(9,e)}RULE(e,t,n=Zs){if(In(this.definedRulesNames,e)){const t={message:Ei.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),type:eo.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(t)}this.definedRulesNames.push(e);const r=this.defineRule(e,t,n);return this[e]=r,r}OVERRIDE_RULE(e,t,n=Zs){const r=function(e,t,n){const r=[];let i;return In(t,e)||(i=`Invalid rule override, rule: ->${e}<- cannot be overridden in the grammar: ->${n}<-as it is not defined in any of the super grammars `,r.push({message:i,type:eo.INVALID_RULE_OVERRIDE,ruleName:e})),r}(e,this.definedRulesNames,this.className);this.definitionErrors=this.definitionErrors.concat(r);const i=this.defineRule(e,t,n);return this[e]=i,i}BACKTRACK(e,t){return function(){this.isBackTrackingStack.push(1);const n=this.saveRecogState();try{return e.apply(this,t),!0}catch(r){if(As(r))return!1;throw r}finally{this.reloadRecogState(n),this.isBackTrackingStack.pop()}}}getGAstProductions(){return this.gastProductionsCache}getSerializedGastProductions(){return e=(0,St.A)(this.gastProductionsCache),(0,Ct.A)(e,mn);var e}},class{initErrorHandler(e){this._errors=[],this.errorMessageProvider=(0,$t.A)(e,"errorMessageProvider")?e.errorMessageProvider:Js.errorMessageProvider}SAVE_ERROR(e){if(As(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:(0,wt.A)(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")}get errors(){return(0,wt.A)(this._errors)}set errors(e){this._errors=e}raiseEarlyExitException(e,t,n){const r=this.getCurrRuleFullName(),i=es(e,this.getGAstProductions()[r],t,this.maxLookahead)[0],s=[];for(let a=1;a<=this.maxLookahead;a++)s.push(this.LA(a));const o=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:i,actual:s,previous:this.LA(0),customUserDescription:n,ruleName:r});throw this.SAVE_ERROR(new ks(o,this.LA(1),this.LA(0)))}raiseNoAltException(e,t){const n=this.getCurrRuleFullName(),r=Zi(e,this.getGAstProductions()[n],this.maxLookahead),i=[];for(let a=1;a<=this.maxLookahead;a++)i.push(this.LA(a));const s=this.LA(0),o=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:r,actual:i,previous:s,customUserDescription:t,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new Rs(o,this.LA(1),s))}},class{initContentAssist(){}computeContentAssist(e,t){const n=this.gastProductionsCache[e];if((0,Fn.A)(n))throw Error(`Rule ->${e}<- does not exist in this grammar.`);return Gi([n],t,this.tokenMatcher,this.maxLookahead)}getNextPossibleTokenTypes(e){const t=or(e.ruleStack),n=this.getGAstProductions()[t];return new bi(n,e).startWalking()}},class{initGastRecorder(e){this.recordingProdStack=[],this.RECORDING_PHASE=!1}enableRecording(){this.RECORDING_PHASE=!0,this.TRACE_INIT("Enable Recording",(()=>{for(let e=0;e<10;e++){const t=e>0?e:"";this[`CONSUME${t}`]=function(t,n){return this.consumeInternalRecord(t,e,n)},this[`SUBRULE${t}`]=function(t,n){return this.subruleInternalRecord(t,e,n)},this[`OPTION${t}`]=function(t){return this.optionInternalRecord(t,e)},this[`OR${t}`]=function(t){return this.orInternalRecord(t,e)},this[`MANY${t}`]=function(t){this.manyInternalRecord(e,t)},this[`MANY_SEP${t}`]=function(t){this.manySepFirstInternalRecord(e,t)},this[`AT_LEAST_ONE${t}`]=function(t){this.atLeastOneInternalRecord(e,t)},this[`AT_LEAST_ONE_SEP${t}`]=function(t){this.atLeastOneSepFirstInternalRecord(e,t)}}this.consume=function(e,t,n){return this.consumeInternalRecord(t,e,n)},this.subrule=function(e,t,n){return this.subruleInternalRecord(t,e,n)},this.option=function(e,t){return this.optionInternalRecord(t,e)},this.or=function(e,t){return this.orInternalRecord(t,e)},this.many=function(e,t){this.manyInternalRecord(e,t)},this.atLeastOne=function(e,t){this.atLeastOneInternalRecord(e,t)},this.ACTION=this.ACTION_RECORD,this.BACKTRACK=this.BACKTRACK_RECORD,this.LA=this.LA_RECORD}))}disableRecording(){this.RECORDING_PHASE=!1,this.TRACE_INIT("Deleting Recording methods",(()=>{const e=this;for(let t=0;t<10;t++){const n=t>0?t:"";delete e[`CONSUME${n}`],delete e[`SUBRULE${n}`],delete e[`OPTION${n}`],delete e[`OR${n}`],delete e[`MANY${n}`],delete e[`MANY_SEP${n}`],delete e[`AT_LEAST_ONE${n}`],delete e[`AT_LEAST_ONE_SEP${n}`]}delete e.consume,delete e.subrule,delete e.option,delete e.or,delete e.many,delete e.atLeastOne,delete e.ACTION,delete e.BACKTRACK,delete e.LA}))}ACTION_RECORD(e){}BACKTRACK_RECORD(e,t){return()=>!0}LA_RECORD(e){return Qs}topLevelRuleRecord(e,t){try{const n=new on({definition:[],name:e});return n.name=e,this.recordingProdStack.push(n),t.call(this),this.recordingProdStack.pop(),n}catch(n){if(!0!==n.KNOWN_RECORDER_ERROR)try{n.message=n.message+'\n\t This error was thrown during the "grammar recording phase" For more info see:\n\thttps://chevrotain.io/docs/guide/internals.html#grammar-recording'}catch(r){throw n}throw n}}optionInternalRecord(e,t){return zs.call(this,cn,e,t)}atLeastOneInternalRecord(e,t){zs.call(this,ln,t,e)}atLeastOneSepFirstInternalRecord(e,t){zs.call(this,un,t,e,Bs)}manyInternalRecord(e,t){zs.call(this,dn,t,e)}manySepFirstInternalRecord(e,t){zs.call(this,hn,t,e,Bs)}orInternalRecord(e,t){return Ys.call(this,e,t)}subruleInternalRecord(e,t,n){if(qs(t),!e||!1===(0,$t.A)(e,"ruleName")){const n=new Error(`<SUBRULE${Xs(t)}> argument is invalid expecting a Parser method reference but got: <${JSON.stringify(e)}>\n inside top level rule: <${this.recordingProdStack[0].name}>`);throw n.KNOWN_RECORDER_ERROR=!0,n}const r=(0,Vr.A)(this.recordingProdStack),i=e.ruleName,s=new sn({idx:t,nonTerminalName:i,label:null==n?void 0:n.LABEL,referencedRule:void 0});return r.definition.push(s),this.outputCst?Ws:Ks}consumeInternalRecord(e,t,n){if(qs(t),!Jr(e)){const n=new Error(`<CONSUME${Xs(t)}> argument is invalid expecting a TokenType reference but got: <${JSON.stringify(e)}>\n inside top level rule: <${this.recordingProdStack[0].name}>`);throw n.KNOWN_RECORDER_ERROR=!0,n}const r=(0,Vr.A)(this.recordingProdStack),i=new pn({idx:t,terminalType:e,label:null==n?void 0:n.LABEL});return r.definition.push(i),Hs}},class{initPerformanceTracer(e){if((0,$t.A)(e,"traceInitPerf")){const t=e.traceInitPerf,n="number"==typeof t;this.traceInitMaxIdent=n?t:1/0,this.traceInitPerf=n?t>0:t}else this.traceInitMaxIdent=0,this.traceInitPerf=Js.traceInitPerf;this.traceInitIndent=-1}TRACE_INIT(e,t){if(!0===this.traceInitPerf){this.traceInitIndent++;const n=new Array(this.traceInitIndent+1).join("\t");this.traceInitIndent<this.traceInitMaxIdent&&console.log(`${n}--\x3e <${e}>`);const{time:r,value:i}=Hr(t),s=r>10?console.warn:console.log;return this.traceInitIndent<this.traceInitMaxIdent&&s(`${n}<-- <${e}> time: ${r}ms`),this.traceInitIndent--,i}return t()}}],no.forEach((e=>{const t=e.prototype;Object.getOwnPropertyNames(t).forEach((n=>{if("constructor"===n)return;const r=Object.getOwnPropertyDescriptor(t,n);r&&(r.get||r.set)?Object.defineProperty(to.prototype,n,r):to.prototype[n]=e.prototype[n]}))}));class so extends io{constructor(e,t=Js){const n=(0,wt.A)(t);n.outputCst=!1,super(e,n)}}function oo(e,t,n){return`${e.name}_${t}_${n}`}class ao{constructor(e){this.target=e}isEpsilon(){return!1}}class co extends ao{constructor(e,t){super(e),this.tokenType=t}}class lo extends ao{constructor(e){super(e)}isEpsilon(){return!0}}class uo extends ao{constructor(e,t,n){super(e),this.rule=t,this.followState=n}isEpsilon(){return!0}}function ho(e){const t={decisionMap:{},decisionStates:[],ruleToStartState:new Map,ruleToStopState:new Map,states:[]};!function(e,t){const n=t.length;for(let r=0;r<n;r++){const n=t[r],i=Eo(e,n,void 0,{type:2}),s=Eo(e,n,void 0,{type:7});i.stop=s,e.ruleToStartState.set(n,i),e.ruleToStopState.set(n,s)}}(t,e);const n=e.length;for(let r=0;r<n;r++){const n=e[r],i=po(t,n,n);void 0!==i&&vo(t,n,i)}return t}function fo(e,t,n){return n instanceof pn?To(e,t,n.terminalType,n):n instanceof sn?function(e,t,n){const r=n.referencedRule,i=e.ruleToStartState.get(r),s=Eo(e,t,n,{type:1}),o=Eo(e,t,n,{type:1}),a=new uo(i,r,o);return ko(s,a),{left:s,right:o}}(e,t,n):n instanceof fn?function(e,t,n){const r=Eo(e,t,n,{type:1});yo(e,r);const i=(0,Ct.A)(n.definition,(n=>fo(e,t,n))),s=Ao(e,t,r,n,...i);return s}(e,t,n):n instanceof cn?function(e,t,n){const r=Eo(e,t,n,{type:1});yo(e,r);const i=Ao(e,t,r,n,po(e,t,n));return function(e,t,n,r){const i=r.left,s=r.right;return Ro(i,s),e.decisionMap[oo(t,"Option",n.idx)]=i,r}(e,t,n,i)}(e,t,n):n instanceof dn?function(e,t,n){const r=Eo(e,t,n,{type:5});yo(e,r);const i=Ao(e,t,r,n,po(e,t,n));return go(e,t,n,i)}(e,t,n):n instanceof hn?function(e,t,n){const r=Eo(e,t,n,{type:5});yo(e,r);const i=Ao(e,t,r,n,po(e,t,n)),s=To(e,t,n.separator,n);return go(e,t,n,i,s)}(e,t,n):n instanceof ln?function(e,t,n){const r=Eo(e,t,n,{type:4});yo(e,r);const i=Ao(e,t,r,n,po(e,t,n));return mo(e,t,n,i)}(e,t,n):n instanceof un?function(e,t,n){const r=Eo(e,t,n,{type:4});yo(e,r);const i=Ao(e,t,r,n,po(e,t,n)),s=To(e,t,n.separator,n);return mo(e,t,n,i,s)}(e,t,n):po(e,t,n)}function po(e,t,n){const r=(0,Xn.A)((0,Ct.A)(n.definition,(n=>fo(e,t,n))),(e=>void 0!==e));return 1===r.length?r[0]:0===r.length?void 0:function(e,t){const n=t.length;for(let s=0;s<n-1;s++){const n=t[s];let r;1===n.left.transitions.length&&(r=n.left.transitions[0]);const i=r instanceof uo,o=r,a=t[s+1].left;1===n.left.type&&1===n.right.type&&void 0!==r&&(i&&o.followState===n.right||r.target===n.right)?(i?o.followState=a:r.target=a,xo(e,n.right)):Ro(n.right,a)}const r=t[0],i=t[n-1];return{left:r.left,right:i.right}}(e,r)}function mo(e,t,n,r,i){const s=r.left,o=r.right,a=Eo(e,t,n,{type:11});yo(e,a);const c=Eo(e,t,n,{type:12});return s.loopback=a,c.loopback=a,e.decisionMap[oo(t,i?"RepetitionMandatoryWithSeparator":"RepetitionMandatory",n.idx)]=a,Ro(o,a),void 0===i?(Ro(a,s),Ro(a,c)):(Ro(a,c),Ro(a,i.left),Ro(i.right,s)),{left:s,right:c}}function go(e,t,n,r,i){const s=r.left,o=r.right,a=Eo(e,t,n,{type:10});yo(e,a);const c=Eo(e,t,n,{type:12}),l=Eo(e,t,n,{type:9});return a.loopback=l,c.loopback=l,Ro(a,s),Ro(a,c),Ro(o,l),void 0!==i?(Ro(l,c),Ro(l,i.left),Ro(i.right,s)):Ro(l,a),e.decisionMap[oo(t,i?"RepetitionWithSeparator":"Repetition",n.idx)]=a,{left:a,right:c}}function yo(e,t){return e.decisionStates.push(t),t.decision=e.decisionStates.length-1,t.decision}function Ao(e,t,n,r,...i){const s=Eo(e,t,r,{type:8,start:n});n.end=s;for(const a of i)void 0!==a?(Ro(n,a.left),Ro(a.right,s)):Ro(n,s);const o={left:n,right:s};return e.decisionMap[oo(t,function(e){if(e instanceof fn)return"Alternation";if(e instanceof cn)return"Option";if(e instanceof dn)return"Repetition";if(e instanceof hn)return"RepetitionWithSeparator";if(e instanceof ln)return"RepetitionMandatory";if(e instanceof un)return"RepetitionMandatoryWithSeparator";throw new Error("Invalid production type encountered")}(r),r.idx)]=n,o}function To(e,t,n,r){const i=Eo(e,t,r,{type:1}),s=Eo(e,t,r,{type:1});return ko(i,new co(s,n)),{left:i,right:s}}function vo(e,t,n){const r=e.ruleToStartState.get(t);Ro(r,n.left);const i=e.ruleToStopState.get(t);Ro(n.right,i);return{left:r,right:i}}function Ro(e,t){ko(e,new lo(t))}function Eo(e,t,n,r){const i=Object.assign({atn:e,production:n,epsilonOnlyTransitions:!1,rule:t,transitions:[],nextTokenWithinRule:[],stateNumber:e.states.length},r);return e.states.push(i),i}function ko(e,t){0===e.transitions.length&&(e.epsilonOnlyTransitions=t.isEpsilon()),e.transitions.push(t)}function xo(e,t){e.states.splice(e.states.indexOf(t),1)}const Io={};class So{constructor(){this.map={},this.configs=[]}get size(){return this.configs.length}finalize(){this.map={}}add(e){const t=No(e);t in this.map||(this.map[t]=this.configs.length,this.configs.push(e))}get elements(){return this.configs}get alts(){return(0,Ct.A)(this.configs,(e=>e.alt))}get key(){let e="";for(const t in this.map)e+=t+":";return e}}function No(e,t=!0){return`${t?`a${e.alt}`:""}s${e.state.stateNumber}:${e.stack.map((e=>e.stateNumber.toString())).join("_")}`}var Co=n(86452);const $o=function(e,t){return e&&e.length?(0,bn.A)(e,(0,Ht.A)(t,2)):[]};function wo(e,t){const n={};return r=>{const i=r.toString();let s=n[i];return void 0!==s||(s={atnStartState:e,decision:t,states:{}},n[i]=s),s}}class Lo{constructor(){this.predicates=[]}is(e){return e>=this.predicates.length||this.predicates[e]}set(e,t){this.predicates[e]=t}toString(){let e="";const t=this.predicates.length;for(let n=0;n<t;n++)e+=!0===this.predicates[n]?"1":"0";return e}}const Oo=new Lo;class bo extends Os{constructor(e){var t;super(),this.logging=null!==(t=null==e?void 0:e.logging)&&void 0!==t?t:e=>console.log(e)}initialize(e){this.atn=ho(e.rules),this.dfas=function(e){const t=e.decisionStates.length,n=Array(t);for(let r=0;r<t;r++)n[r]=wo(e.decisionStates[r],r);return n}(this.atn)}validateAmbiguousAlternationAlternatives(){return[]}validateEmptyOrAlternatives(){return[]}buildLookaheadForAlternation(e){const{prodOccurrence:t,rule:n,hasPredicates:r,dynamicTokensEnabled:i}=e,s=this.dfas,o=this.logging,a=oo(n,"Alternation",t),c=this.atn.decisionMap[a].decision,l=(0,Ct.A)(Vi({maxLookahead:1,occurrence:t,prodType:"Alternation",rule:n}),(e=>(0,Ct.A)(e,(e=>e[0]))));if(_o(l,!1)&&!i){const e=(0,Yn.A)(l,((e,t,n)=>((0,It.A)(t,(t=>{t&&(e[t.tokenTypeIdx]=n,(0,It.A)(t.categoryMatches,(t=>{e[t]=n})))})),e)),{});return r?function(t){var n;const r=this.LA(1),i=e[r.tokenTypeIdx];if(void 0!==t&&void 0!==i){const e=null===(n=t[i])||void 0===n?void 0:n.GATE;if(void 0!==e&&!1===e.call(this))return}return i}:function(){const t=this.LA(1);return e[t.tokenTypeIdx]}}return r?function(e){const t=new Lo,n=void 0===e?0:e.length;for(let i=0;i<n;i++){const n=null==e?void 0:e[i].GATE;t.set(i,void 0===n||n.call(this))}const r=Po.call(this,s,c,t,o);return"number"==typeof r?r:void 0}:function(){const e=Po.call(this,s,c,Oo,o);return"number"==typeof e?e:void 0}}buildLookaheadForOptional(e){const{prodOccurrence:t,rule:n,prodType:r,dynamicTokensEnabled:i}=e,s=this.dfas,o=this.logging,a=oo(n,r,t),c=this.atn.decisionMap[a].decision,l=(0,Ct.A)(Vi({maxLookahead:1,occurrence:t,prodType:r,rule:n}),(e=>(0,Ct.A)(e,(e=>e[0]))));if(_o(l)&&l[0][0]&&!i){const e=l[0],t=(0,Pn.A)(e);if(1===t.length&&(0,Nt.A)(t[0].categoryMatches)){const e=t[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===e}}{const e=(0,Yn.A)(t,((e,t)=>(void 0!==t&&(e[t.tokenTypeIdx]=!0,(0,It.A)(t.categoryMatches,(t=>{e[t]=!0}))),e)),{});return function(){const t=this.LA(1);return!0===e[t.tokenTypeIdx]}}}return function(){const e=Po.call(this,s,c,Oo,o);return"object"!=typeof e&&0===e}}}function _o(e,t=!0){const n=new Set;for(const r of e){const e=new Set;for(const i of r){if(void 0===i){if(t)break;return!1}const r=[i.tokenTypeIdx].concat(i.categoryMatches);for(const t of r)if(n.has(t)){if(!e.has(t))return!1}else n.add(t),e.add(t)}}return!0}function Po(e,t,n,r){const i=e[t](n);let s=i.start;if(void 0===s){s=jo(i,Ko(Vo(i.atnStartState))),i.start=s}return Mo.apply(this,[i,s,n,r])}function Mo(e,t,n,r){let i=t,s=1;const o=[];let a=this.LA(s++);for(;;){let t=(c=a,i.edges[c.tokenTypeIdx]);if(void 0===t&&(t=Do.apply(this,[e,i,a,s,n,r])),t===Io)return Fo(o,i,a);if(!0===t.isAcceptState)return t.prediction;i=t,o.push(a),a=this.LA(s++)}var c}function Do(e,t,n,r,i,s){const o=function(e,t,n){const r=new So,i=[];for(const o of e.elements){if(!1===n.is(o.alt))continue;if(7===o.state.type){i.push(o);continue}const e=o.state.transitions.length;for(let n=0;n<e;n++){const e=Go(o.state.transitions[n],t);void 0!==e&&r.add({state:e,alt:o.alt,stack:o.stack})}}let s;0===i.length&&1===r.size&&(s=r);if(void 0===s){s=new So;for(const e of r.elements)Ho(e,s)}if(i.length>0&&!function(e){for(const t of e.elements)if(7===t.state.type)return!0;return!1}(s))for(const o of i)s.add(o);return s}(t.configs,n,i);if(0===o.size)return Bo(e,t,n,Io),Io;let a=Ko(o);const c=function(e,t){let n;for(const r of e.elements)if(!0===t.is(r.alt))if(void 0===n)n=r.alt;else if(n!==r.alt)return;return n}(o,i);if(void 0!==c)a.isAcceptState=!0,a.prediction=c,a.configs.uniqueAlt=c;else if(function(e){if(function(e){for(const t of e.elements)if(7!==t.state.type)return!1;return!0}(e))return!0;const t=function(e){const t=new Map;for(const n of e){const e=No(n,!1);let r=t.get(e);void 0===r&&(r={},t.set(e,r)),r[n.alt]=!0}return t}(e.elements);return function(e){for(const t of Array.from(e.values()))if(Object.keys(t).length>1)return!0;return!1}(t)&&!function(e){for(const t of Array.from(e.values()))if(1===Object.keys(t).length)return!0;return!1}(t)}(o)){const t=(0,Co.A)(o.alts);a.isAcceptState=!0,a.prediction=t,a.configs.uniqueAlt=t,Uo.apply(this,[e,r,o.alts,s])}return a=Bo(e,t,n,a),a}function Uo(e,t,n,r){const i=[];for(let o=1;o<=t;o++)i.push(this.LA(o).tokenType);const s=e.atnStartState;r(function(e){const t=(0,Ct.A)(e.prefixPath,(e=>si(e))).join(", "),n=0===e.production.idx?"":e.production.idx;let r=`Ambiguous Alternatives Detected: <${e.ambiguityIndices.join(", ")}> in <${function(e){if(e instanceof sn)return"SUBRULE";if(e instanceof cn)return"OPTION";if(e instanceof fn)return"OR";if(e instanceof ln)return"AT_LEAST_ONE";if(e instanceof un)return"AT_LEAST_ONE_SEP";if(e instanceof hn)return"MANY_SEP";if(e instanceof dn)return"MANY";if(e instanceof pn)return"CONSUME";throw Error("non exhaustive match")}(e.production)}${n}> inside <${e.topLevelRule.name}> Rule,\n<${t}> may appears as a prefix path in all these alternatives.\n`;return r+="See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES\nFor Further details.",r}({topLevelRule:s.rule,ambiguityIndices:n,production:s.production,prefixPath:i}))}function Fo(e,t,n){const r=xi(t.configs.elements,(e=>e.state.transitions));return{actualToken:n,possibleTokenTypes:$o(r.filter((e=>e instanceof co)).map((e=>e.tokenType)),(e=>e.tokenTypeIdx)),tokenPath:e}}function Go(e,t){if(e instanceof co&&Ti(t,e.tokenType))return e.target}function Ko(e){return{configs:e,edges:{},isAcceptState:!1,prediction:-1}}function Bo(e,t,n,r){return r=jo(e,r),t.edges[n.tokenTypeIdx]=r,r}function jo(e,t){if(t===Io)return t;const n=t.configs.key,r=e.states[n];return void 0!==r?r:(t.configs.finalize(),e.states[n]=t,t)}function Vo(e){const t=new So,n=e.transitions.length;for(let r=0;r<n;r++){Ho({state:e.transitions[r].target,alt:r,stack:[]},t)}return t}function Ho(e,t){const n=e.state;if(7===n.type){if(e.stack.length>0){const n=[...e.stack];Ho({state:n.pop(),alt:e.alt,stack:n},t)}else t.add(e);return}n.epsilonOnlyTransitions||t.add(e);const r=n.transitions.length;for(let i=0;i<r;i++){const r=Wo(e,n.transitions[i]);void 0!==r&&Ho(r,t)}}function Wo(e,t){if(t instanceof lo)return{state:t.target,alt:e.alt,stack:e.stack};if(t instanceof uo){const n=[...e.stack,t.followState];return{state:t.target,alt:e.alt,stack:n}}}var zo,Yo,Xo,qo,Qo,Jo,Zo,ea,ta,na,ra,ia,sa,oa,aa,ca,la,ua,da,ha,fa,pa,ma,ga,ya,Aa,Ta,va,Ra,Ea,ka,xa,Ia,Sa,Na,Ca,$a,wa,La,Oa,ba,_a,Pa,Ma,Da,Ua,Fa,Ga,Ka,Ba,ja,Va,Ha,Wa,za,Ya,Xa,qa,Qa,Ja,Za,ec,tc,nc,rc,ic,sc,oc,ac,cc,lc,uc,dc,hc,fc,pc,mc,gc;!function(e){e.is=function(e){return"string"==typeof e}}(zo||(zo={})),function(e){e.is=function(e){return"string"==typeof e}}(Yo||(Yo={})),function(e){e.MIN_VALUE=-2147483648,e.MAX_VALUE=2147483647,e.is=function(t){return"number"==typeof t&&e.MIN_VALUE<=t&&t<=e.MAX_VALUE}}(Xo||(Xo={})),function(e){e.MIN_VALUE=0,e.MAX_VALUE=2147483647,e.is=function(t){return"number"==typeof t&&e.MIN_VALUE<=t&&t<=e.MAX_VALUE}}(qo||(qo={})),function(e){e.create=function(e,t){return e===Number.MAX_VALUE&&(e=qo.MAX_VALUE),t===Number.MAX_VALUE&&(t=qo.MAX_VALUE),{line:e,character:t}},e.is=function(e){let t=e;return Ac.objectLiteral(t)&&Ac.uinteger(t.line)&&Ac.uinteger(t.character)}}(Qo||(Qo={})),function(e){e.create=function(e,t,n,r){if(Ac.uinteger(e)&&Ac.uinteger(t)&&Ac.uinteger(n)&&Ac.uinteger(r))return{start:Qo.create(e,t),end:Qo.create(n,r)};if(Qo.is(e)&&Qo.is(t))return{start:e,end:t};throw new Error(`Range#create called with invalid arguments[${e}, ${t}, ${n}, ${r}]`)},e.is=function(e){let t=e;return Ac.objectLiteral(t)&&Qo.is(t.start)&&Qo.is(t.end)}}(Jo||(Jo={})),function(e){e.create=function(e,t){return{uri:e,range:t}},e.is=function(e){let t=e;return Ac.objectLiteral(t)&&Jo.is(t.range)&&(Ac.string(t.uri)||Ac.undefined(t.uri))}}(Zo||(Zo={})),function(e){e.create=function(e,t,n,r){return{targetUri:e,targetRange:t,targetSelectionRange:n,originSelectionRange:r}},e.is=function(e){let t=e;return Ac.objectLiteral(t)&&Jo.is(t.targetRange)&&Ac.string(t.targetUri)&&Jo.is(t.targetSelectionRange)&&(Jo.is(t.originSelectionRange)||Ac.undefined(t.originSelectionRange))}}(ea||(ea={})),function(e){e.create=function(e,t,n,r){return{red:e,green:t,blue:n,alpha:r}},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Ac.numberRange(t.red,0,1)&&Ac.numberRange(t.green,0,1)&&Ac.numberRange(t.blue,0,1)&&Ac.numberRange(t.alpha,0,1)}}(ta||(ta={})),function(e){e.create=function(e,t){return{range:e,color:t}},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Jo.is(t.range)&&ta.is(t.color)}}(na||(na={})),function(e){e.create=function(e,t,n){return{label:e,textEdit:t,additionalTextEdits:n}},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Ac.string(t.label)&&(Ac.undefined(t.textEdit)||ha.is(t))&&(Ac.undefined(t.additionalTextEdits)||Ac.typedArray(t.additionalTextEdits,ha.is))}}(ra||(ra={})),function(e){e.Comment="comment",e.Imports="imports",e.Region="region"}(ia||(ia={})),function(e){e.create=function(e,t,n,r,i,s){const o={startLine:e,endLine:t};return Ac.defined(n)&&(o.startCharacter=n),Ac.defined(r)&&(o.endCharacter=r),Ac.defined(i)&&(o.kind=i),Ac.defined(s)&&(o.collapsedText=s),o},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Ac.uinteger(t.startLine)&&Ac.uinteger(t.startLine)&&(Ac.undefined(t.startCharacter)||Ac.uinteger(t.startCharacter))&&(Ac.undefined(t.endCharacter)||Ac.uinteger(t.endCharacter))&&(Ac.undefined(t.kind)||Ac.string(t.kind))}}(sa||(sa={})),function(e){e.create=function(e,t){return{location:e,message:t}},e.is=function(e){let t=e;return Ac.defined(t)&&Zo.is(t.location)&&Ac.string(t.message)}}(oa||(oa={})),function(e){e.Error=1,e.Warning=2,e.Information=3,e.Hint=4}(aa||(aa={})),function(e){e.Unnecessary=1,e.Deprecated=2}(ca||(ca={})),function(e){e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Ac.string(t.href)}}(la||(la={})),function(e){e.create=function(e,t,n,r,i,s){let o={range:e,message:t};return Ac.defined(n)&&(o.severity=n),Ac.defined(r)&&(o.code=r),Ac.defined(i)&&(o.source=i),Ac.defined(s)&&(o.relatedInformation=s),o},e.is=function(e){var t;let n=e;return Ac.defined(n)&&Jo.is(n.range)&&Ac.string(n.message)&&(Ac.number(n.severity)||Ac.undefined(n.severity))&&(Ac.integer(n.code)||Ac.string(n.code)||Ac.undefined(n.code))&&(Ac.undefined(n.codeDescription)||Ac.string(null===(t=n.codeDescription)||void 0===t?void 0:t.href))&&(Ac.string(n.source)||Ac.undefined(n.source))&&(Ac.undefined(n.relatedInformation)||Ac.typedArray(n.relatedInformation,oa.is))}}(ua||(ua={})),function(e){e.create=function(e,t,...n){let r={title:e,command:t};return Ac.defined(n)&&n.length>0&&(r.arguments=n),r},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.string(t.title)&&Ac.string(t.command)}}(da||(da={})),function(e){e.replace=function(e,t){return{range:e,newText:t}},e.insert=function(e,t){return{range:{start:e,end:e},newText:t}},e.del=function(e){return{range:e,newText:""}},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Ac.string(t.newText)&&Jo.is(t.range)}}(ha||(ha={})),function(e){e.create=function(e,t,n){const r={label:e};return void 0!==t&&(r.needsConfirmation=t),void 0!==n&&(r.description=n),r},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Ac.string(t.label)&&(Ac.boolean(t.needsConfirmation)||void 0===t.needsConfirmation)&&(Ac.string(t.description)||void 0===t.description)}}(fa||(fa={})),function(e){e.is=function(e){const t=e;return Ac.string(t)}}(pa||(pa={})),function(e){e.replace=function(e,t,n){return{range:e,newText:t,annotationId:n}},e.insert=function(e,t,n){return{range:{start:e,end:e},newText:t,annotationId:n}},e.del=function(e,t){return{range:e,newText:"",annotationId:t}},e.is=function(e){const t=e;return ha.is(t)&&(fa.is(t.annotationId)||pa.is(t.annotationId))}}(ma||(ma={})),function(e){e.create=function(e,t){return{textDocument:e,edits:t}},e.is=function(e){let t=e;return Ac.defined(t)&&ka.is(t.textDocument)&&Array.isArray(t.edits)}}(ga||(ga={})),function(e){e.create=function(e,t,n){let r={kind:"create",uri:e};return void 0===t||void 0===t.overwrite&&void 0===t.ignoreIfExists||(r.options=t),void 0!==n&&(r.annotationId=n),r},e.is=function(e){let t=e;return t&&"create"===t.kind&&Ac.string(t.uri)&&(void 0===t.options||(void 0===t.options.overwrite||Ac.boolean(t.options.overwrite))&&(void 0===t.options.ignoreIfExists||Ac.boolean(t.options.ignoreIfExists)))&&(void 0===t.annotationId||pa.is(t.annotationId))}}(ya||(ya={})),function(e){e.create=function(e,t,n,r){let i={kind:"rename",oldUri:e,newUri:t};return void 0===n||void 0===n.overwrite&&void 0===n.ignoreIfExists||(i.options=n),void 0!==r&&(i.annotationId=r),i},e.is=function(e){let t=e;return t&&"rename"===t.kind&&Ac.string(t.oldUri)&&Ac.string(t.newUri)&&(void 0===t.options||(void 0===t.options.overwrite||Ac.boolean(t.options.overwrite))&&(void 0===t.options.ignoreIfExists||Ac.boolean(t.options.ignoreIfExists)))&&(void 0===t.annotationId||pa.is(t.annotationId))}}(Aa||(Aa={})),function(e){e.create=function(e,t,n){let r={kind:"delete",uri:e};return void 0===t||void 0===t.recursive&&void 0===t.ignoreIfNotExists||(r.options=t),void 0!==n&&(r.annotationId=n),r},e.is=function(e){let t=e;return t&&"delete"===t.kind&&Ac.string(t.uri)&&(void 0===t.options||(void 0===t.options.recursive||Ac.boolean(t.options.recursive))&&(void 0===t.options.ignoreIfNotExists||Ac.boolean(t.options.ignoreIfNotExists)))&&(void 0===t.annotationId||pa.is(t.annotationId))}}(Ta||(Ta={})),function(e){e.is=function(e){let t=e;return t&&(void 0!==t.changes||void 0!==t.documentChanges)&&(void 0===t.documentChanges||t.documentChanges.every((e=>Ac.string(e.kind)?ya.is(e)||Aa.is(e)||Ta.is(e):ga.is(e))))}}(va||(va={}));!function(e){e.create=function(e){return{uri:e}},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.string(t.uri)}}(Ra||(Ra={})),function(e){e.create=function(e,t){return{uri:e,version:t}},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.string(t.uri)&&Ac.integer(t.version)}}(Ea||(Ea={})),function(e){e.create=function(e,t){return{uri:e,version:t}},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.string(t.uri)&&(null===t.version||Ac.integer(t.version))}}(ka||(ka={})),function(e){e.create=function(e,t,n,r){return{uri:e,languageId:t,version:n,text:r}},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.string(t.uri)&&Ac.string(t.languageId)&&Ac.integer(t.version)&&Ac.string(t.text)}}(xa||(xa={})),function(e){e.PlainText="plaintext",e.Markdown="markdown",e.is=function(t){const n=t;return n===e.PlainText||n===e.Markdown}}(Ia||(Ia={})),function(e){e.is=function(e){const t=e;return Ac.objectLiteral(e)&&Ia.is(t.kind)&&Ac.string(t.value)}}(Sa||(Sa={})),function(e){e.Text=1,e.Method=2,e.Function=3,e.Constructor=4,e.Field=5,e.Variable=6,e.Class=7,e.Interface=8,e.Module=9,e.Property=10,e.Unit=11,e.Value=12,e.Enum=13,e.Keyword=14,e.Snippet=15,e.Color=16,e.File=17,e.Reference=18,e.Folder=19,e.EnumMember=20,e.Constant=21,e.Struct=22,e.Event=23,e.Operator=24,e.TypeParameter=25}(Na||(Na={})),function(e){e.PlainText=1,e.Snippet=2}(Ca||(Ca={})),function(e){e.Deprecated=1}($a||($a={})),function(e){e.create=function(e,t,n){return{newText:e,insert:t,replace:n}},e.is=function(e){const t=e;return t&&Ac.string(t.newText)&&Jo.is(t.insert)&&Jo.is(t.replace)}}(wa||(wa={})),function(e){e.asIs=1,e.adjustIndentation=2}(La||(La={})),function(e){e.is=function(e){const t=e;return t&&(Ac.string(t.detail)||void 0===t.detail)&&(Ac.string(t.description)||void 0===t.description)}}(Oa||(Oa={})),function(e){e.create=function(e){return{label:e}}}(ba||(ba={})),function(e){e.create=function(e,t){return{items:e||[],isIncomplete:!!t}}}(_a||(_a={})),function(e){e.fromPlainText=function(e){return e.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")},e.is=function(e){const t=e;return Ac.string(t)||Ac.objectLiteral(t)&&Ac.string(t.language)&&Ac.string(t.value)}}(Pa||(Pa={})),function(e){e.is=function(e){let t=e;return!!t&&Ac.objectLiteral(t)&&(Sa.is(t.contents)||Pa.is(t.contents)||Ac.typedArray(t.contents,Pa.is))&&(void 0===e.range||Jo.is(e.range))}}(Ma||(Ma={})),function(e){e.create=function(e,t){return t?{label:e,documentation:t}:{label:e}}}(Da||(Da={})),function(e){e.create=function(e,t,...n){let r={label:e};return Ac.defined(t)&&(r.documentation=t),Ac.defined(n)?r.parameters=n:r.parameters=[],r}}(Ua||(Ua={})),function(e){e.Text=1,e.Read=2,e.Write=3}(Fa||(Fa={})),function(e){e.create=function(e,t){let n={range:e};return Ac.number(t)&&(n.kind=t),n}}(Ga||(Ga={})),function(e){e.File=1,e.Module=2,e.Namespace=3,e.Package=4,e.Class=5,e.Method=6,e.Property=7,e.Field=8,e.Constructor=9,e.Enum=10,e.Interface=11,e.Function=12,e.Variable=13,e.Constant=14,e.String=15,e.Number=16,e.Boolean=17,e.Array=18,e.Object=19,e.Key=20,e.Null=21,e.EnumMember=22,e.Struct=23,e.Event=24,e.Operator=25,e.TypeParameter=26}(Ka||(Ka={})),function(e){e.Deprecated=1}(Ba||(Ba={})),function(e){e.create=function(e,t,n,r,i){let s={name:e,kind:t,location:{uri:r,range:n}};return i&&(s.containerName=i),s}}(ja||(ja={})),function(e){e.create=function(e,t,n,r){return void 0!==r?{name:e,kind:t,location:{uri:n,range:r}}:{name:e,kind:t,location:{uri:n}}}}(Va||(Va={})),function(e){e.create=function(e,t,n,r,i,s){let o={name:e,detail:t,kind:n,range:r,selectionRange:i};return void 0!==s&&(o.children=s),o},e.is=function(e){let t=e;return t&&Ac.string(t.name)&&Ac.number(t.kind)&&Jo.is(t.range)&&Jo.is(t.selectionRange)&&(void 0===t.detail||Ac.string(t.detail))&&(void 0===t.deprecated||Ac.boolean(t.deprecated))&&(void 0===t.children||Array.isArray(t.children))&&(void 0===t.tags||Array.isArray(t.tags))}}(Ha||(Ha={})),function(e){e.Empty="",e.QuickFix="quickfix",e.Refactor="refactor",e.RefactorExtract="refactor.extract",e.RefactorInline="refactor.inline",e.RefactorRewrite="refactor.rewrite",e.Source="source",e.SourceOrganizeImports="source.organizeImports",e.SourceFixAll="source.fixAll"}(Wa||(Wa={})),function(e){e.Invoked=1,e.Automatic=2}(za||(za={})),function(e){e.create=function(e,t,n){let r={diagnostics:e};return null!=t&&(r.only=t),null!=n&&(r.triggerKind=n),r},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.typedArray(t.diagnostics,ua.is)&&(void 0===t.only||Ac.typedArray(t.only,Ac.string))&&(void 0===t.triggerKind||t.triggerKind===za.Invoked||t.triggerKind===za.Automatic)}}(Ya||(Ya={})),function(e){e.create=function(e,t,n){let r={title:e},i=!0;return"string"==typeof t?(i=!1,r.kind=t):da.is(t)?r.command=t:r.edit=t,i&&void 0!==n&&(r.kind=n),r},e.is=function(e){let t=e;return t&&Ac.string(t.title)&&(void 0===t.diagnostics||Ac.typedArray(t.diagnostics,ua.is))&&(void 0===t.kind||Ac.string(t.kind))&&(void 0!==t.edit||void 0!==t.command)&&(void 0===t.command||da.is(t.command))&&(void 0===t.isPreferred||Ac.boolean(t.isPreferred))&&(void 0===t.edit||va.is(t.edit))}}(Xa||(Xa={})),function(e){e.create=function(e,t){let n={range:e};return Ac.defined(t)&&(n.data=t),n},e.is=function(e){let t=e;return Ac.defined(t)&&Jo.is(t.range)&&(Ac.undefined(t.command)||da.is(t.command))}}(qa||(qa={})),function(e){e.create=function(e,t){return{tabSize:e,insertSpaces:t}},e.is=function(e){let t=e;return Ac.defined(t)&&Ac.uinteger(t.tabSize)&&Ac.boolean(t.insertSpaces)}}(Qa||(Qa={})),function(e){e.create=function(e,t,n){return{range:e,target:t,data:n}},e.is=function(e){let t=e;return Ac.defined(t)&&Jo.is(t.range)&&(Ac.undefined(t.target)||Ac.string(t.target))}}(Ja||(Ja={})),function(e){e.create=function(e,t){return{range:e,parent:t}},e.is=function(t){let n=t;return Ac.objectLiteral(n)&&Jo.is(n.range)&&(void 0===n.parent||e.is(n.parent))}}(Za||(Za={})),function(e){e.namespace="namespace",e.type="type",e.class="class",e.enum="enum",e.interface="interface",e.struct="struct",e.typeParameter="typeParameter",e.parameter="parameter",e.variable="variable",e.property="property",e.enumMember="enumMember",e.event="event",e.function="function",e.method="method",e.macro="macro",e.keyword="keyword",e.modifier="modifier",e.comment="comment",e.string="string",e.number="number",e.regexp="regexp",e.operator="operator",e.decorator="decorator"}(ec||(ec={})),function(e){e.declaration="declaration",e.definition="definition",e.readonly="readonly",e.static="static",e.deprecated="deprecated",e.abstract="abstract",e.async="async",e.modification="modification",e.documentation="documentation",e.defaultLibrary="defaultLibrary"}(tc||(tc={})),function(e){e.is=function(e){const t=e;return Ac.objectLiteral(t)&&(void 0===t.resultId||"string"==typeof t.resultId)&&Array.isArray(t.data)&&(0===t.data.length||"number"==typeof t.data[0])}}(nc||(nc={})),function(e){e.create=function(e,t){return{range:e,text:t}},e.is=function(e){const t=e;return null!=t&&Jo.is(t.range)&&Ac.string(t.text)}}(rc||(rc={})),function(e){e.create=function(e,t,n){return{range:e,variableName:t,caseSensitiveLookup:n}},e.is=function(e){const t=e;return null!=t&&Jo.is(t.range)&&Ac.boolean(t.caseSensitiveLookup)&&(Ac.string(t.variableName)||void 0===t.variableName)}}(ic||(ic={})),function(e){e.create=function(e,t){return{range:e,expression:t}},e.is=function(e){const t=e;return null!=t&&Jo.is(t.range)&&(Ac.string(t.expression)||void 0===t.expression)}}(sc||(sc={})),function(e){e.create=function(e,t){return{frameId:e,stoppedLocation:t}},e.is=function(e){const t=e;return Ac.defined(t)&&Jo.is(e.stoppedLocation)}}(oc||(oc={})),function(e){e.Type=1,e.Parameter=2,e.is=function(e){return 1===e||2===e}}(ac||(ac={})),function(e){e.create=function(e){return{value:e}},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&(void 0===t.tooltip||Ac.string(t.tooltip)||Sa.is(t.tooltip))&&(void 0===t.location||Zo.is(t.location))&&(void 0===t.command||da.is(t.command))}}(cc||(cc={})),function(e){e.create=function(e,t,n){const r={position:e,label:t};return void 0!==n&&(r.kind=n),r},e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Qo.is(t.position)&&(Ac.string(t.label)||Ac.typedArray(t.label,cc.is))&&(void 0===t.kind||ac.is(t.kind))&&void 0===t.textEdits||Ac.typedArray(t.textEdits,ha.is)&&(void 0===t.tooltip||Ac.string(t.tooltip)||Sa.is(t.tooltip))&&(void 0===t.paddingLeft||Ac.boolean(t.paddingLeft))&&(void 0===t.paddingRight||Ac.boolean(t.paddingRight))}}(lc||(lc={})),function(e){e.createSnippet=function(e){return{kind:"snippet",value:e}}}(uc||(uc={})),function(e){e.create=function(e,t,n,r){return{insertText:e,filterText:t,range:n,command:r}}}(dc||(dc={})),function(e){e.create=function(e){return{items:e}}}(hc||(hc={})),function(e){e.Invoked=0,e.Automatic=1}(fc||(fc={})),function(e){e.create=function(e,t){return{range:e,text:t}}}(pc||(pc={})),function(e){e.create=function(e,t){return{triggerKind:e,selectedCompletionInfo:t}}}(mc||(mc={})),function(e){e.is=function(e){const t=e;return Ac.objectLiteral(t)&&Yo.is(t.uri)&&Ac.string(t.name)}}(gc||(gc={}));var yc,Ac;!function(e){function t(e,n){if(e.length<=1)return e;const r=e.length/2|0,i=e.slice(0,r),s=e.slice(r);t(i,n),t(s,n);let o=0,a=0,c=0;for(;o<i.length&&a<s.length;){let t=n(i[o],s[a]);e[c++]=t<=0?i[o++]:s[a++]}for(;o<i.length;)e[c++]=i[o++];for(;a<s.length;)e[c++]=s[a++];return e}e.create=function(e,t,n,r){return new Tc(e,t,n,r)},e.is=function(e){let t=e;return!!(Ac.defined(t)&&Ac.string(t.uri)&&(Ac.undefined(t.languageId)||Ac.string(t.languageId))&&Ac.uinteger(t.lineCount)&&Ac.func(t.getText)&&Ac.func(t.positionAt)&&Ac.func(t.offsetAt))},e.applyEdits=function(e,n){let r=e.getText(),i=t(n,((e,t)=>{let n=e.range.start.line-t.range.start.line;return 0===n?e.range.start.character-t.range.start.character:n})),s=r.length;for(let t=i.length-1;t>=0;t--){let n=i[t],o=e.offsetAt(n.range.start),a=e.offsetAt(n.range.end);if(!(a<=s))throw new Error("Overlapping edit");r=r.substring(0,o)+n.newText+r.substring(a,r.length),s=o}return r}}(yc||(yc={}));class Tc{constructor(e,t,n,r){this._uri=e,this._languageId=t,this._version=n,this._content=r,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){let t=this.offsetAt(e.start),n=this.offsetAt(e.end);return this._content.substring(t,n)}return this._content}update(e,t){this._content=e.text,this._version=t,this._lineOffsets=void 0}getLineOffsets(){if(void 0===this._lineOffsets){let e=[],t=this._content,n=!0;for(let r=0;r<t.length;r++){n&&(e.push(r),n=!1);let i=t.charAt(r);n="\r"===i||"\n"===i,"\r"===i&&r+1<t.length&&"\n"===t.charAt(r+1)&&r++}n&&t.length>0&&e.push(t.length),this._lineOffsets=e}return this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);let t=this.getLineOffsets(),n=0,r=t.length;if(0===r)return Qo.create(0,e);for(;n<r;){let i=Math.floor((n+r)/2);t[i]>e?r=i:n=i+1}let i=n-1;return Qo.create(i,e-t[i])}offsetAt(e){let t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;let n=t[e.line],r=e.line+1<t.length?t[e.line+1]:this._content.length;return Math.max(Math.min(n+e.character,r),n)}get lineCount(){return this.getLineOffsets().length}}!function(e){const t=Object.prototype.toString;e.defined=function(e){return void 0!==e},e.undefined=function(e){return void 0===e},e.boolean=function(e){return!0===e||!1===e},e.string=function(e){return"[object String]"===t.call(e)},e.number=function(e){return"[object Number]"===t.call(e)},e.numberRange=function(e,n,r){return"[object Number]"===t.call(e)&&n<=e&&e<=r},e.integer=function(e){return"[object Number]"===t.call(e)&&-2147483648<=e&&e<=2147483647},e.uinteger=function(e){return"[object Number]"===t.call(e)&&0<=e&&e<=2147483647},e.func=function(e){return"[object Function]"===t.call(e)},e.objectLiteral=function(e){return null!==e&&"object"==typeof e},e.typedArray=function(e,t){return Array.isArray(e)&&e.every(t)}}(Ac||(Ac={}));class vc{constructor(){this.nodeStack=[]}get current(){return this.nodeStack[this.nodeStack.length-1]}buildRootNode(e){return this.rootNode=new Ic(e),this.rootNode.root=this.rootNode,this.nodeStack=[this.rootNode],this.rootNode}buildCompositeNode(e){const t=new kc;return t.grammarSource=e,t.root=this.rootNode,this.current.content.push(t),this.nodeStack.push(t),t}buildLeafNode(e,t){const n=new Ec(e.startOffset,e.image.length,v(e),e.tokenType,!1);return n.grammarSource=t,n.root=this.rootNode,this.current.content.push(n),n}removeNode(e){const t=e.container;if(t){const n=t.content.indexOf(e);n>=0&&t.content.splice(n,1)}}construct(e){const t=this.current;"string"==typeof e.$type&&(this.current.astNode=e),e.$cstNode=t;const n=this.nodeStack.pop();0===(null==n?void 0:n.content.length)&&this.removeNode(n)}addHiddenTokens(e){for(const t of e){const e=new Ec(t.startOffset,t.image.length,v(t),t.tokenType,!0);e.root=this.rootNode,this.addHiddenToken(this.rootNode,e)}}addHiddenToken(e,t){const{offset:n,end:r}=t;for(let i=0;i<e.content.length;i++){const s=e.content[i],{offset:o,end:c}=s;if(a(s)&&n>o&&r<c)return void this.addHiddenToken(s,t);if(r<=o)return void e.content.splice(i,0,t)}e.content.push(t)}}class Rc{get parent(){return this.container}get feature(){return this.grammarSource}get hidden(){return!1}get astNode(){var e,t;const n="string"==typeof(null===(e=this._astNode)||void 0===e?void 0:e.$type)?this._astNode:null===(t=this.container)||void 0===t?void 0:t.astNode;if(!n)throw new Error("This node has no associated AST element");return n}set astNode(e){this._astNode=e}get element(){return this.astNode}get text(){return this.root.fullText.substring(this.offset,this.end)}}class Ec extends Rc{get offset(){return this._offset}get length(){return this._length}get end(){return this._offset+this._length}get hidden(){return this._hidden}get tokenType(){return this._tokenType}get range(){return this._range}constructor(e,t,n,r,i=!1){super(),this._hidden=i,this._offset=e,this._tokenType=r,this._length=t,this._range=n}}class kc extends Rc{constructor(){super(...arguments),this.content=new xc(this)}get children(){return this.content}get offset(){var e,t;return null!==(t=null===(e=this.firstNonHiddenNode)||void 0===e?void 0:e.offset)&&void 0!==t?t:0}get length(){return this.end-this.offset}get end(){var e,t;return null!==(t=null===(e=this.lastNonHiddenNode)||void 0===e?void 0:e.end)&&void 0!==t?t:0}get range(){const e=this.firstNonHiddenNode,t=this.lastNonHiddenNode;if(e&&t){if(void 0===this._rangeCache){const{range:n}=e,{range:r}=t;this._rangeCache={start:n.start,end:r.end.line<n.start.line?n.start:r.end}}return this._rangeCache}return{start:Qo.create(0,0),end:Qo.create(0,0)}}get firstNonHiddenNode(){for(const e of this.content)if(!e.hidden)return e;return this.content[0]}get lastNonHiddenNode(){for(let e=this.content.length-1;e>=0;e--){const t=this.content[e];if(!t.hidden)return t}return this.content[this.content.length-1]}}class xc extends Array{constructor(e){super(),this.parent=e,Object.setPrototypeOf(this,xc.prototype)}push(...e){return this.addParents(e),super.push(...e)}unshift(...e){return this.addParents(e),super.unshift(...e)}splice(e,t,...n){return this.addParents(n),super.splice(e,t,...n)}addParents(e){for(const t of e)t.container=this.parent}}class Ic extends kc{get text(){return this._text.substring(this.offset,this.end)}get fullText(){return this._text}constructor(e){super(),this._text="",this._text=null!=e?e:""}}const Sc=Symbol("Datatype");function Nc(e){return e.$type===Sc}const Cc=e=>e.endsWith("\u200b")?e:e+"\u200b";class $c{constructor(e){this._unorderedGroups=new Map,this.lexer=e.parser.Lexer;const t=this.lexer.definition;this.wrapper=new Pc(t,Object.assign(Object.assign({},e.parser.ParserConfig),{errorMessageProvider:e.parser.ParserErrorMessageProvider}))}alternatives(e,t){this.wrapper.wrapOr(e,t)}optional(e,t){this.wrapper.wrapOption(e,t)}many(e,t){this.wrapper.wrapMany(e,t)}atLeastOne(e,t){this.wrapper.wrapAtLeastOne(e,t)}isRecording(){return this.wrapper.IS_RECORDING}get unorderedGroups(){return this._unorderedGroups}getRuleStack(){return this.wrapper.RULE_STACK}finalize(){this.wrapper.wrapSelfAnalysis()}}class wc extends $c{get current(){return this.stack[this.stack.length-1]}constructor(e){super(e),this.nodeBuilder=new vc,this.stack=[],this.assignmentMap=new Map,this.linker=e.references.Linker,this.converter=e.parser.ValueConverter,this.astReflection=e.shared.AstReflection}rule(e,t){const n=e.fragment?void 0:gt(e)?Sc:Tt(e),r=this.wrapper.DEFINE_RULE(Cc(e.name),this.startImplementation(n,t).bind(this));return e.entry&&(this.mainRule=r),r}parse(e){this.nodeBuilder.buildRootNode(e);const t=this.lexer.tokenize(e);this.wrapper.input=t.tokens;const n=this.mainRule.call(this.wrapper,{});return this.nodeBuilder.addHiddenTokens(t.hidden),this.unorderedGroups.clear(),{value:n,lexerErrors:t.errors,parserErrors:this.wrapper.errors}}startImplementation(e,t){return n=>{if(!this.isRecording()){const t={$type:e};this.stack.push(t),e===Sc&&(t.value="")}let r;try{r=t(n)}catch(i){r=void 0}return this.isRecording()||void 0!==r||(r=this.construct()),r}}consume(e,t,n){const r=this.wrapper.wrapConsume(e,t);if(!this.isRecording()&&this.isValidToken(r)){const e=this.nodeBuilder.buildLeafNode(r,n),{assignment:t,isCrossRef:i}=this.getAssignment(n),s=this.current;if(t){const s=Ae(n)?r.image:this.converter.convert(r.image,e);this.assign(t.operator,t.feature,s,e,i)}else if(Nc(s)){let t=r.image;Ae(n)||(t=this.converter.convert(t,e).toString()),s.value+=t}}}isValidToken(e){return!e.isInsertedInRecovery&&!isNaN(e.startOffset)&&"number"==typeof e.endOffset&&!isNaN(e.endOffset)}subrule(e,t,n,r){let i;this.isRecording()||(i=this.nodeBuilder.buildCompositeNode(n));const s=this.wrapper.wrapSubrule(e,t,r);!this.isRecording()&&i&&i.length>0&&this.performSubruleAssignment(s,n,i)}performSubruleAssignment(e,t,n){const{assignment:r,isCrossRef:i}=this.getAssignment(t);if(r)this.assign(r.operator,r.feature,e,n,i);else if(!r){const t=this.current;if(Nc(t))t.value+=e.toString();else if("object"==typeof e&&e){const n=e.$type,r=this.assignWithoutOverride(e,t);n&&(r.$type=n);const i=r;this.stack.pop(),this.stack.push(i)}}}action(e,t){if(!this.isRecording()){let n=this.current;if(!n.$cstNode&&t.feature&&t.operator){n=this.construct(!1);const e=n.$cstNode.feature;this.nodeBuilder.buildCompositeNode(e)}const r={$type:e};this.stack.pop(),this.stack.push(r),t.feature&&t.operator&&this.assign(t.operator,t.feature,n,n.$cstNode,!1)}}construct(e=!0){if(this.isRecording())return;const t=this.current;return be(t),this.nodeBuilder.construct(t),e&&this.stack.pop(),Nc(t)?this.converter.convert(t.value,t.$cstNode):(function(e,t){const n=e.getTypeMetaData(t.$type),r=t;for(const i of n.properties)void 0!==i.defaultValue&&void 0===r[i.name]&&(r[i.name]=Ke(i.defaultValue))}(this.astReflection,t),t)}getAssignment(e){if(!this.assignmentMap.has(e)){const t=_e(e,ue);this.assignmentMap.set(e,{assignment:t,isCrossRef:!!t&&fe(t.terminal)})}return this.assignmentMap.get(e)}assign(e,t,n,r,i){const s=this.current;let o;switch(o=i&&"string"==typeof n?this.linker.buildReference(s,t,r,n):n,e){case"=":s[t]=o;break;case"?=":s[t]=!0;break;case"+=":Array.isArray(s[t])||(s[t]=[]),s[t].push(o)}}assignWithoutOverride(e,t){for(const[n,r]of Object.entries(t)){const t=e[n];void 0===t?e[n]=r:Array.isArray(t)&&Array.isArray(r)&&(r.push(...t),e[n]=r)}return e}get definitionErrors(){return this.wrapper.definitionErrors}}class Lc{buildMismatchTokenMessage(e){return vi.buildMismatchTokenMessage(e)}buildNotAllInputParsedMessage(e){return vi.buildNotAllInputParsedMessage(e)}buildNoViableAltMessage(e){return vi.buildNoViableAltMessage(e)}buildEarlyExitMessage(e){return vi.buildEarlyExitMessage(e)}}class Oc extends Lc{buildMismatchTokenMessage({expected:e,actual:t}){return`Expecting ${e.LABEL?"`"+e.LABEL+"`":e.name.endsWith(":KW")?`keyword '${e.name.substring(0,e.name.length-3)}'`:`token of type '${e.name}'`} but found \`${t.image}\`.`}buildNotAllInputParsedMessage({firstRedundant:e}){return`Expecting end of file but found \`${e.image}\`.`}}class bc extends $c{constructor(){super(...arguments),this.tokens=[],this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}action(){}construct(){}parse(e){this.resetState();const t=this.lexer.tokenize(e);return this.tokens=t.tokens,this.wrapper.input=[...this.tokens],this.mainRule.call(this.wrapper,{}),this.unorderedGroups.clear(),{tokens:this.tokens,elementStack:[...this.lastElementStack],tokenIndex:this.nextTokenIndex}}rule(e,t){const n=this.wrapper.DEFINE_RULE(Cc(e.name),this.startImplementation(t).bind(this));return e.entry&&(this.mainRule=n),n}resetState(){this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}startImplementation(e){return t=>{const n=this.keepStackSize();try{e(t)}finally{this.resetStackSize(n)}}}removeUnexpectedElements(){this.elementStack.splice(this.stackSize)}keepStackSize(){const e=this.elementStack.length;return this.stackSize=e,e}resetStackSize(e){this.removeUnexpectedElements(),this.stackSize=e}consume(e,t,n){this.wrapper.wrapConsume(e,t),this.isRecording()||(this.lastElementStack=[...this.elementStack,n],this.nextTokenIndex=this.currIdx+1)}subrule(e,t,n,r){this.before(n),this.wrapper.wrapSubrule(e,t,r),this.after(n)}before(e){this.isRecording()||this.elementStack.push(e)}after(e){if(!this.isRecording()){const t=this.elementStack.lastIndexOf(e);t>=0&&this.elementStack.splice(t)}}get currIdx(){return this.wrapper.currIdx}}const _c={recoveryEnabled:!0,nodeLocationTracking:"full",skipValidations:!0,errorMessageProvider:new Oc};class Pc extends so{constructor(e,t){const n=t&&"maxLookahead"in t;super(e,Object.assign(Object.assign(Object.assign({},_c),{lookaheadStrategy:n?new Os({maxLookahead:t.maxLookahead}):new bo}),t))}get IS_RECORDING(){return this.RECORDING_PHASE}DEFINE_RULE(e,t){return this.RULE(e,t)}wrapSelfAnalysis(){this.performSelfAnalysis()}wrapConsume(e,t){return this.consume(e,t)}wrapSubrule(e,t,n){return this.subrule(e,t,{ARGS:[n]})}wrapOr(e,t){this.or(e,t)}wrapOption(e,t){this.option(e,t)}wrapMany(e,t){this.many(e,t)}wrapAtLeastOne(e,t){this.atLeastOne(e,t)}}function Mc(e,t,n){return function(e,t){const n=lt(t,!1),r=m(t.rules).filter(X).filter((e=>n.has(e)));for(const i of r){const t=Object.assign(Object.assign({},e),{consume:1,optional:1,subrule:1,many:1,or:1});t.rules.set(i.name,e.parser.rule(i,Dc(t,i.definition)))}}({parser:t,tokens:n,rules:new Map,ruleNames:new Map},e),t}function Dc(e,t,n=!1){let r;if(Ae(t))r=function(e,t){const n=e.consume++,r=e.tokens[t.value];if(!r)throw new Error("Could not find token for keyword: "+t.value);return()=>e.parser.consume(n,r,t)}(e,t);else if(oe(t))r=function(e,t){const n=Tt(t);return()=>e.parser.action(n,t)}(e,t);else if(ue(t))r=Dc(e,t.terminal);else if(fe(t))r=Gc(e,t);else if(Ee(t))r=function(e,t){const n=t.rule.ref;if(X(n)){const r=e.subrule++,i=t.arguments.length>0?function(e,t){const n=t.map((e=>Uc(e.value)));return t=>{const r={};for(let i=0;i<n.length;i++){const s=e.parameters[i],o=n[i];r[s.name]=o(t)}return r}}(n,t.arguments):()=>({});return s=>e.parser.subrule(r,Bc(e,n),t,i(s))}if(te(n)){const r=e.consume++,i=jc(e,n.name);return()=>e.parser.consume(r,i,t)}if(!n)throw new S(t.$cstNode,`Undefined rule type: ${t.$type}`);N()}(e,t);else if(ce(t))r=function(e,t){if(1===t.elements.length)return Dc(e,t.elements[0]);{const n=[];for(const i of t.elements){const t={ALT:Dc(e,i,!0)},r=Fc(i);r&&(t.GATE=Uc(r)),n.push(t)}const r=e.or++;return t=>e.parser.alternatives(r,n.map((e=>{const n={ALT:()=>e.ALT(t)},r=e.GATE;return r&&(n.GATE=()=>r(t)),n})))}}(e,t);else if(Ce(t))r=function(e,t){if(1===t.elements.length)return Dc(e,t.elements[0]);const n=[];for(const a of t.elements){const t={ALT:Dc(e,a,!0)},r=Fc(a);r&&(t.GATE=Uc(r)),n.push(t)}const r=e.or++,i=(e,t)=>`uGroup_${e}_${t.getRuleStack().join("-")}`,s=t=>e.parser.alternatives(r,n.map(((n,s)=>{const o={ALT:()=>!0},a=e.parser;o.ALT=()=>{if(n.ALT(t),!a.isRecording()){const e=i(r,a);a.unorderedGroups.get(e)||a.unorderedGroups.set(e,[]);const t=a.unorderedGroups.get(e);void 0===(null==t?void 0:t[s])&&(t[s]=!0)}};const c=n.GATE;return o.GATE=c?()=>c(t):()=>{const e=a.unorderedGroups.get(i(r,a));return!(null==e?void 0:e[s])},o}))),o=Kc(e,Fc(t),s,"*");return t=>{o(t),e.parser.isRecording()||e.parser.unorderedGroups.delete(i(r,e.parser))}}(e,t);else if(ge(t))r=function(e,t){const n=t.elements.map((t=>Dc(e,t)));return e=>n.forEach((t=>t(e)))}(e,t);else{if(i=t,!Oe.isInstance(i,pe))throw new S(t.$cstNode,`Unexpected element type: ${t.$type}`);{const n=e.consume++;r=()=>e.parser.consume(n,yi,t)}}var i;return Kc(e,n?void 0:Fc(t),r,t.cardinality)}function Uc(e){if(t=e,Oe.isInstance(t,U)){const t=Uc(e.left),n=Uc(e.right);return e=>t(e)||n(e)}if(function(e){return Oe.isInstance(e,D)}(e)){const t=Uc(e.left),n=Uc(e.right);return e=>t(e)&&n(e)}if(function(e){return Oe.isInstance(e,V)}(e)){const t=Uc(e.value);return e=>!t(e)}if(function(e){return Oe.isInstance(e,z)}(e)){const t=e.parameter.ref.name;return e=>void 0!==e&&!0===e[t]}if(function(e){return Oe.isInstance(e,M)}(e)){const t=Boolean(e.true);return()=>t}var t;N()}function Fc(e){if(ge(e))return e.guardCondition}function Gc(e,t,n=t.terminal){if(n){if(Ee(n)&&X(n.rule.ref)){const r=e.subrule++;return i=>e.parser.subrule(r,Bc(e,n.rule.ref),t,i)}if(Ee(n)&&te(n.rule.ref)){const r=e.consume++,i=jc(e,n.rule.ref.name);return()=>e.parser.consume(r,i,t)}if(Ae(n)){const r=e.consume++,i=jc(e,n.value);return()=>e.parser.consume(r,i,t)}throw new Error("Could not build cross reference parser")}{if(!t.type.ref)throw new Error("Could not resolve reference to type: "+t.type.$refText);const n=pt(t.type.ref),r=null==n?void 0:n.terminal;if(!r)throw new Error("Could not find name assignment for type: "+Tt(t.type.ref));return Gc(e,t,r)}}function Kc(e,t,n,r){const i=t&&Uc(t);if(!r){if(i){const t=e.or++;return r=>e.parser.alternatives(t,[{ALT:()=>n(r),GATE:()=>i(r)},{ALT:ro(),GATE:()=>!i(r)}])}return n}if("*"===r){const t=e.many++;return r=>e.parser.many(t,{DEF:()=>n(r),GATE:i?()=>i(r):void 0})}if("+"===r){const t=e.many++;if(i){const r=e.or++;return s=>e.parser.alternatives(r,[{ALT:()=>e.parser.atLeastOne(t,{DEF:()=>n(s)}),GATE:()=>i(s)},{ALT:ro(),GATE:()=>!i(s)}])}return r=>e.parser.atLeastOne(t,{DEF:()=>n(r)})}if("?"===r){const t=e.optional++;return r=>e.parser.optional(t,{DEF:()=>n(r),GATE:i?()=>i(r):void 0})}N()}function Bc(e,t){const n=function(e,t){if(X(t))return t.name;if(e.ruleNames.has(t))return e.ruleNames.get(t);{let n=t,r=n.$container,i=t.$type;for(;!X(r);){if(ge(r)||ce(r)||Ce(r)){i=r.elements.indexOf(n).toString()+":"+i}n=r,r=r.$container}return i=r.name+":"+i,e.ruleNames.set(t,i),i}}(e,t),r=e.rules.get(n);if(!r)throw new Error(`Rule "${n}" not found."`);return r}function jc(e,t){const n=e.tokens[t];if(!n)throw new Error(`Token "${t}" not found."`);return n}function Vc(e){const t=function(e){const t=e.Grammar,n=e.parser.Lexer,r=new wc(e);return Mc(t,r,n.definition)}(e);return t.finalize(),t}class Hc{buildTokens(e,t){const n=m(lt(e,!1)),r=this.buildTerminalTokens(n),i=this.buildKeywordTokens(n,r,t);return r.forEach((e=>{const t=e.PATTERN;"object"==typeof t&&t&&"test"in t&&ot(t)?i.unshift(e):i.push(e)})),i}buildTerminalTokens(e){return e.filter(te).filter((e=>!e.fragment)).map((e=>this.buildTerminalToken(e))).toArray()}buildTerminalToken(e){const t=vt(e),n=this.requiresCustomPattern(t)?this.regexPatternFunction(t):t,r={name:e.name,PATTERN:n,LINE_BREAKS:!0};return e.hidden&&(r.GROUP=ot(t)?ii.SKIPPED:"hidden"),r}requiresCustomPattern(e){return!!e.flags.includes("u")||!(!e.source.includes("?<=")&&!e.source.includes("?<!"))}regexPatternFunction(e){const t=new RegExp(e,e.flags+"y");return(e,n)=>{t.lastIndex=n;return t.exec(e)}}buildKeywordTokens(e,t,n){return e.filter(X).flatMap((e=>De(e).filter(Ae))).distinct((e=>e.value)).toArray().sort(((e,t)=>t.value.length-e.value.length)).map((e=>this.buildKeywordToken(e,t,Boolean(null==n?void 0:n.caseInsensitive))))}buildKeywordToken(e,t,n){return{name:e.value,PATTERN:this.buildKeywordPattern(e,n),LONGER_ALT:this.findLongerAlt(e,t)}}buildKeywordPattern(e,t){return t?new RegExp(function(e){return Array.prototype.map.call(e,(e=>/\w/.test(e)?`[${e.toLowerCase()}${e.toUpperCase()}]`:at(e))).join("")}(e.value)):e.value}findLongerAlt(e,t){return t.reduce(((t,n)=>{const r=null==n?void 0:n.PATTERN;return(null==r?void 0:r.source)&&ct("^"+r.source+"$",e.value)&&t.push(n),t}),[])}}class Wc{convert(e,t){let n=t.grammarSource;if(fe(n)&&(n=function(e){if(e.terminal)return e.terminal;if(e.type.ref){const t=pt(e.type.ref);return null==t?void 0:t.terminal}}(n)),Ee(n)){const r=n.rule.ref;if(!r)throw new Error("This cst node was not parsed by a rule.");return this.runConverter(r,e,t)}return e}runConverter(e,t,n){var r;switch(e.name.toUpperCase()){case"INT":return zc.convertInt(t);case"STRING":return zc.convertString(t);case"ID":return zc.convertID(t)}switch(null===(r=function(e){var t,n,r;return te(e)?null!==(n=null===(t=e.type)||void 0===t?void 0:t.name)&&void 0!==n?n:"string":gt(e)?e.name:null!==(r=At(e))&&void 0!==r?r:e.name}(e))||void 0===r?void 0:r.toLowerCase()){case"number":return zc.convertNumber(t);case"boolean":return zc.convertBoolean(t);case"bigint":return zc.convertBigint(t);case"date":return zc.convertDate(t);default:return t}}}var zc;!function(e){function t(e){switch(e){case"b":return"\b";case"f":return"\f";case"n":return"\n";case"r":return"\r";case"t":return"\t";case"v":return"\v";case"0":return"\0";default:return e}}e.convertString=function(e){let n="";for(let r=1;r<e.length-1;r++){const i=e.charAt(r);if("\\"===i){n+=t(e.charAt(++r))}else n+=i}return n},e.convertID=function(e){return"^"===e.charAt(0)?e.substring(1):e},e.convertInt=function(e){return parseInt(e)},e.convertBigint=function(e){return BigInt(e)},e.convertDate=function(e){return new Date(e)},e.convertNumber=function(e){return Number(e)},e.convertBoolean=function(e){return"true"===e.toLowerCase()}}(zc||(zc={}));var Yc=n(59850);let Xc=0,qc=10;const Qc=Symbol("OperationCancelled");function Jc(e){return e===Qc}async function Zc(e){if(e===Yc.XO.None)return;const t=Date.now();if(t-Xc>=qc&&(Xc=t,await new Promise((e=>{"undefined"==typeof setImmediate?setTimeout(e,0):setImmediate(e)}))),e.isCancellationRequested)throw Qc}class el{constructor(){this.promise=new Promise(((e,t)=>{this.resolve=t=>(e(t),this),this.reject=e=>(t(e),this)}))}}class tl{constructor(e,t,n,r){this._uri=e,this._languageId=t,this._version=n,this._content=r,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){const t=this.offsetAt(e.start),n=this.offsetAt(e.end);return this._content.substring(t,n)}return this._content}update(e,t){for(const n of e)if(tl.isIncremental(n)){const e=al(n.range),t=this.offsetAt(e.start),r=this.offsetAt(e.end);this._content=this._content.substring(0,t)+n.text+this._content.substring(r,this._content.length);const i=Math.max(e.start.line,0),s=Math.max(e.end.line,0);let o=this._lineOffsets;const a=sl(n.text,!1,t);if(s-i===a.length)for(let n=0,l=a.length;n<l;n++)o[n+i+1]=a[n];else a.length<1e4?o.splice(i+1,s-i,...a):this._lineOffsets=o=o.slice(0,i+1).concat(a,o.slice(s+1));const c=n.text.length-(r-t);if(0!==c)for(let n=i+1+a.length,l=o.length;n<l;n++)o[n]=o[n]+c}else{if(!tl.isFull(n))throw new Error("Unknown change event received");this._content=n.text,this._lineOffsets=void 0}this._version=t}getLineOffsets(){return void 0===this._lineOffsets&&(this._lineOffsets=sl(this._content,!0)),this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);const t=this.getLineOffsets();let n=0,r=t.length;if(0===r)return{line:0,character:e};for(;n<r;){const i=Math.floor((n+r)/2);t[i]>e?r=i:n=i+1}const i=n-1;return{line:i,character:(e=this.ensureBeforeEOL(e,t[i]))-t[i]}}offsetAt(e){const t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;const n=t[e.line];if(e.character<=0)return n;const r=e.line+1<t.length?t[e.line+1]:this._content.length,i=Math.min(n+e.character,r);return this.ensureBeforeEOL(i,n)}ensureBeforeEOL(e,t){for(;e>t&&ol(this._content.charCodeAt(e-1));)e--;return e}get lineCount(){return this.getLineOffsets().length}static isIncremental(e){const t=e;return null!=t&&"string"==typeof t.text&&void 0!==t.range&&(void 0===t.rangeLength||"number"==typeof t.rangeLength)}static isFull(e){const t=e;return null!=t&&"string"==typeof t.text&&void 0===t.range&&void 0===t.rangeLength}}var nl,rl;function il(e,t){if(e.length<=1)return e;const n=e.length/2|0,r=e.slice(0,n),i=e.slice(n);il(r,t),il(i,t);let s=0,o=0,a=0;for(;s<r.length&&o<i.length;){const n=t(r[s],i[o]);e[a++]=n<=0?r[s++]:i[o++]}for(;s<r.length;)e[a++]=r[s++];for(;o<i.length;)e[a++]=i[o++];return e}function sl(e,t,n=0){const r=t?[n]:[];for(let i=0;i<e.length;i++){const t=e.charCodeAt(i);ol(t)&&(13===t&&i+1<e.length&&10===e.charCodeAt(i+1)&&i++,r.push(n+i+1))}return r}function ol(e){return 13===e||10===e}function al(e){const t=e.start,n=e.end;return t.line>n.line||t.line===n.line&&t.character>n.character?{start:n,end:t}:e}function cl(e){const t=al(e.range);return t!==e.range?{newText:e.newText,range:t}:e}!function(e){e.create=function(e,t,n,r){return new tl(e,t,n,r)},e.update=function(e,t,n){if(e instanceof tl)return e.update(t,n),e;throw new Error("TextDocument.update: document must be created by TextDocument.create")},e.applyEdits=function(e,t){const n=e.getText(),r=il(t.map(cl),((e,t)=>{const n=e.range.start.line-t.range.start.line;return 0===n?e.range.start.character-t.range.start.character:n}));let i=0;const s=[];for(const o of r){const t=e.offsetAt(o.range.start);if(t<i)throw new Error("Overlapping edit");t>i&&s.push(n.substring(i,t)),o.newText.length&&s.push(o.newText),i=e.offsetAt(o.range.end)}return s.push(n.substr(i)),s.join("")}}(nl||(nl={})),(()=>{var e={470:e=>{function t(e){if("string"!=typeof e)throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function n(e,t){for(var n,r="",i=0,s=-1,o=0,a=0;a<=e.length;++a){if(a<e.length)n=e.charCodeAt(a);else{if(47===n)break;n=47}if(47===n){if(s===a-1||1===o);else if(s!==a-1&&2===o){if(r.length<2||2!==i||46!==r.charCodeAt(r.length-1)||46!==r.charCodeAt(r.length-2))if(r.length>2){var c=r.lastIndexOf("/");if(c!==r.length-1){-1===c?(r="",i=0):i=(r=r.slice(0,c)).length-1-r.lastIndexOf("/"),s=a,o=0;continue}}else if(2===r.length||1===r.length){r="",i=0,s=a,o=0;continue}t&&(r.length>0?r+="/..":r="..",i=2)}else r.length>0?r+="/"+e.slice(s+1,a):r=e.slice(s+1,a),i=a-s-1;s=a,o=0}else 46===n&&-1!==o?++o:o=-1}return r}var r={resolve:function(){for(var e,r="",i=!1,s=arguments.length-1;s>=-1&&!i;s--){var o;s>=0?o=arguments[s]:(void 0===e&&(e=process.cwd()),o=e),t(o),0!==o.length&&(r=o+"/"+r,i=47===o.charCodeAt(0))}return r=n(r,!i),i?r.length>0?"/"+r:"/":r.length>0?r:"."},normalize:function(e){if(t(e),0===e.length)return".";var r=47===e.charCodeAt(0),i=47===e.charCodeAt(e.length-1);return 0!==(e=n(e,!r)).length||r||(e="."),e.length>0&&i&&(e+="/"),r?"/"+e:e},isAbsolute:function(e){return t(e),e.length>0&&47===e.charCodeAt(0)},join:function(){if(0===arguments.length)return".";for(var e,n=0;n<arguments.length;++n){var i=arguments[n];t(i),i.length>0&&(void 0===e?e=i:e+="/"+i)}return void 0===e?".":r.normalize(e)},relative:function(e,n){if(t(e),t(n),e===n)return"";if((e=r.resolve(e))===(n=r.resolve(n)))return"";for(var i=1;i<e.length&&47===e.charCodeAt(i);++i);for(var s=e.length,o=s-i,a=1;a<n.length&&47===n.charCodeAt(a);++a);for(var c=n.length-a,l=o<c?o:c,u=-1,d=0;d<=l;++d){if(d===l){if(c>l){if(47===n.charCodeAt(a+d))return n.slice(a+d+1);if(0===d)return n.slice(a+d)}else o>l&&(47===e.charCodeAt(i+d)?u=d:0===d&&(u=0));break}var h=e.charCodeAt(i+d);if(h!==n.charCodeAt(a+d))break;47===h&&(u=d)}var f="";for(d=i+u+1;d<=s;++d)d!==s&&47!==e.charCodeAt(d)||(0===f.length?f+="..":f+="/..");return f.length>0?f+n.slice(a+u):(a+=u,47===n.charCodeAt(a)&&++a,n.slice(a))},_makeLong:function(e){return e},dirname:function(e){if(t(e),0===e.length)return".";for(var n=e.charCodeAt(0),r=47===n,i=-1,s=!0,o=e.length-1;o>=1;--o)if(47===(n=e.charCodeAt(o))){if(!s){i=o;break}}else s=!1;return-1===i?r?"/":".":r&&1===i?"//":e.slice(0,i)},basename:function(e,n){if(void 0!==n&&"string"!=typeof n)throw new TypeError('"ext" argument must be a string');t(e);var r,i=0,s=-1,o=!0;if(void 0!==n&&n.length>0&&n.length<=e.length){if(n.length===e.length&&n===e)return"";var a=n.length-1,c=-1;for(r=e.length-1;r>=0;--r){var l=e.charCodeAt(r);if(47===l){if(!o){i=r+1;break}}else-1===c&&(o=!1,c=r+1),a>=0&&(l===n.charCodeAt(a)?-1==--a&&(s=r):(a=-1,s=c))}return i===s?s=c:-1===s&&(s=e.length),e.slice(i,s)}for(r=e.length-1;r>=0;--r)if(47===e.charCodeAt(r)){if(!o){i=r+1;break}}else-1===s&&(o=!1,s=r+1);return-1===s?"":e.slice(i,s)},extname:function(e){t(e);for(var n=-1,r=0,i=-1,s=!0,o=0,a=e.length-1;a>=0;--a){var c=e.charCodeAt(a);if(47!==c)-1===i&&(s=!1,i=a+1),46===c?-1===n?n=a:1!==o&&(o=1):-1!==n&&(o=-1);else if(!s){r=a+1;break}}return-1===n||-1===i||0===o||1===o&&n===i-1&&n===r+1?"":e.slice(n,i)},format:function(e){if(null===e||"object"!=typeof e)throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof e);return function(e,t){var n=t.dir||t.root,r=t.base||(t.name||"")+(t.ext||"");return n?n===t.root?n+r:n+"/"+r:r}(0,e)},parse:function(e){t(e);var n={root:"",dir:"",base:"",ext:"",name:""};if(0===e.length)return n;var r,i=e.charCodeAt(0),s=47===i;s?(n.root="/",r=1):r=0;for(var o=-1,a=0,c=-1,l=!0,u=e.length-1,d=0;u>=r;--u)if(47!==(i=e.charCodeAt(u)))-1===c&&(l=!1,c=u+1),46===i?-1===o?o=u:1!==d&&(d=1):-1!==o&&(d=-1);else if(!l){a=u+1;break}return-1===o||-1===c||0===d||1===d&&o===c-1&&o===a+1?-1!==c&&(n.base=n.name=0===a&&s?e.slice(1,c):e.slice(a,c)):(0===a&&s?(n.name=e.slice(1,o),n.base=e.slice(1,c)):(n.name=e.slice(a,o),n.base=e.slice(a,c)),n.ext=e.slice(o,c)),a>0?n.dir=e.slice(0,a-1):s&&(n.dir="/"),n},sep:"/",delimiter:":",win32:null,posix:null};r.posix=r,e.exports=r}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,n),s.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};(()=>{let e;if(n.r(r),n.d(r,{URI:()=>u,Utils:()=>x}),"object"==typeof process)e="win32"===process.platform;else if("object"==typeof navigator){let t=navigator.userAgent;e=t.indexOf("Windows")>=0}const t=/^\w[\w\d+.-]*$/,i=/^\//,s=/^\/\//;function o(e,n){if(!e.scheme&&n)throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${e.authority}", path: "${e.path}", query: "${e.query}", fragment: "${e.fragment}"}`);if(e.scheme&&!t.test(e.scheme))throw new Error("[UriError]: Scheme contains illegal characters.");if(e.path)if(e.authority){if(!i.test(e.path))throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character')}else if(s.test(e.path))throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")')}const a="",c="/",l=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;class u{static isUri(e){return e instanceof u||!!e&&"string"==typeof e.authority&&"string"==typeof e.fragment&&"string"==typeof e.path&&"string"==typeof e.query&&"string"==typeof e.scheme&&"string"==typeof e.fsPath&&"function"==typeof e.with&&"function"==typeof e.toString}scheme;authority;path;query;fragment;constructor(e,t,n,r,i,s=!1){"object"==typeof e?(this.scheme=e.scheme||a,this.authority=e.authority||a,this.path=e.path||a,this.query=e.query||a,this.fragment=e.fragment||a):(this.scheme=function(e,t){return e||t?e:"file"}(e,s),this.authority=t||a,this.path=function(e,t){switch(e){case"https":case"http":case"file":t?t[0]!==c&&(t=c+t):t=c}return t}(this.scheme,n||a),this.query=r||a,this.fragment=i||a,o(this,s))}get fsPath(){return g(this,!1)}with(e){if(!e)return this;let{scheme:t,authority:n,path:r,query:i,fragment:s}=e;return void 0===t?t=this.scheme:null===t&&(t=a),void 0===n?n=this.authority:null===n&&(n=a),void 0===r?r=this.path:null===r&&(r=a),void 0===i?i=this.query:null===i&&(i=a),void 0===s?s=this.fragment:null===s&&(s=a),t===this.scheme&&n===this.authority&&r===this.path&&i===this.query&&s===this.fragment?this:new h(t,n,r,i,s)}static parse(e,t=!1){const n=l.exec(e);return n?new h(n[2]||a,v(n[4]||a),v(n[5]||a),v(n[7]||a),v(n[9]||a),t):new h(a,a,a,a,a)}static file(t){let n=a;if(e&&(t=t.replace(/\\/g,c)),t[0]===c&&t[1]===c){const e=t.indexOf(c,2);-1===e?(n=t.substring(2),t=c):(n=t.substring(2,e),t=t.substring(e)||c)}return new h("file",n,t,a,a)}static from(e){const t=new h(e.scheme,e.authority,e.path,e.query,e.fragment);return o(t,!0),t}toString(e=!1){return y(this,e)}toJSON(){return this}static revive(e){if(e){if(e instanceof u)return e;{const t=new h(e);return t._formatted=e.external,t._fsPath=e._sep===d?e.fsPath:null,t}}return e}}const d=e?1:void 0;class h extends u{_formatted=null;_fsPath=null;get fsPath(){return this._fsPath||(this._fsPath=g(this,!1)),this._fsPath}toString(e=!1){return e?y(this,!0):(this._formatted||(this._formatted=y(this,!1)),this._formatted)}toJSON(){const e={$mid:1};return this._fsPath&&(e.fsPath=this._fsPath,e._sep=d),this._formatted&&(e.external=this._formatted),this.path&&(e.path=this.path),this.scheme&&(e.scheme=this.scheme),this.authority&&(e.authority=this.authority),this.query&&(e.query=this.query),this.fragment&&(e.fragment=this.fragment),e}}const f={58:"%3A",47:"%2F",63:"%3F",35:"%23",91:"%5B",93:"%5D",64:"%40",33:"%21",36:"%24",38:"%26",39:"%27",40:"%28",41:"%29",42:"%2A",43:"%2B",44:"%2C",59:"%3B",61:"%3D",32:"%20"};function p(e,t,n){let r,i=-1;for(let s=0;s<e.length;s++){const o=e.charCodeAt(s);if(o>=97&&o<=122||o>=65&&o<=90||o>=48&&o<=57||45===o||46===o||95===o||126===o||t&&47===o||n&&91===o||n&&93===o||n&&58===o)-1!==i&&(r+=encodeURIComponent(e.substring(i,s)),i=-1),void 0!==r&&(r+=e.charAt(s));else{void 0===r&&(r=e.substr(0,s));const t=f[o];void 0!==t?(-1!==i&&(r+=encodeURIComponent(e.substring(i,s)),i=-1),r+=t):-1===i&&(i=s)}}return-1!==i&&(r+=encodeURIComponent(e.substring(i))),void 0!==r?r:e}function m(e){let t;for(let n=0;n<e.length;n++){const r=e.charCodeAt(n);35===r||63===r?(void 0===t&&(t=e.substr(0,n)),t+=f[r]):void 0!==t&&(t+=e[n])}return void 0!==t?t:e}function g(t,n){let r;return r=t.authority&&t.path.length>1&&"file"===t.scheme?`//${t.authority}${t.path}`:47===t.path.charCodeAt(0)&&(t.path.charCodeAt(1)>=65&&t.path.charCodeAt(1)<=90||t.path.charCodeAt(1)>=97&&t.path.charCodeAt(1)<=122)&&58===t.path.charCodeAt(2)?n?t.path.substr(1):t.path[1].toLowerCase()+t.path.substr(2):t.path,e&&(r=r.replace(/\//g,"\\")),r}function y(e,t){const n=t?m:p;let r="",{scheme:i,authority:s,path:o,query:a,fragment:l}=e;if(i&&(r+=i,r+=":"),(s||"file"===i)&&(r+=c,r+=c),s){let e=s.indexOf("@");if(-1!==e){const t=s.substr(0,e);s=s.substr(e+1),e=t.lastIndexOf(":"),-1===e?r+=n(t,!1,!1):(r+=n(t.substr(0,e),!1,!1),r+=":",r+=n(t.substr(e+1),!1,!0)),r+="@"}s=s.toLowerCase(),e=s.lastIndexOf(":"),-1===e?r+=n(s,!1,!0):(r+=n(s.substr(0,e),!1,!0),r+=s.substr(e))}if(o){if(o.length>=3&&47===o.charCodeAt(0)&&58===o.charCodeAt(2)){const e=o.charCodeAt(1);e>=65&&e<=90&&(o=`/${String.fromCharCode(e+32)}:${o.substr(3)}`)}else if(o.length>=2&&58===o.charCodeAt(1)){const e=o.charCodeAt(0);e>=65&&e<=90&&(o=`${String.fromCharCode(e+32)}:${o.substr(2)}`)}r+=n(o,!0,!1)}return a&&(r+="?",r+=n(a,!1,!1)),l&&(r+="#",r+=t?l:p(l,!1,!1)),r}function A(e){try{return decodeURIComponent(e)}catch{return e.length>3?e.substr(0,3)+A(e.substr(3)):e}}const T=/(%[0-9A-Za-z][0-9A-Za-z])+/g;function v(e){return e.match(T)?e.replace(T,(e=>A(e))):e}var R=n(470);const E=R.posix||R,k="/";var x;!function(e){e.joinPath=function(e,...t){return e.with({path:E.join(e.path,...t)})},e.resolvePath=function(e,...t){let n=e.path,r=!1;n[0]!==k&&(n=k+n,r=!0);let i=E.resolve(n,...t);return r&&i[0]===k&&!e.authority&&(i=i.substring(1)),e.with({path:i})},e.dirname=function(e){if(0===e.path.length||e.path===k)return e;let t=E.dirname(e.path);return 1===t.length&&46===t.charCodeAt(0)&&(t=""),e.with({path:t})},e.basename=function(e){return E.basename(e.path)},e.extname=function(e){return E.extname(e.path)}}(x||(x={}))})(),rl=r})();const{URI:ll,Utils:ul}=rl;var dl,hl;!function(e){e.basename=ul.basename,e.dirname=ul.dirname,e.extname=ul.extname,e.joinPath=ul.joinPath,e.resolvePath=ul.resolvePath,e.equals=function(e,t){return(null==e?void 0:e.toString())===(null==t?void 0:t.toString())},e.relative=function(e,t){const n="string"==typeof e?e:e.path,r="string"==typeof t?t:t.path,i=n.split("/").filter((e=>e.length>0)),s=r.split("/").filter((e=>e.length>0));let o=0;for(;o<i.length&&i[o]===s[o];o++);return"../".repeat(i.length-o)+s.slice(o).join("/")}}(dl||(dl={})),function(e){e[e.Changed=0]="Changed",e[e.Parsed=1]="Parsed",e[e.IndexedContent=2]="IndexedContent",e[e.ComputedScopes=3]="ComputedScopes",e[e.Linked=4]="Linked",e[e.IndexedReferences=5]="IndexedReferences",e[e.Validated=6]="Validated"}(hl||(hl={}));class fl{constructor(e){this.serviceRegistry=e.ServiceRegistry,this.textDocuments=e.workspace.TextDocuments,this.fileSystemProvider=e.workspace.FileSystemProvider}async fromUri(e,t=Yc.XO.None){const n=await this.fileSystemProvider.readFile(e);return this.createAsync(e,n,t)}fromTextDocument(e,t,n){return t=null!=t?t:ll.parse(e.uri),n?this.createAsync(t,e,n):this.create(t,e)}fromString(e,t,n){return n?this.createAsync(t,e,n):this.create(t,e)}fromModel(e,t){return this.create(t,{$model:e})}create(e,t){if("string"==typeof t){const n=this.parse(e,t);return this.createLangiumDocument(n,e,void 0,t)}if("$model"in t){const n={value:t.$model,parserErrors:[],lexerErrors:[]};return this.createLangiumDocument(n,e)}{const n=this.parse(e,t.getText());return this.createLangiumDocument(n,e,t)}}async createAsync(e,t,n){if("string"==typeof t){const r=await this.parseAsync(e,t,n);return this.createLangiumDocument(r,e,void 0,t)}{const r=await this.parseAsync(e,t.getText(),n);return this.createLangiumDocument(r,e,t)}}createLangiumDocument(e,t,n,r){let i;if(n)i={parseResult:e,uri:t,state:hl.Parsed,references:[],textDocument:n};else{const n=this.createTextDocumentGetter(t,r);i={parseResult:e,uri:t,state:hl.Parsed,references:[],get textDocument(){return n()}}}return e.value.$document=i,i}async update(e,t){var n,r;const i=null===(n=e.parseResult.value.$cstNode)||void 0===n?void 0:n.root.fullText,s=null===(r=this.textDocuments)||void 0===r?void 0:r.get(e.uri.toString()),o=s?s.getText():await this.fileSystemProvider.readFile(e.uri);if(s)Object.defineProperty(e,"textDocument",{value:s});else{const t=this.createTextDocumentGetter(e.uri,o);Object.defineProperty(e,"textDocument",{get:t})}return i!==o&&(e.parseResult=await this.parseAsync(e.uri,o,t),e.parseResult.value.$document=e),e.state=hl.Parsed,e}parse(e,t){return this.serviceRegistry.getServices(e).parser.LangiumParser.parse(t)}parseAsync(e,t,n){return this.serviceRegistry.getServices(e).parser.AsyncParser.parse(t,n)}createTextDocumentGetter(e,t){const n=this.serviceRegistry;let r;return()=>null!=r?r:r=nl.create(e.toString(),n.getServices(e).LanguageMetaData.languageId,0,null!=t?t:"")}}class pl{constructor(e){this.documentMap=new Map,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory}get all(){return m(this.documentMap.values())}addDocument(e){const t=e.uri.toString();if(this.documentMap.has(t))throw new Error(`A document with the URI '${t}' is already present.`);this.documentMap.set(t,e)}getDocument(e){const t=e.toString();return this.documentMap.get(t)}async getOrCreateDocument(e,t){let n=this.getDocument(e);return n||(n=await this.langiumDocumentFactory.fromUri(e,t),this.addDocument(n),n)}createDocument(e,t,n){if(n)return this.langiumDocumentFactory.fromString(t,e,n).then((e=>(this.addDocument(e),e)));{const n=this.langiumDocumentFactory.fromString(t,e);return this.addDocument(n),n}}hasDocument(e){return this.documentMap.has(e.toString())}invalidateDocument(e){const t=e.toString(),n=this.documentMap.get(t);return n&&(n.state=hl.Changed,n.precomputedScopes=void 0,n.references=[],n.diagnostics=void 0),n}deleteDocument(e){const t=e.toString(),n=this.documentMap.get(t);return n&&(n.state=hl.Changed,this.documentMap.delete(t)),n}}class ml{constructor(e){this.reflection=e.shared.AstReflection,this.langiumDocuments=()=>e.shared.workspace.LangiumDocuments,this.scopeProvider=e.references.ScopeProvider,this.astNodeLocator=e.workspace.AstNodeLocator}async link(e,t=Yc.XO.None){for(const n of Ue(e.parseResult.value))await Zc(t),Ge(n).forEach((t=>this.doLink(t,e)))}doLink(e,t){const n=e.reference;if(void 0===n._ref)try{const t=this.getCandidate(e);if(s(t))n._ref=t;else if(n._nodeDescription=t,this.langiumDocuments().hasDocument(t.documentUri)){const r=this.loadAstNode(t);n._ref=null!=r?r:this.createLinkingError(e,t)}}catch(r){n._ref=Object.assign(Object.assign({},e),{message:`An error occurred while resolving reference to '${n.$refText}': ${r}`})}t.references.push(n)}unlink(e){for(const t of e.references)delete t._ref,delete t._nodeDescription;e.references=[]}getCandidate(e){const t=this.scopeProvider.getScope(e).getElement(e.reference.$refText);return null!=t?t:this.createLinkingError(e)}buildReference(e,t,n,i){const o=this,a={$refNode:n,$refText:i,get ref(){var n,i;if(r(this._ref))return this._ref;if("object"==typeof(i=this._nodeDescription)&&null!==i&&"string"==typeof i.name&&"string"==typeof i.type&&"string"==typeof i.path){const n=o.loadAstNode(this._nodeDescription);this._ref=null!=n?n:o.createLinkingError({reference:a,container:e,property:t},this._nodeDescription)}else if(void 0===this._ref){const r=o.getLinkedNode({reference:a,container:e,property:t});if(r.error&&Pe(e).state<hl.ComputedScopes)return;this._ref=null!==(n=r.node)&&void 0!==n?n:r.error,this._nodeDescription=r.descr}return r(this._ref)?this._ref:void 0},get $nodeDescription(){return this._nodeDescription},get error(){return s(this._ref)?this._ref:void 0}};return a}getLinkedNode(e){try{const t=this.getCandidate(e);if(s(t))return{error:t};const n=this.loadAstNode(t);return n?{node:n,descr:t}:{descr:t,error:this.createLinkingError(e,t)}}catch(t){return{error:Object.assign(Object.assign({},e),{message:`An error occurred while resolving reference to '${e.reference.$refText}': ${t}`})}}}loadAstNode(e){if(e.node)return e.node;const t=this.langiumDocuments().getDocument(e.documentUri);return t?this.astNodeLocator.getAstNode(t.parseResult.value,e.path):void 0}createLinkingError(e,t){const n=Pe(e.container);n.state<hl.ComputedScopes&&console.warn(`Attempted reference resolution before document reached ComputedScopes state (${n.uri}).`);const r=this.reflection.getReferenceType(e);return Object.assign(Object.assign({},e),{message:`Could not resolve reference to ${r} named '${e.reference.$refText}'.`,targetDescription:t})}}class gl{getName(e){if(function(e){return"string"==typeof e.name}(e))return e.name}getNameNode(e){return dt(e.$cstNode,"name")}}class yl{constructor(e){this.nameProvider=e.references.NameProvider,this.index=e.shared.workspace.IndexManager,this.nodeLocator=e.workspace.AstNodeLocator}findDeclaration(e){if(e){const t=function(e){var t;const n=e.astNode;for(;n===(null===(t=e.container)||void 0===t?void 0:t.astNode);){const t=_e(e.grammarSource,ue);if(t)return t;e=e.container}}(e),n=e.astNode;if(t&&n){const r=n[t.feature];if(i(r))return r.ref;if(Array.isArray(r))for(const t of r)if(i(t)&&t.$refNode&&t.$refNode.offset<=e.offset&&t.$refNode.end>=e.end)return t.ref}if(n){const t=this.nameProvider.getNameNode(n);if(t&&(t===e||function(e,t){for(;e.container;)if((e=e.container)===t)return!0;return!1}(e,t)))return n}}}findDeclarationNode(e){const t=this.findDeclaration(e);if(null==t?void 0:t.$cstNode){const e=this.nameProvider.getNameNode(t);return null!=e?e:t.$cstNode}}findReferences(e,t){const n=[];if(t.includeDeclaration){const t=this.getReferenceToSelf(e);t&&n.push(t)}let r=this.index.findAllReferences(e,this.nodeLocator.getAstNodePath(e));return t.documentUri&&(r=r.filter((e=>dl.equals(e.sourceUri,t.documentUri)))),n.push(...r),m(n)}getReferenceToSelf(e){const t=this.nameProvider.getNameNode(e);if(t){const n=Pe(e),r=this.nodeLocator.getAstNodePath(e);return{sourceUri:n.uri,sourcePath:r,targetUri:n.uri,targetPath:r,segment:R(t),local:!0}}}}class Al{constructor(e){if(this.map=new Map,e)for(const[t,n]of e)this.add(t,n)}get size(){return y.sum(m(this.map.values()).map((e=>e.length)))}clear(){this.map.clear()}delete(e,t){if(void 0===t)return this.map.delete(e);{const n=this.map.get(e);if(n){const r=n.indexOf(t);if(r>=0)return 1===n.length?this.map.delete(e):n.splice(r,1),!0}return!1}}get(e){var t;return null!==(t=this.map.get(e))&&void 0!==t?t:[]}has(e,t){if(void 0===t)return this.map.has(e);{const n=this.map.get(e);return!!n&&n.indexOf(t)>=0}}add(e,t){return this.map.has(e)?this.map.get(e).push(t):this.map.set(e,[t]),this}addAll(e,t){return this.map.has(e)?this.map.get(e).push(...t):this.map.set(e,Array.from(t)),this}forEach(e){this.map.forEach(((t,n)=>t.forEach((t=>e(t,n,this)))))}[Symbol.iterator](){return this.entries().iterator()}entries(){return m(this.map.entries()).flatMap((([e,t])=>t.map((t=>[e,t]))))}keys(){return m(this.map.keys())}values(){return m(this.map.values()).flat()}entriesGroupedByKey(){return m(this.map.entries())}}class Tl{get size(){return this.map.size}constructor(e){if(this.map=new Map,this.inverse=new Map,e)for(const[t,n]of e)this.set(t,n)}clear(){this.map.clear(),this.inverse.clear()}set(e,t){return this.map.set(e,t),this.inverse.set(t,e),this}get(e){return this.map.get(e)}getKey(e){return this.inverse.get(e)}delete(e){const t=this.map.get(e);return void 0!==t&&(this.map.delete(e),this.inverse.delete(t),!0)}}class vl{constructor(e){this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider}async computeExports(e,t=Yc.XO.None){return this.computeExportsForNode(e.parseResult.value,e,void 0,t)}async computeExportsForNode(e,t,n=Me,r=Yc.XO.None){const i=[];this.exportNode(e,i,t);for(const s of n(e))await Zc(r),this.exportNode(s,i,t);return i}exportNode(e,t,n){const r=this.nameProvider.getName(e);r&&t.push(this.descriptions.createDescription(e,r,n))}async computeLocalScopes(e,t=Yc.XO.None){const n=e.parseResult.value,r=new Al;for(const i of De(n))await Zc(t),this.processNode(i,e,r);return r}processNode(e,t,n){const r=e.$container;if(r){const i=this.nameProvider.getName(e);i&&n.add(r,this.descriptions.createDescription(e,i,t))}}}class Rl{constructor(e,t,n){var r;this.elements=e,this.outerScope=t,this.caseInsensitive=null!==(r=null==n?void 0:n.caseInsensitive)&&void 0!==r&&r}getAllElements(){return this.outerScope?this.elements.concat(this.outerScope.getAllElements()):this.elements}getElement(e){const t=this.caseInsensitive?this.elements.find((t=>t.name.toLowerCase()===e.toLowerCase())):this.elements.find((t=>t.name===e));return t||(this.outerScope?this.outerScope.getElement(e):void 0)}}class El{constructor(e,t,n){var r;this.elements=new Map,this.caseInsensitive=null!==(r=null==n?void 0:n.caseInsensitive)&&void 0!==r&&r;for(const i of e){const e=this.caseInsensitive?i.name.toLowerCase():i.name;this.elements.set(e,i)}this.outerScope=t}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,n=this.elements.get(t);return n||(this.outerScope?this.outerScope.getElement(e):void 0)}getAllElements(){let e=m(this.elements.values());return this.outerScope&&(e=e.concat(this.outerScope.getAllElements())),e}}class kl{constructor(){this.toDispose=[],this.isDisposed=!1}onDispose(e){this.toDispose.push(e)}dispose(){this.throwIfDisposed(),this.clear(),this.isDisposed=!0,this.toDispose.forEach((e=>e.dispose()))}throwIfDisposed(){if(this.isDisposed)throw new Error("This cache has already been disposed")}}class xl extends kl{constructor(){super(...arguments),this.cache=new Map}has(e){return this.throwIfDisposed(),this.cache.has(e)}set(e,t){this.throwIfDisposed(),this.cache.set(e,t)}get(e,t){if(this.throwIfDisposed(),this.cache.has(e))return this.cache.get(e);if(t){const n=t();return this.cache.set(e,n),n}}delete(e){return this.throwIfDisposed(),this.cache.delete(e)}clear(){this.throwIfDisposed(),this.cache.clear()}}class Il extends kl{constructor(e){super(),this.cache=new Map,this.converter=null!=e?e:e=>e}has(e,t){return this.throwIfDisposed(),this.cacheForContext(e).has(t)}set(e,t,n){this.throwIfDisposed(),this.cacheForContext(e).set(t,n)}get(e,t,n){this.throwIfDisposed();const r=this.cacheForContext(e);if(r.has(t))return r.get(t);if(n){const e=n();return r.set(t,e),e}}delete(e,t){return this.throwIfDisposed(),this.cacheForContext(e).delete(t)}clear(e){if(this.throwIfDisposed(),e){const t=this.converter(e);this.cache.delete(t)}else this.cache.clear()}cacheForContext(e){const t=this.converter(e);let n=this.cache.get(t);return n||(n=new Map,this.cache.set(t,n)),n}}class Sl extends xl{constructor(e){super(),this.onDispose(e.workspace.DocumentBuilder.onUpdate((()=>{this.clear()})))}}class Nl{constructor(e){this.reflection=e.shared.AstReflection,this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider,this.indexManager=e.shared.workspace.IndexManager,this.globalScopeCache=new Sl(e.shared)}getScope(e){const t=[],n=this.reflection.getReferenceType(e),r=Pe(e.container).precomputedScopes;if(r){let i=e.container;do{const e=r.get(i);e.length>0&&t.push(m(e).filter((e=>this.reflection.isSubtype(e.type,n)))),i=i.$container}while(i)}let i=this.getGlobalScope(n,e);for(let s=t.length-1;s>=0;s--)i=this.createScope(t[s],i);return i}createScope(e,t,n){return new Rl(m(e),t,n)}createScopeForNodes(e,t,n){const r=m(e).map((e=>{const t=this.nameProvider.getName(e);if(t)return this.descriptions.createDescription(e,t)})).nonNullable();return new Rl(r,t,n)}getGlobalScope(e,t){return this.globalScopeCache.get(e,(()=>new El(this.indexManager.allElements(e))))}}function Cl(e){return"object"==typeof e&&!!e&&("$ref"in e||"$error"in e)}class $l{constructor(e){this.ignoreProperties=new Set(["$container","$containerProperty","$containerIndex","$document","$cstNode"]),this.langiumDocuments=e.shared.workspace.LangiumDocuments,this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider,this.commentProvider=e.documentation.CommentProvider}serialize(e,t={}){const n=null==t?void 0:t.replacer,r=(e,n)=>this.replacer(e,n,t),i=n?(e,t)=>n(e,t,r):r;try{return this.currentDocument=Pe(e),JSON.stringify(e,i,null==t?void 0:t.space)}finally{this.currentDocument=void 0}}deserialize(e,t={}){const n=JSON.parse(e);return this.linkNode(n,n,t),n}replacer(e,t,{refText:n,sourceText:s,textRegions:o,comments:a,uriConverter:c}){var l,u,d,h;if(!this.ignoreProperties.has(e)){if(i(t)){const e=t.ref,r=n?t.$refText:void 0;if(e){const n=Pe(e);let i="";this.currentDocument&&this.currentDocument!==n&&(i=c?c(n.uri,t):n.uri.toString());return{$ref:`${i}#${this.astNodeLocator.getAstNodePath(e)}`,$refText:r}}return{$error:null!==(u=null===(l=t.error)||void 0===l?void 0:l.message)&&void 0!==u?u:"Could not resolve reference",$refText:r}}if(r(t)){let n;if(o&&(n=this.addAstNodeRegionWithAssignmentsTo(Object.assign({},t)),e&&!t.$document||!(null==n?void 0:n.$textRegion)||(n.$textRegion.documentURI=null===(d=this.currentDocument)||void 0===d?void 0:d.uri.toString())),s&&!e&&(null!=n||(n=Object.assign({},t)),n.$sourceText=null===(h=t.$cstNode)||void 0===h?void 0:h.text),a){null!=n||(n=Object.assign({},t));const e=this.commentProvider.getComment(t);e&&(n.$comment=e.replace(/\r/g,""))}return null!=n?n:t}return t}}addAstNodeRegionWithAssignmentsTo(e){const t=e=>({offset:e.offset,end:e.end,length:e.length,range:e.range});if(e.$cstNode){const n=(e.$textRegion=t(e.$cstNode)).assignments={};return Object.keys(e).filter((e=>!e.startsWith("$"))).forEach((r=>{const i=function(e,t){return e&&t?ht(e,t,e.astNode,!0):[]}(e.$cstNode,r).map(t);0!==i.length&&(n[r]=i)})),e}}linkNode(e,t,n,i,s,o){for(const[c,l]of Object.entries(e))if(Array.isArray(l))for(let i=0;i<l.length;i++){const s=l[i];Cl(s)?l[i]=this.reviveReference(e,c,t,s,n):r(s)&&this.linkNode(s,t,n,e,c,i)}else Cl(l)?e[c]=this.reviveReference(e,c,t,l,n):r(l)&&this.linkNode(l,t,n,e,c);const a=e;a.$container=i,a.$containerProperty=s,a.$containerIndex=o}reviveReference(e,t,n,i,s){let o=i.$refText,a=i.$error;if(i.$ref){const e=this.getRefNode(n,i.$ref,s.uriConverter);if(r(e))return o||(o=this.nameProvider.getName(e)),{$refText:null!=o?o:"",ref:e};a=e}if(a){const n={$refText:null!=o?o:""};return n.error={container:e,property:t,message:a,reference:n},n}}getRefNode(e,t,n){try{const r=t.indexOf("#");if(0===r){const n=this.astNodeLocator.getAstNode(e,t.substring(1));return n||"Could not resolve path: "+t}if(r<0){const e=n?n(t):ll.parse(t),r=this.langiumDocuments.getDocument(e);return r?r.parseResult.value:"Could not find document for URI: "+t}const i=n?n(t.substring(0,r)):ll.parse(t.substring(0,r)),s=this.langiumDocuments.getDocument(i);if(!s)return"Could not find document for URI: "+t;if(r===t.length-1)return s.parseResult.value;const o=this.astNodeLocator.getAstNode(s.parseResult.value,t.substring(r+1));return o||"Could not resolve URI: "+t}catch(r){return String(r)}}}class wl{register(e){if(this.singleton||this.map){if(!this.map&&(this.map={},this.singleton)){for(const e of this.singleton.LanguageMetaData.fileExtensions)this.map[e]=this.singleton;this.singleton=void 0}for(const t of e.LanguageMetaData.fileExtensions)void 0!==this.map[t]&&this.map[t]!==e&&console.warn(`The file extension ${t} is used by multiple languages. It is now assigned to '${e.LanguageMetaData.languageId}'.`),this.map[t]=e}else this.singleton=e}getServices(e){if(void 0!==this.singleton)return this.singleton;if(void 0===this.map)throw new Error("The service registry is empty. Use `register` to register the services of a language.");const t=dl.extname(e),n=this.map[t];if(!n)throw new Error(`The service registry contains no services for the extension '${t}'.`);return n}get all(){return void 0!==this.singleton?[this.singleton]:void 0!==this.map?Object.values(this.map):[]}}function Ll(e){return{code:e}}var Ol,bl,_l;!function(e){e.all=["fast","slow","built-in"]}(Ol||(Ol={}));class Pl{constructor(e){this.entries=new Al,this.reflection=e.shared.AstReflection}register(e,t=this,n="fast"){if("built-in"===n)throw new Error("The 'built-in' category is reserved for lexer, parser, and linker errors.");for(const[r,i]of Object.entries(e)){const e=i;if(Array.isArray(e))for(const i of e){const e={check:this.wrapValidationException(i,t),category:n};this.addEntry(r,e)}else if("function"==typeof e){const i={check:this.wrapValidationException(e,t),category:n};this.addEntry(r,i)}}}wrapValidationException(e,t){return async(n,r,i)=>{try{await e.call(t,n,r,i)}catch(s){if(Jc(s))throw s;console.error("An error occurred during validation:",s);const e=s instanceof Error?s.message:String(s);s instanceof Error&&s.stack&&console.error(s.stack),r("error","An error occurred during validation: "+e,{node:n})}}}addEntry(e,t){if("AstNode"!==e)for(const n of this.reflection.getAllSubTypes(e))this.entries.add(n,t);else this.entries.add("AstNode",t)}getChecks(e,t){let n=m(this.entries.get(e)).concat(this.entries.get("AstNode"));return t&&(n=n.filter((e=>t.includes(e.category)))),n.map((e=>e.check))}}class Ml{constructor(e){this.validationRegistry=e.validation.ValidationRegistry,this.metadata=e.LanguageMetaData}async validateDocument(e,t={},n=Yc.XO.None){const r=e.parseResult,i=[];if(await Zc(n),!t.categories||t.categories.includes("built-in")){if(this.processLexingErrors(r,i,t),t.stopAfterLexingErrors&&i.some((e=>{var t;return(null===(t=e.data)||void 0===t?void 0:t.code)===bl.LexingError})))return i;if(this.processParsingErrors(r,i,t),t.stopAfterParsingErrors&&i.some((e=>{var t;return(null===(t=e.data)||void 0===t?void 0:t.code)===bl.ParsingError})))return i;if(this.processLinkingErrors(e,i,t),t.stopAfterLinkingErrors&&i.some((e=>{var t;return(null===(t=e.data)||void 0===t?void 0:t.code)===bl.LinkingError})))return i}try{i.push(...await this.validateAst(r.value,t,n))}catch(s){if(Jc(s))throw s;console.error("An error occurred during validation:",s)}return await Zc(n),i}processLexingErrors(e,t,n){for(const r of e.lexerErrors){const e={severity:Ul("error"),range:{start:{line:r.line-1,character:r.column-1},end:{line:r.line-1,character:r.column+r.length-1}},message:r.message,data:Ll(bl.LexingError),source:this.getSource()};t.push(e)}}processParsingErrors(e,t,n){for(const r of e.parserErrors){let e;if(isNaN(r.token.startOffset)){if("previousToken"in r){const t=r.previousToken;if(isNaN(t.startOffset)){const t={line:0,character:0};e={start:t,end:t}}else{const n={line:t.endLine-1,character:t.endColumn};e={start:n,end:n}}}}else e=v(r.token);if(e){const n={severity:Ul("error"),range:e,message:r.message,data:Ll(bl.ParsingError),source:this.getSource()};t.push(n)}}}processLinkingErrors(e,t,n){for(const r of e.references){const e=r.error;if(e){const n={node:e.container,property:e.property,index:e.index,data:{code:bl.LinkingError,containerType:e.container.$type,property:e.property,refText:e.reference.$refText}};t.push(this.toDiagnostic("error",e.message,n))}}}async validateAst(e,t,n=Yc.XO.None){const r=[],i=(e,t,n)=>{r.push(this.toDiagnostic(e,t,n))};return await Promise.all(Ue(e).map((async e=>{await Zc(n);const r=this.validationRegistry.getChecks(e.$type,t.categories);for(const t of r)await t(e,i,n)}))),r}toDiagnostic(e,t,n){return{message:t,range:Dl(n),severity:Ul(e),code:n.code,codeDescription:n.codeDescription,tags:n.tags,relatedInformation:n.relatedInformation,data:n.data,source:this.getSource()}}getSource(){return this.metadata.languageId}}function Dl(e){if(e.range)return e.range;let t;return"string"==typeof e.property?t=dt(e.node.$cstNode,e.property,e.index):"string"==typeof e.keyword&&(t=function(e,t,n){if(!e)return;const r=ft(e,t,null==e?void 0:e.astNode);return 0!==r.length?r[n=void 0!==n?Math.max(0,Math.min(n,r.length-1)):0]:void 0}(e.node.$cstNode,e.keyword,e.index)),null!=t||(t=e.node.$cstNode),t?t.range:{start:{line:0,character:0},end:{line:0,character:0}}}function Ul(e){switch(e){case"error":return 1;case"warning":return 2;case"info":return 3;case"hint":return 4;default:throw new Error("Invalid diagnostic severity: "+e)}}!function(e){e.LexingError="lexing-error",e.ParsingError="parsing-error",e.LinkingError="linking-error"}(bl||(bl={}));class Fl{constructor(e){this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider}createDescription(e,t,n=Pe(e)){null!=t||(t=this.nameProvider.getName(e));const r=this.astNodeLocator.getAstNodePath(e);if(!t)throw new Error(`Node at path ${r} has no name.`);let i;const s=()=>{var t;return null!=i?i:i=R(null!==(t=this.nameProvider.getNameNode(e))&&void 0!==t?t:e.$cstNode)};return{node:e,name:t,get nameSegment(){return s()},selectionSegment:R(e.$cstNode),type:e.$type,documentUri:n.uri,path:r}}}class Gl{constructor(e){this.nodeLocator=e.workspace.AstNodeLocator}async createDescriptions(e,t=Yc.XO.None){const n=[],r=e.parseResult.value;for(const i of Ue(r))await Zc(t),Ge(i).filter((e=>!s(e))).forEach((e=>{const t=this.createDescription(e);t&&n.push(t)}));return n}createDescription(e){const t=e.reference.$nodeDescription,n=e.reference.$refNode;if(!t||!n)return;const r=Pe(e.container).uri;return{sourceUri:r,sourcePath:this.nodeLocator.getAstNodePath(e.container),targetUri:t.documentUri,targetPath:t.path,segment:R(n),local:dl.equals(t.documentUri,r)}}}class Kl{constructor(){this.segmentSeparator="/",this.indexSeparator="@"}getAstNodePath(e){if(e.$container){const t=this.getAstNodePath(e.$container),n=this.getPathSegment(e);return t+this.segmentSeparator+n}return""}getPathSegment({$containerProperty:e,$containerIndex:t}){if(!e)throw new Error("Missing '$containerProperty' in AST node.");return void 0!==t?e+this.indexSeparator+t:e}getAstNode(e,t){return t.split(this.segmentSeparator).reduce(((e,t)=>{if(!e||0===t.length)return e;const n=t.indexOf(this.indexSeparator);if(n>0){const r=t.substring(0,n),i=parseInt(t.substring(n+1)),s=e[r];return null==s?void 0:s[i]}return e[t]}),e)}}class Bl{constructor(e){this._ready=new el,this.settings={},this.workspaceConfig=!1,this.serviceRegistry=e.ServiceRegistry}get ready(){return this._ready.promise}initialize(e){var t,n;this.workspaceConfig=null!==(n=null===(t=e.capabilities.workspace)||void 0===t?void 0:t.configuration)&&void 0!==n&&n}async initialized(e){if(this.workspaceConfig){if(e.register){const t=this.serviceRegistry.all;e.register({section:t.map((e=>this.toSectionName(e.LanguageMetaData.languageId)))})}if(e.fetchConfiguration){const t=this.serviceRegistry.all.map((e=>({section:this.toSectionName(e.LanguageMetaData.languageId)}))),n=await e.fetchConfiguration(t);t.forEach(((e,t)=>{this.updateSectionConfiguration(e.section,n[t])}))}}this._ready.resolve()}updateConfiguration(e){e.settings&&Object.keys(e.settings).forEach((t=>{this.updateSectionConfiguration(t,e.settings[t])}))}updateSectionConfiguration(e,t){this.settings[e]=t}async getConfiguration(e,t){await this.ready;const n=this.toSectionName(e);if(this.settings[n])return this.settings[n][t]}toSectionName(e){return`${e}`}}!function(e){e.create=function(e){return{dispose:async()=>await e()}}}(_l||(_l={}));class jl{constructor(e){this.updateBuildOptions={validation:{categories:["built-in","fast"]}},this.updateListeners=[],this.buildPhaseListeners=new Al,this.buildState=new Map,this.documentBuildWaiters=new Map,this.currentState=hl.Changed,this.langiumDocuments=e.workspace.LangiumDocuments,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory,this.indexManager=e.workspace.IndexManager,this.serviceRegistry=e.ServiceRegistry}async build(e,t={},n=Yc.XO.None){var r,i;for(const s of e){const e=s.uri.toString();if(s.state===hl.Validated){if("boolean"==typeof t.validation&&t.validation)s.state=hl.IndexedReferences,s.diagnostics=void 0,this.buildState.delete(e);else if("object"==typeof t.validation){const n=this.buildState.get(e),o=null===(r=null==n?void 0:n.result)||void 0===r?void 0:r.validationChecks;if(o){const r=(null!==(i=t.validation.categories)&&void 0!==i?i:Ol.all).filter((e=>!o.includes(e)));r.length>0&&(this.buildState.set(e,{completed:!1,options:{validation:Object.assign(Object.assign({},t.validation),{categories:r})},result:n.result}),s.state=hl.IndexedReferences)}}}else this.buildState.delete(e)}this.currentState=hl.Changed,await this.emitUpdate(e.map((e=>e.uri)),[]),await this.buildDocuments(e,t,n)}async update(e,t,n=Yc.XO.None){this.currentState=hl.Changed;for(const s of t)this.langiumDocuments.deleteDocument(s),this.buildState.delete(s.toString()),this.indexManager.remove(s);for(const s of e){if(!this.langiumDocuments.invalidateDocument(s)){const e=this.langiumDocumentFactory.fromModel({$type:"INVALID"},s);e.state=hl.Changed,this.langiumDocuments.addDocument(e)}this.buildState.delete(s.toString())}const r=m(e).concat(t).map((e=>e.toString())).toSet();this.langiumDocuments.all.filter((e=>!r.has(e.uri.toString())&&this.shouldRelink(e,r))).forEach((e=>{this.serviceRegistry.getServices(e.uri).references.Linker.unlink(e),e.state=Math.min(e.state,hl.ComputedScopes),e.diagnostics=void 0})),await this.emitUpdate(e,t),await Zc(n);const i=this.langiumDocuments.all.filter((e=>{var t;return e.state<hl.Linked||!(null===(t=this.buildState.get(e.uri.toString()))||void 0===t?void 0:t.completed)})).toArray();await this.buildDocuments(i,this.updateBuildOptions,n)}async emitUpdate(e,t){await Promise.all(this.updateListeners.map((n=>n(e,t))))}shouldRelink(e,t){return!!e.references.some((e=>void 0!==e.error))||this.indexManager.isAffected(e,t)}onUpdate(e){return this.updateListeners.push(e),_l.create((()=>{const t=this.updateListeners.indexOf(e);t>=0&&this.updateListeners.splice(t,1)}))}async buildDocuments(e,t,n){this.prepareBuild(e,t),await this.runCancelable(e,hl.Parsed,n,(e=>this.langiumDocumentFactory.update(e,n))),await this.runCancelable(e,hl.IndexedContent,n,(e=>this.indexManager.updateContent(e,n))),await this.runCancelable(e,hl.ComputedScopes,n,(async e=>{const t=this.serviceRegistry.getServices(e.uri).references.ScopeComputation;e.precomputedScopes=await t.computeLocalScopes(e,n)})),await this.runCancelable(e,hl.Linked,n,(e=>this.serviceRegistry.getServices(e.uri).references.Linker.link(e,n))),await this.runCancelable(e,hl.IndexedReferences,n,(e=>this.indexManager.updateReferences(e,n)));const r=e.filter((e=>this.shouldValidate(e)));await this.runCancelable(r,hl.Validated,n,(e=>this.validate(e,n)));for(const i of e){const e=this.buildState.get(i.uri.toString());e&&(e.completed=!0)}}prepareBuild(e,t){for(const n of e){const e=n.uri.toString(),r=this.buildState.get(e);r&&!r.completed||this.buildState.set(e,{completed:!1,options:t,result:null==r?void 0:r.result})}}async runCancelable(e,t,n,r){const i=e.filter((e=>e.state<t));for(const s of i)await Zc(n),await r(s),s.state=t;await this.notifyBuildPhase(i,t,n),this.currentState=t}onBuildPhase(e,t){return this.buildPhaseListeners.add(e,t),_l.create((()=>{this.buildPhaseListeners.delete(e,t)}))}waitUntil(e,t,n){let r;if(t&&"path"in t?r=t:n=t,null!=n||(n=Yc.XO.None),r){const t=this.langiumDocuments.getDocument(r);if(t&&t.state>e)return Promise.resolve(r)}return this.currentState>=e?Promise.resolve(void 0):n.isCancellationRequested?Promise.reject(Qc):new Promise(((t,i)=>{const s=this.onBuildPhase(e,(()=>{if(s.dispose(),o.dispose(),r){const e=this.langiumDocuments.getDocument(r);t(null==e?void 0:e.uri)}else t(void 0)})),o=n.onCancellationRequested((()=>{s.dispose(),o.dispose(),i(Qc)}))}))}async notifyBuildPhase(e,t,n){if(0===e.length)return;const r=this.buildPhaseListeners.get(t);for(const i of r)await Zc(n),await i(e,n)}shouldValidate(e){return Boolean(this.getBuildOptions(e).validation)}async validate(e,t){var n,r;const i=this.serviceRegistry.getServices(e.uri).validation.DocumentValidator,s=this.getBuildOptions(e).validation,o="object"==typeof s?s:void 0,a=await i.validateDocument(e,o,t);e.diagnostics?e.diagnostics.push(...a):e.diagnostics=a;const c=this.buildState.get(e.uri.toString());if(c){null!==(n=c.result)&&void 0!==n||(c.result={});const e=null!==(r=null==o?void 0:o.categories)&&void 0!==r?r:Ol.all;c.result.validationChecks?c.result.validationChecks.push(...e):c.result.validationChecks=[...e]}}getBuildOptions(e){var t,n;return null!==(n=null===(t=this.buildState.get(e.uri.toString()))||void 0===t?void 0:t.options)&&void 0!==n?n:{}}}class Vl{constructor(e){this.symbolIndex=new Map,this.symbolByTypeIndex=new Il,this.referenceIndex=new Map,this.documents=e.workspace.LangiumDocuments,this.serviceRegistry=e.ServiceRegistry,this.astReflection=e.AstReflection}findAllReferences(e,t){const n=Pe(e).uri,r=[];return this.referenceIndex.forEach((e=>{e.forEach((e=>{dl.equals(e.targetUri,n)&&e.targetPath===t&&r.push(e)}))})),m(r)}allElements(e,t){let n=m(this.symbolIndex.keys());return t&&(n=n.filter((e=>!t||t.has(e)))),n.map((t=>this.getFileDescriptions(t,e))).flat()}getFileDescriptions(e,t){var n;if(!t)return null!==(n=this.symbolIndex.get(e))&&void 0!==n?n:[];const r=this.symbolByTypeIndex.get(e,t,(()=>{var n;return(null!==(n=this.symbolIndex.get(e))&&void 0!==n?n:[]).filter((e=>this.astReflection.isSubtype(e.type,t)))}));return r}remove(e){const t=e.toString();this.symbolIndex.delete(t),this.symbolByTypeIndex.clear(t),this.referenceIndex.delete(t)}async updateContent(e,t=Yc.XO.None){const n=this.serviceRegistry.getServices(e.uri),r=await n.references.ScopeComputation.computeExports(e,t),i=e.uri.toString();this.symbolIndex.set(i,r),this.symbolByTypeIndex.clear(i)}async updateReferences(e,t=Yc.XO.None){const n=this.serviceRegistry.getServices(e.uri),r=await n.workspace.ReferenceDescriptionProvider.createDescriptions(e,t);this.referenceIndex.set(e.uri.toString(),r)}isAffected(e,t){const n=this.referenceIndex.get(e.uri.toString());return!!n&&n.some((e=>!e.local&&t.has(e.targetUri.toString())))}}class Hl{constructor(e){this.initialBuildOptions={},this._ready=new el,this.serviceRegistry=e.ServiceRegistry,this.langiumDocuments=e.workspace.LangiumDocuments,this.documentBuilder=e.workspace.DocumentBuilder,this.fileSystemProvider=e.workspace.FileSystemProvider,this.mutex=e.workspace.WorkspaceLock}get ready(){return this._ready.promise}initialize(e){var t;this.folders=null!==(t=e.workspaceFolders)&&void 0!==t?t:void 0}initialized(e){return this.mutex.write((e=>{var t;return this.initializeWorkspace(null!==(t=this.folders)&&void 0!==t?t:[],e)}))}async initializeWorkspace(e,t=Yc.XO.None){const n=await this.performStartup(e);await Zc(t),await this.documentBuilder.build(n,this.initialBuildOptions,t)}async performStartup(e){const t=this.serviceRegistry.all.flatMap((e=>e.LanguageMetaData.fileExtensions)),n=[],r=e=>{n.push(e),this.langiumDocuments.hasDocument(e.uri)||this.langiumDocuments.addDocument(e)};return await this.loadAdditionalDocuments(e,r),await Promise.all(e.map((e=>[e,this.getRootFolder(e)])).map((async e=>this.traverseFolder(...e,t,r)))),this._ready.resolve(),n}loadAdditionalDocuments(e,t){return Promise.resolve()}getRootFolder(e){return ll.parse(e.uri)}async traverseFolder(e,t,n,r){const i=await this.fileSystemProvider.readDirectory(t);await Promise.all(i.map((async t=>{if(this.includeEntry(e,t,n))if(t.isDirectory)await this.traverseFolder(e,t.uri,n,r);else if(t.isFile){const e=await this.langiumDocuments.getOrCreateDocument(t.uri);r(e)}})))}includeEntry(e,t,n){const r=dl.basename(t.uri);if(r.startsWith("."))return!1;if(t.isDirectory)return"node_modules"!==r&&"out"!==r;if(t.isFile){const e=dl.extname(t.uri);return n.includes(e)}return!1}}class Wl{constructor(e){const t=e.parser.TokenBuilder.buildTokens(e.Grammar,{caseInsensitive:e.LanguageMetaData.caseInsensitive});this.tokenTypes=this.toTokenTypeDictionary(t);const n=Yl(t)?Object.values(t):t;this.chevrotainLexer=new ii(n,{positionTracking:"full"})}get definition(){return this.tokenTypes}tokenize(e){var t;const n=this.chevrotainLexer.tokenize(e);return{tokens:n.tokens,errors:n.errors,hidden:null!==(t=n.groups.hidden)&&void 0!==t?t:[]}}toTokenTypeDictionary(e){if(Yl(e))return e;const t=zl(e)?Object.values(e.modes).flat():e,n={};return t.forEach((e=>n[e.name]=e)),n}}function zl(e){return e&&"modes"in e&&"defaultMode"in e}function Yl(e){return!function(e){return Array.isArray(e)&&(0===e.length||"name"in e[0])}(e)&&!zl(e)}function Xl(e,t,n){let r,i;"string"==typeof e?(i=t,r=n):(i=e.range.start,r=t),i||(i=Qo.create(0,0));const s=function(e){var t,n,r;const i=[];let s=e.position.line,o=e.position.character;for(let a=0;a<e.lines.length;a++){const c=0===a,l=a===e.lines.length-1;let u=e.lines[a],d=0;if(c&&e.options.start){const n=null===(t=e.options.start)||void 0===t?void 0:t.exec(u);n&&(d=n.index+n[0].length)}else{const t=null===(n=e.options.line)||void 0===n?void 0:n.exec(u);t&&(d=t.index+t[0].length)}if(l){const t=null===(r=e.options.end)||void 0===r?void 0:r.exec(u);t&&(u=u.substring(0,t.index))}u=u.substring(0,ru(u));if(nu(u,d)>=u.length){if(i.length>0){const e=Qo.create(s,o);i.push({type:"break",content:"",range:Jo.create(e,e)})}}else{Ql.lastIndex=d;const e=Ql.exec(u);if(e){const t=e[0],n=e[1],r=Qo.create(s,o+d),a=Qo.create(s,o+d+t.length);i.push({type:"tag",content:n,range:Jo.create(r,a)}),d+=t.length,d=nu(u,d)}if(d<u.length){const e=u.substring(d),t=Array.from(e.matchAll(Jl));i.push(...Zl(t,e,s,o+d))}}s++,o=0}if(i.length>0&&"break"===i[i.length-1].type)return i.slice(0,-1);return i}({lines:ql(e),position:i,options:lu(r)});return function(e){var t,n,r,i;const s=Qo.create(e.position.line,e.position.character);if(0===e.tokens.length)return new du([],Jo.create(s,s));const o=[];for(;e.index<e.tokens.length;){const t=iu(e,o[o.length-1]);t&&o.push(t)}const a=null!==(n=null===(t=o[0])||void 0===t?void 0:t.range.start)&&void 0!==n?n:s,c=null!==(i=null===(r=o[o.length-1])||void 0===r?void 0:r.range.end)&&void 0!==i?i:s;return new du(o,Jo.create(a,c))}({index:0,tokens:s,position:i})}function ql(e){let t="";t="string"==typeof e?e:e.text;return t.split(nt)}const Ql=/\s*(@([\p{L}][\p{L}\p{N}]*)?)/uy,Jl=/\{(@[\p{L}][\p{L}\p{N}]*)(\s*)([^\r\n}]+)?\}/gu;function Zl(e,t,n,r){const i=[];if(0===e.length){const e=Qo.create(n,r),s=Qo.create(n,r+t.length);i.push({type:"text",content:t,range:Jo.create(e,s)})}else{let s=0;for(const a of e){const e=a.index,o=t.substring(s,e);o.length>0&&i.push({type:"text",content:t.substring(s,e),range:Jo.create(Qo.create(n,s+r),Qo.create(n,e+r))});let c=o.length+1;const l=a[1];if(i.push({type:"inline-tag",content:l,range:Jo.create(Qo.create(n,s+c+r),Qo.create(n,s+c+l.length+r))}),c+=l.length,4===a.length){c+=a[2].length;const e=a[3];i.push({type:"text",content:e,range:Jo.create(Qo.create(n,s+c+r),Qo.create(n,s+c+e.length+r))})}else i.push({type:"text",content:"",range:Jo.create(Qo.create(n,s+c+r),Qo.create(n,s+c+r))});s=e+a[0].length}const o=t.substring(s);o.length>0&&i.push({type:"text",content:o,range:Jo.create(Qo.create(n,s+r),Qo.create(n,s+r+o.length))})}return i}const eu=/\S/,tu=/\s*$/;function nu(e,t){const n=e.substring(t).match(eu);return n?t+n.index:e.length}function ru(e){const t=e.match(tu);if(t&&"number"==typeof t.index)return t.index}function iu(e,t){const n=e.tokens[e.index];return"tag"===n.type?au(e,!1):"text"===n.type||"inline-tag"===n.type?su(e):(function(e,t){if(t){const n=new pu("",e.range);"inlines"in t?t.inlines.push(n):t.content.inlines.push(n)}}(n,t),void e.index++)}function su(e){let t=e.tokens[e.index];const n=t;let r=t;const i=[];for(;t&&"break"!==t.type&&"tag"!==t.type;)i.push(ou(e)),r=t,t=e.tokens[e.index];return new fu(i,Jo.create(n.range.start,r.range.end))}function ou(e){return"inline-tag"===e.tokens[e.index].type?au(e,!0):cu(e)}function au(e,t){const n=e.tokens[e.index++],r=n.content.substring(1),i=e.tokens[e.index];if("text"===(null==i?void 0:i.type)){if(t){const i=cu(e);return new hu(r,new fu([i],i.range),t,Jo.create(n.range.start,i.range.end))}{const i=su(e);return new hu(r,i,t,Jo.create(n.range.start,i.range.end))}}{const e=n.range;return new hu(r,new fu([],e),t,e)}}function cu(e){const t=e.tokens[e.index++];return new pu(t.content,t.range)}function lu(e){if(!e)return lu({start:"/**",end:"*/",line:"*"});const{start:t,end:n,line:r}=e;return{start:uu(t,!0),end:uu(n,!1),line:uu(r,!0)}}function uu(e,t){if("string"==typeof e||"object"==typeof e){const n="string"==typeof e?at(e):e.source;return t?new RegExp(`^\\s*${n}`):new RegExp(`\\s*${n}\\s*$`)}return e}class du{constructor(e,t){this.elements=e,this.range=t}getTag(e){return this.getAllTags().find((t=>t.name===e))}getTags(e){return this.getAllTags().filter((t=>t.name===e))}getAllTags(){return this.elements.filter((e=>"name"in e))}toString(){let e="";for(const t of this.elements)if(0===e.length)e=t.toString();else{const n=t.toString();e+=mu(e)+n}return e.trim()}toMarkdown(e){let t="";for(const n of this.elements)if(0===t.length)t=n.toMarkdown(e);else{const r=n.toMarkdown(e);t+=mu(t)+r}return t.trim()}}class hu{constructor(e,t,n,r){this.name=e,this.content=t,this.inline=n,this.range=r}toString(){let e=`@${this.name}`;const t=this.content.toString();return 1===this.content.inlines.length?e=`${e} ${t}`:this.content.inlines.length>1&&(e=`${e}\n${t}`),this.inline?`{${e}}`:e}toMarkdown(e){var t,n;return null!==(n=null===(t=null==e?void 0:e.renderTag)||void 0===t?void 0:t.call(e,this))&&void 0!==n?n:this.toMarkdownDefault(e)}toMarkdownDefault(e){const t=this.content.toMarkdown(e);if(this.inline){const n=function(e,t,n){var r,i;if("linkplain"===e||"linkcode"===e||"link"===e){const s=t.indexOf(" ");let o=t;if(s>0){const e=nu(t,s);o=t.substring(e),t=t.substring(0,s)}("linkcode"===e||"link"===e&&"code"===n.link)&&(o=`\`${o}\``);const a=null!==(i=null===(r=n.renderLink)||void 0===r?void 0:r.call(n,t,o))&&void 0!==i?i:function(e,t){try{return ll.parse(e,!0),`[${t}](${e})`}catch(r){return e}}(t,o);return a}return}(this.name,t,null!=e?e:{});if("string"==typeof n)return n}let n="";"italic"===(null==e?void 0:e.tag)||void 0===(null==e?void 0:e.tag)?n="*":"bold"===(null==e?void 0:e.tag)?n="**":"bold-italic"===(null==e?void 0:e.tag)&&(n="***");let r=`${n}@${this.name}${n}`;return 1===this.content.inlines.length?r=`${r} \u2014 ${t}`:this.content.inlines.length>1&&(r=`${r}\n${t}`),this.inline?`{${r}}`:r}}class fu{constructor(e,t){this.inlines=e,this.range=t}toString(){let e="";for(let t=0;t<this.inlines.length;t++){const n=this.inlines[t],r=this.inlines[t+1];e+=n.toString(),r&&r.range.start.line>n.range.start.line&&(e+="\n")}return e}toMarkdown(e){let t="";for(let n=0;n<this.inlines.length;n++){const r=this.inlines[n],i=this.inlines[n+1];t+=r.toMarkdown(e),i&&i.range.start.line>r.range.start.line&&(t+="\n")}return t}}class pu{constructor(e,t){this.text=e,this.range=t}toString(){return this.text}toMarkdown(){return this.text}}function mu(e){return e.endsWith("\n")?"\n":"\n\n"}class gu{constructor(e){this.indexManager=e.shared.workspace.IndexManager,this.commentProvider=e.documentation.CommentProvider}getDocumentation(e){const t=this.commentProvider.getComment(e);if(t&&function(e,t){const n=lu(t),r=ql(e);if(0===r.length)return!1;const i=r[0],s=r[r.length-1],o=n.start,a=n.end;return Boolean(null==o?void 0:o.exec(i))&&Boolean(null==a?void 0:a.exec(s))}(t)){return Xl(t).toMarkdown({renderLink:(t,n)=>this.documentationLinkRenderer(e,t,n),renderTag:t=>this.documentationTagRenderer(e,t)})}}documentationLinkRenderer(e,t,n){var r;const i=null!==(r=this.findNameInPrecomputedScopes(e,t))&&void 0!==r?r:this.findNameInGlobalScope(e,t);if(i&&i.nameSegment){const e=i.nameSegment.range.start.line+1,t=i.nameSegment.range.start.character+1;return`[${n}](${i.documentUri.with({fragment:`L${e},${t}`}).toString()})`}}documentationTagRenderer(e,t){}findNameInPrecomputedScopes(e,t){const n=Pe(e).precomputedScopes;if(!n)return;let r=e;do{const e=n.get(r).find((e=>e.name===t));if(e)return e;r=r.$container}while(r)}findNameInGlobalScope(e,t){return this.indexManager.allElements().find((e=>e.name===t))}}class yu{constructor(e){this.grammarConfig=()=>e.parser.GrammarConfig}getComment(e){var t;return function(e){return"string"==typeof e.$comment}(e)?e.$comment:null===(t=x(e.$cstNode,this.grammarConfig().multilineCommentRules))||void 0===t?void 0:t.text}}var Au;n(62676);class Tu{constructor(e){this.syncParser=e.parser.LangiumParser}parse(e){return Promise.resolve(this.syncParser.parse(e))}}class vu{constructor(){this.previousTokenSource=new Yc.Qi,this.writeQueue=[],this.readQueue=[],this.done=!0}write(e){this.cancelWrite();const t=new Yc.Qi;return this.previousTokenSource=t,this.enqueue(this.writeQueue,e,t.token)}read(e){return this.enqueue(this.readQueue,e)}enqueue(e,t,n){const r=new el,i={action:t,deferred:r,cancellationToken:null!=n?n:Yc.XO.None};return e.push(i),this.performNextOperation(),r.promise}async performNextOperation(){if(!this.done)return;const e=[];if(this.writeQueue.length>0)e.push(this.writeQueue.shift());else{if(!(this.readQueue.length>0))return;e.push(...this.readQueue.splice(0,this.readQueue.length))}this.done=!1,await Promise.all(e.map((async({action:e,deferred:t,cancellationToken:n})=>{try{const r=await Promise.resolve().then((()=>e(n)));t.resolve(r)}catch(r){Jc(r)?t.resolve(void 0):t.reject(r)}}))),this.done=!0,this.performNextOperation()}cancelWrite(){this.previousTokenSource.cancel()}}class Ru{constructor(e){this.grammarElementIdMap=new Tl,this.tokenTypeIdMap=new Tl,this.grammar=e.Grammar,this.lexer=e.parser.Lexer,this.linker=e.references.Linker}dehydrate(e){return{lexerErrors:e.lexerErrors.map((e=>Object.assign({},e))),parserErrors:e.parserErrors.map((e=>Object.assign({},e))),value:this.dehydrateAstNode(e.value,this.createDehyrationContext(e.value))}}createDehyrationContext(e){const t=new Map,n=new Map;for(const r of Ue(e))t.set(r,{});if(e.$cstNode)for(const r of T(e.$cstNode))n.set(r,{});return{astNodes:t,cstNodes:n}}dehydrateAstNode(e,t){const n=t.astNodes.get(e);n.$type=e.$type,n.$containerIndex=e.$containerIndex,n.$containerProperty=e.$containerProperty,void 0!==e.$cstNode&&(n.$cstNode=this.dehydrateCstNode(e.$cstNode,t));for(const[s,o]of Object.entries(e))if(!s.startsWith("$"))if(Array.isArray(o)){const e=[];n[s]=e;for(const n of o)r(n)?e.push(this.dehydrateAstNode(n,t)):i(n)?e.push(this.dehydrateReference(n,t)):e.push(n)}else r(o)?n[s]=this.dehydrateAstNode(o,t):i(o)?n[s]=this.dehydrateReference(o,t):void 0!==o&&(n[s]=o);return n}dehydrateReference(e,t){const n={};return n.$refText=e.$refText,e.$refNode&&(n.$refNode=t.cstNodes.get(e.$refNode)),n}dehydrateCstNode(e,t){const n=t.cstNodes.get(e);return l(e)?n.fullText=e.fullText:n.grammarSource=this.getGrammarElementId(e.grammarSource),n.hidden=e.hidden,n.astNode=t.astNodes.get(e.astNode),a(e)?n.content=e.content.map((e=>this.dehydrateCstNode(e,t))):c(e)&&(n.tokenType=e.tokenType.name,n.offset=e.offset,n.length=e.length,n.startLine=e.range.start.line,n.startColumn=e.range.start.character,n.endLine=e.range.end.line,n.endColumn=e.range.end.character),n}hydrate(e){const t=e.value,n=this.createHydrationContext(t);return"$cstNode"in t&&this.hydrateCstNode(t.$cstNode,n),{lexerErrors:e.lexerErrors,parserErrors:e.parserErrors,value:this.hydrateAstNode(t,n)}}createHydrationContext(e){const t=new Map,n=new Map;for(const i of Ue(e))t.set(i,{});let r;if(e.$cstNode)for(const i of T(e.$cstNode)){let e;"fullText"in i?(e=new Ic(i.fullText),r=e):"content"in i?e=new kc:"tokenType"in i&&(e=this.hydrateCstLeafNode(i)),e&&(n.set(i,e),e.root=r)}return{astNodes:t,cstNodes:n}}hydrateAstNode(e,t){const n=t.astNodes.get(e);n.$type=e.$type,n.$containerIndex=e.$containerIndex,n.$containerProperty=e.$containerProperty,e.$cstNode&&(n.$cstNode=t.cstNodes.get(e.$cstNode));for(const[s,o]of Object.entries(e))if(!s.startsWith("$"))if(Array.isArray(o)){const e=[];n[s]=e;for(const a of o)r(a)?e.push(this.setParent(this.hydrateAstNode(a,t),n)):i(a)?e.push(this.hydrateReference(a,n,s,t)):e.push(a)}else r(o)?n[s]=this.setParent(this.hydrateAstNode(o,t),n):i(o)?n[s]=this.hydrateReference(o,n,s,t):void 0!==o&&(n[s]=o);return n}setParent(e,t){return e.$container=t,e}hydrateReference(e,t,n,r){return this.linker.buildReference(t,n,r.cstNodes.get(e.$refNode),e.$refText)}hydrateCstNode(e,t,n=0){const r=t.cstNodes.get(e);if("number"==typeof e.grammarSource&&(r.grammarSource=this.getGrammarElement(e.grammarSource)),r.astNode=t.astNodes.get(e.astNode),a(r))for(const i of e.content){const e=this.hydrateCstNode(i,t,n++);r.content.push(e)}return r}hydrateCstLeafNode(e){const t=this.getTokenType(e.tokenType),n=e.offset,r=e.length,i=e.startLine,s=e.startColumn,o=e.endLine,a=e.endColumn,c=e.hidden;return new Ec(n,r,{start:{line:i,character:s},end:{line:o,character:a}},t,c)}getTokenType(e){return this.lexer.definition[e]}getGrammarElementId(e){return 0===this.grammarElementIdMap.size&&this.createGrammarElementIdMap(),this.grammarElementIdMap.get(e)}getGrammarElement(e){0===this.grammarElementIdMap.size&&this.createGrammarElementIdMap();const t=this.grammarElementIdMap.getKey(e);if(t)return t;throw new Error("Invalid grammar element id: "+e)}createGrammarElementIdMap(){let e=0;for(const n of Ue(this.grammar))t=n,Oe.isInstance(t,b)&&this.grammarElementIdMap.set(n,e++);var t}}function Eu(e){return{documentation:{CommentProvider:e=>new yu(e),DocumentationProvider:e=>new gu(e)},parser:{AsyncParser:e=>new Tu(e),GrammarConfig:e=>function(e){const t=[],n=e.Grammar;for(const i of n.rules)te(i)&&(r=i).hidden&&!vt(r).test(" ")&&st(vt(i))&&t.push(i.name);var r;return{multilineCommentRules:t,nameRegexp:k}}(e),LangiumParser:e=>Vc(e),CompletionParser:e=>function(e){const t=e.Grammar,n=e.parser.Lexer,r=new bc(e);return Mc(t,r,n.definition),r.finalize(),r}(e),ValueConverter:()=>new Wc,TokenBuilder:()=>new Hc,Lexer:e=>new Wl(e),ParserErrorMessageProvider:()=>new Oc},workspace:{AstNodeLocator:()=>new Kl,AstNodeDescriptionProvider:e=>new Fl(e),ReferenceDescriptionProvider:e=>new Gl(e)},references:{Linker:e=>new ml(e),NameProvider:()=>new gl,ScopeProvider:e=>new Nl(e),ScopeComputation:e=>new vl(e),References:e=>new yl(e)},serializer:{Hydrator:e=>new Ru(e),JsonSerializer:e=>new $l(e)},validation:{DocumentValidator:e=>new Ml(e),ValidationRegistry:e=>new Pl(e)},shared:()=>e.shared}}function ku(e){return{ServiceRegistry:()=>new wl,workspace:{LangiumDocuments:e=>new pl(e),LangiumDocumentFactory:e=>new fl(e),DocumentBuilder:e=>new jl(e),IndexManager:e=>new Vl(e),WorkspaceManager:e=>new Hl(e),FileSystemProvider:t=>e.fileSystemProvider(t),WorkspaceLock:()=>new vu,ConfigurationProvider:e=>new Bl(e)}}}function xu(e,t,n,r,i,s,o,a,c){return Su([e,t,n,r,i,s,o,a,c].reduce($u,{}))}!function(e){e.merge=(e,t)=>$u($u({},e),t)}(Au||(Au={}));const Iu=Symbol("isProxy");function Su(e,t){const n=new Proxy({},{deleteProperty:()=>!1,get:(r,i)=>Cu(r,i,e,t||n),getOwnPropertyDescriptor:(r,i)=>(Cu(r,i,e,t||n),Object.getOwnPropertyDescriptor(r,i)),has:(t,n)=>n in e,ownKeys:()=>[...Reflect.ownKeys(e),Iu]});return n[Iu]=!0,n}const Nu=Symbol();function Cu(e,t,n,r){if(t in e){if(e[t]instanceof Error)throw new Error("Construction failure. Please make sure that your dependencies are constructable.",{cause:e[t]});if(e[t]===Nu)throw new Error('Cycle detected. Please make "'+String(t)+'" lazy. See https://langium.org/docs/configuration-services/#resolving-cyclic-dependencies');return e[t]}if(t in n){const s=n[t];e[t]=Nu;try{e[t]="function"==typeof s?s(r):Su(s,r)}catch(i){throw e[t]=i instanceof Error?i:void 0,i}return e[t]}}function $u(e,t){if(t)for(const[n,r]of Object.entries(t))if(void 0!==r){const t=e[n];e[n]=null!==t&&null!==r&&"object"==typeof t&&"object"==typeof r?$u(t,r):r}return e}class wu{readFile(){throw new Error("No file system is available.")}async readDirectory(){return[]}}const Lu={fileSystemProvider:()=>new wu},Ou={Grammar:()=>{},LanguageMetaData:()=>({caseInsensitive:!1,fileExtensions:[".langium"],languageId:"langium"})},bu={AstReflection:()=>new Le};function _u(e){var t;const n=function(){const e=xu(ku(Lu),bu),t=xu(Eu({shared:e}),Ou);return e.ServiceRegistry.register(t),t}(),r=n.serializer.JsonSerializer.deserialize(e);return n.shared.workspace.LangiumDocumentFactory.fromModel(r,ll.parse(`memory://${null!==(t=r.name)&&void 0!==t?t:"grammar"}.langium`)),r}},72559:(e,t,n)=>{n.d(t,{A:()=>i});var r=n(61882);const i=function(e,t,n){for(var i=-1,s=e.length;++i<s;){var o=e[i],a=t(o);if(null!=a&&(void 0===c?a==a&&!(0,r.A)(a):n(a,c)))var c=a,l=o}return l}},36224:(e,t,n)=>{n.d(t,{A:()=>r});const r=function(e,t){return e<t}},52568:(e,t,n)=>{n.d(t,{A:()=>s});var r=n(6240),i=n(38446);const s=function(e,t){var n=-1,s=(0,i.A)(e)?Array(e.length):[];return(0,r.A)(e,(function(e,r,i){s[++n]=t(e,r,i)})),s}},99354:(e,t,n)=>{n.d(t,{A:()=>u});var r=n(66318),i=n(52851),s=n(7819),o=n(25353),a=n(23149),c=n(30901);const l=function(e,t,n,r){if(!(0,a.A)(e))return e;for(var l=-1,u=(t=(0,s.A)(t,e)).length,d=u-1,h=e;null!=h&&++l<u;){var f=(0,c.A)(t[l]),p=n;if("__proto__"===f||"constructor"===f||"prototype"===f)return e;if(l!=d){var m=h[f];void 0===(p=r?r(m,f,h):void 0)&&(p=(0,a.A)(m)?m:(0,o.A)(t[l+1])?[]:{})}(0,i.A)(h,f,p),h=h[f]}return e};const u=function(e,t,n){for(var i=-1,o=t.length,a={};++i<o;){var c=t[i],u=(0,r.A)(e,c);n(u,c)&&l(a,(0,s.A)(c,e),u)}return a}},50053:(e,t,n)=>{n.d(t,{A:()=>i});var r=n(68675);const i=function(e){return(0,r.A)(e,4)}},23068:(e,t,n)=>{n.d(t,{A:()=>l});var r=n(24326),i=n(66984),s=n(6832),o=n(55615),a=Object.prototype,c=a.hasOwnProperty;const l=(0,r.A)((function(e,t){e=Object(e);var n=-1,r=t.length,l=r>2?t[2]:void 0;for(l&&(0,s.A)(t[0],t[1],l)&&(r=1);++n<r;)for(var u=t[n],d=(0,o.A)(u),h=-1,f=d.length;++h<f;){var p=d[h],m=e[p];(void 0===m||(0,i.A)(m,a[p])&&!c.call(e,p))&&(e[p]=u[p])}return e}))},16145:(e,t,n)=>{n.d(t,{A:()=>u});var r=n(23958),i=n(38446),s=n(27422);const o=function(e){return function(t,n,o){var a=Object(t);if(!(0,i.A)(t)){var c=(0,r.A)(n,3);t=(0,s.A)(t),n=function(e){return c(a[e],e,a)}}var l=e(t,n,o);return l>-1?a[c?t[l]:l]:void 0}};var a=n(25707),c=n(18593),l=Math.max;const u=o((function(e,t,n){var i=null==e?0:e.length;if(!i)return-1;var s=null==n?0:(0,c.A)(n);return s<0&&(s=l(i+s,0)),(0,a.A)(e,(0,r.A)(t,3),s)}))},34098:(e,t,n)=>{n.d(t,{A:()=>i});var r=n(13588);const i=function(e){return(null==e?0:e.length)?(0,r.A)(e,1):[]}},48585:(e,t,n)=>{n.d(t,{A:()=>o});var r=Object.prototype.hasOwnProperty;const i=function(e,t){return null!=e&&r.call(e,t)};var s=n(85054);const o=function(e,t){return null!=e&&(0,s.A)(e,t,i)}},9703:(e,t,n)=>{n.d(t,{A:()=>o});var r=n(88496),i=n(92049),s=n(53098);const o=function(e){return"string"==typeof e||!(0,i.A)(e)&&(0,s.A)(e)&&"[object String]"==(0,r.A)(e)}},26666:(e,t,n)=>{n.d(t,{A:()=>r});const r=function(e){var t=null==e?0:e.length;return t?e[t-1]:void 0}},74722:(e,t,n)=>{n.d(t,{A:()=>a});var r=n(45572),i=n(23958),s=n(52568),o=n(92049);const a=function(e,t){return((0,o.A)(e)?r.A:s.A)(e,(0,i.A)(t,3))}},86452:(e,t,n)=>{n.d(t,{A:()=>o});var r=n(72559),i=n(36224),s=n(29008);const o=function(e){return e&&e.length?(0,r.A)(e,s.A,i.A):void 0}},74342:(e,t,n)=>{n.d(t,{A:()=>m});var r=/\s/;const i=function(e){for(var t=e.length;t--&&r.test(e.charAt(t)););return t};var s=/^\s+/;const o=function(e){return e?e.slice(0,i(e)+1).replace(s,""):e};var a=n(23149),c=n(61882),l=/^[-+]0x[0-9a-f]+$/i,u=/^0b[01]+$/i,d=/^0o[0-7]+$/i,h=parseInt;const f=function(e){if("number"==typeof e)return e;if((0,c.A)(e))return NaN;if((0,a.A)(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=(0,a.A)(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=o(e);var n=u.test(e);return n||d.test(e)?h(e.slice(2),n?2:8):l.test(e)?NaN:+e};var p=1/0;const m=function(e){return e?(e=f(e))===p||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}},18593:(e,t,n)=>{n.d(t,{A:()=>i});var r=n(74342);const i=function(e){var t=(0,r.A)(e),n=t%1;return t==t?n?t-n:t:0}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/890.8531ec8c.js b/pr-preview/pr-1071/assets/js/890.8531ec8c.js deleted file mode 100644 index 42429f67c9..0000000000 --- a/pr-preview/pr-1071/assets/js/890.8531ec8c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[890],{10890:(s,c,e)=>{e.d(c,{createInfoServices:()=>t.v});var t=e(97021);e(19369)}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/89486910.949b861e.js b/pr-preview/pr-1071/assets/js/89486910.949b861e.js deleted file mode 100644 index 47755c830f..0000000000 --- a/pr-preview/pr-1071/assets/js/89486910.949b861e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7086],{41805:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/docs/components/overview.md","sourceDirName":"components","slug":"/components/overview","permalink":"/contrast/pr-preview/pr-1071/next/components/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/components/overview.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/next/troubleshooting"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/next/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},l=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(71789).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},71789:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/896da145.10df34fb.js b/pr-preview/pr-1071/assets/js/896da145.10df34fb.js deleted file mode 100644 index cb4b2a432b..0000000000 --- a/pr-preview/pr-1071/assets/js/896da145.10df34fb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1739],{57204:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"examples/index","title":"Examples","description":"","source":"@site/versioned_docs/version-0.7/examples/index.md","sourceDirName":"examples","slug":"/examples/","permalink":"/contrast/pr-preview/pr-1071/0.7/examples/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/examples/index.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto"}}');var s=n(74848),o=n(28453),c=n(44074);const i={},l="Examples",a={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"examples",children:"Examples"})}),"\n","\n",(0,s.jsx)(c.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>b});var r=n(96540),s=n(34164),o=n(45357),c=n(14783),i=n(97639);const l=["zero","one","two","few","many","other"];function a(e){return l.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:a(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:a(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function m(){const e=d();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=n(74848);function j(e){let{href:t,children:n}=e;return(0,g.jsx)(c.A,{href:t,className:(0,s.A)("card padding--lg",x.cardContainer),children:n})}function v(e){let{href:t,icon:n,title:r,description:o}=e;return(0,g.jsxs)(j,{href:t,children:[(0,g.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",x.cardTitle),title:r,children:[n," ",r]}),o&&(0,g.jsx)("p",{className:(0,s.A)("text--truncate",x.cardDescription),title:o,children:o})]})}function w(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,g.jsx)(v,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function y(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,g.jsx)(v,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function C(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(y,{item:t});case"category":return(0,g.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const n=(0,o.$S)();return(0,g.jsx)(b,{items:n.items,className:t})}function b(e){const{items:t,className:n}=e;if(!t)return(0,g.jsx)(N,{...e});const r=(0,o.d1)(t);return(0,g.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(C,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>i});var r=n(96540);const s={},o=r.createContext(s);function c(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/89a4f0ca.87c559a7.js b/pr-preview/pr-1071/assets/js/89a4f0ca.87c559a7.js deleted file mode 100644 index 88b357e406..0000000000 --- a/pr-preview/pr-1071/assets/js/89a4f0ca.87c559a7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4687],{78700:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/docs/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/next/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/basics/features.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/next/basics/security-benefits"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/install"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8bfc695a.a2c52c3f.js b/pr-preview/pr-1071/assets/js/8bfc695a.a2c52c3f.js deleted file mode 100644 index 0aebb3e17d..0000000000 --- a/pr-preview/pr-1071/assets/js/8bfc695a.a2c52c3f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7261],{52261:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-1.2/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/getting-started/install.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/basics/features"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/getting-started/cluster-setup"}}');var r=s(74848),a=s(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v1.2.0/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,s)=>{s.d(e,{R:()=>o,x:()=>i});var n=s(96540);const r={},a=n.createContext(r);function o(t){const e=n.useContext(a);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),n.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8c9a8791.b68218dc.js b/pr-preview/pr-1071/assets/js/8c9a8791.b68218dc.js deleted file mode 100644 index e037b9f919..0000000000 --- a/pr-preview/pr-1071/assets/js/8c9a8791.b68218dc.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5335],{20016:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-0.7/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/0.7/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/components/runtime.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Components","permalink":"/contrast/pr-preview/pr-1071/0.7/components/"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.7/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"<code>cloud-hypervisor</code> virtual machine manager (VMM)",id:"cloud-hypervisor-virtual-machine-manager-vmm",level:3},{value:"<code>Tardev snapshotter</code>",id:"tardev-snapshotter",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(85604).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"cloud-hypervisor-virtual-machine-manager-vmm",children:[(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," virtual machine manager (VMM)"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})})," to create a confidential virtual machine for every pod.\nThis requires the ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," binary to be installed on every node (responsibility of the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),")."]}),"\n",(0,i.jsx)(n.h3,{id:"tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"Tardev snapshotter"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses a special ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotter"]})," (",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})}),") to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},85604:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8dca39c2.4500e87f.js b/pr-preview/pr-1071/assets/js/8dca39c2.4500e87f.js deleted file mode 100644 index 0b5b7c50a1..0000000000 --- a/pr-preview/pr-1071/assets/js/8dca39c2.4500e87f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3116],{82489:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-0.5/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/basics/confidential-containers.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Contrast","permalink":"/contrast/pr-preview/pr-1071/0.5/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo Preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable, core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe guest VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo Preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/8ec58f4b.4a23bd26.js b/pr-preview/pr-1071/assets/js/8ec58f4b.4a23bd26.js deleted file mode 100644 index 08382bfe56..0000000000 --- a/pr-preview/pr-1071/assets/js/8ec58f4b.4a23bd26.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2506],{37802:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/versioned_docs/version-1.2/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/features-limitations.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/architecture/observability"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/about/telemetry"}}');var r=t(74848),s=t(28453);const a={},o="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2},{value:"Automatic recovery and high availability",id:"automatic-recovery-and-high-availability",level:2},{value:"Overriding Kata configuration",id:"overriding-kata-configuration",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,r.jsx)(n.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,r.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,r.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Bare-metal support"}),": Support for running ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/getting-started/bare-metal",children:"Contrast on bare-metal Kubernetes"})," is available for AMD SEV-SNP and Intel TDX."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Persistent volumes"}),": Contrast only supports volumes with ",(0,r.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode",children:(0,r.jsx)(n.code,{children:"volumeMode: Block"})}),". These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Port forwarding"}),": This feature ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,r.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,r.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,r.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Volume integrity checks"}),": Integrity checks don't cover any volume mounts, such as ",(0,r.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,r.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container, affect the service mesh implementation of Contrast.\nCurrently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,r.jsx)(n.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"automatic-recovery-and-high-availability",children:"Automatic recovery and high availability"}),"\n",(0,r.jsx)(n.p,{children:"The Contrast Coordinator is a singleton and can't be scaled to more than one instance.\nWhen this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually.\nIn a future release, we plan to support distributed Coordinator instances that can recover automatically."}),"\n",(0,r.jsx)(n.h2,{id:"overriding-kata-configuration",children:"Overriding Kata configuration"}),"\n",(0,r.jsxs)(n.p,{children:["Kata Containers supports ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/blob/b4da4b5e3b9b21048af9333b071235a57a3e9493/docs/how-to/how-to-set-sandbox-config-kata.md",children:"overriding certain configuration values via Kubernetes annotations"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"It needs to be noted that setting these values is unsupported, and doing so may lead to unexpected\nbehaviour, as Contrast isn't tested against all possible configuration combinations."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var i=t(96540);const r={},s=i.createContext(r);function a(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9040bbc8.74221d60.js b/pr-preview/pr-1071/assets/js/9040bbc8.74221d60.js deleted file mode 100644 index 8abfa627e8..0000000000 --- a/pr-preview/pr-1071/assets/js/9040bbc8.74221d60.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2453],{98935:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-1.0/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/examples/emojivoto.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/1.0/deployment"}}');var i=n(74848),s=n(28453);const a={},r="Confidential emoji voting",d={},l=[{value:"Motivation",id:"motivation",level:3},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Downloading the deployment",id:"downloading-the-deployment",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Voter's perspective: Verifying the ballot",id:"voters-perspective-verifying-the-ballot",level:2},{value:"Attest the Coordinator",id:"attest-the-coordinator",level:3},{value:"Manifest history and artifact audit",id:"manifest-history-and-artifact-audit",level:3},{value:"Confidential connection to the attested workload",id:"confidential-connection-to-the-attested-workload",level:3},{value:"Certificate SAN and manifest update (optional)",id:"certificate-san-and-manifest-update-optional",level:2},{value:"Configure the service SAN in the manifest",id:"configure-the-service-san-in-the-manifest",level:3},{value:"Update the manifest",id:"update-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(82463).A+"",width:"1503",height:"732"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,i.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voters perspective."]})}),"\n",(0,i.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,i.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,i.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,i.jsx)(t.code,{children:"voting"}),"). The ",(0,i.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,i.jsx)(t.h3,{id:"motivation",children:"Motivation"}),"\n",(0,i.jsx)(t.p,{children:"Using a voting service, users' votes are considered highly sensitive data, as we require\na secret ballot. Also, users are likely interested in the fairness of the ballot. For\nboth requirements, we can use Confidential Computing and, specifically, workload attestation\nto prove to those interested in voting that the app is running in a protected environment\nwhere their votes are processed without leaking to the platform provider or workload owner."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Installed Contrast CLI."}),"\nSee the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/getting-started/install",children:"installation instructions"})," on how to get it."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Running cluster with Confidential Containers support."}),"\nPlease follow the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup",children:"cluster setup instructions"}),"\nto create a cluster."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,i.jsx)(t.h3,{id:"downloading-the-deployment",children:"Downloading the deployment"}),"\n",(0,i.jsx)(t.p,{children:"The emojivoto deployment files are part of Contrast release. You can download the\nlatest deployment by running:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.0.0/emojivoto-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,i.jsxs)(t.p,{children:["Contrast depends on a ",(0,i.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:["custom Kubernetes ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," (",(0,i.jsx)(t.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,i.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/runtime.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.0.0/coordinator.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,i.jsxs)(t.p,{children:["Run the ",(0,i.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,i.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})}),"\n",(0,i.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,i.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,i.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/components/runtime",children:"runtime class"})," ",(0,i.jsx)(t.code,{children:"contrast-cc-<platform>-<runtime-hash>"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,i.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,i.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,i.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,i.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,i.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,i.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,i.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,i.jsx)(t.h2,{id:"voters-perspective-verifying-the-ballot",children:"Voter's perspective: Verifying the ballot"}),"\n",(0,i.jsx)(t.p,{children:"As voters, we want to verify the fairness and confidentiality of the deployment before\ndeciding to vote. Regardless of the scale of our distributed deployment, Contrast only\nneeds a single remote attestation step to verify the deployment. By doing remote attestation\nof the Coordinator, we transitively verify those systems the Coordinator has already attested\nor will attest in the future. Successful verification of the Coordinator means that\nwe can be sure it will enforce the configured manifest."}),"\n",(0,i.jsx)(t.h3,{id:"attest-the-coordinator",children:"Attest the Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"A potential voter can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The CLI will attest the Coordinator using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,i.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,i.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,i.jsx)(t.h3,{id:"manifest-history-and-artifact-audit",children:"Manifest history and artifact audit"}),"\n",(0,i.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,i.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,i.jsx)(t.h3,{id:"confidential-connection-to-the-attested-workload",children:"Confidential connection to the attested workload"}),"\n",(0,i.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, you can securely connect\nto the workloads using the Coordinator's ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,i.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,i.jsx)(t.h2,{id:"certificate-san-and-manifest-update-optional",children:"Certificate SAN and manifest update (optional)"}),"\n",(0,i.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,i.jsx)(t.h3,{id:"configure-the-service-san-in-the-manifest",children:"Configure the service SAN in the manifest"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,i.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,i.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {\n "SANs": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n "WorkloadSecretID": "web"\n },\n'})}),"\n",(0,i.jsx)(t.h3,{id:"update-the-manifest",children:"Update the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,i.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,i.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,i.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,i.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},82463:(e,t,n)=>{n.d(t,{A:()=>o});const o=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var o=n(96540);const i={},s=o.createContext(i);function a(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/90af0d0d.9fc28b24.js b/pr-preview/pr-1071/assets/js/90af0d0d.9fc28b24.js deleted file mode 100644 index 3820587fb1..0000000000 --- a/pr-preview/pr-1071/assets/js/90af0d0d.9fc28b24.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8921],{17170:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-0.6/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/0.6/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/components/runtime.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Components","permalink":"/contrast/pr-preview/pr-1071/0.6/components/"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.6/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"<code>cloud-hypervisor</code> virtual machine manager (VMM)",id:"cloud-hypervisor-virtual-machine-manager-vmm",level:3},{value:"<code>Tardev snapshotter</code>",id:"tardev-snapshotter",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(92791).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"cloud-hypervisor-virtual-machine-manager-vmm",children:[(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," virtual machine manager (VMM)"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})})," to create a confidential virtual machine for every pod.\nThis requires the ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," binary to be installed on every node (responsibility of the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),")."]}),"\n",(0,i.jsx)(n.h3,{id:"tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"Tardev snapshotter"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses a special ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotter"]})," (",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})}),") to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},92791:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/91456bd6.f04512d4.js b/pr-preview/pr-1071/assets/js/91456bd6.f04512d4.js deleted file mode 100644 index c9efdb5d8e..0000000000 --- a/pr-preview/pr-1071/assets/js/91456bd6.f04512d4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9366],{93287:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-1.2/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/basics/features.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/basics/security-benefits"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/getting-started/install"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9230b32a.873d5e8d.js b/pr-preview/pr-1071/assets/js/9230b32a.873d5e8d.js deleted file mode 100644 index 485aed7505..0000000000 --- a/pr-preview/pr-1071/assets/js/9230b32a.873d5e8d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5829],{39428:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.9","label":"0.9","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.9","isLast":false,"docsSidebars":{"docs":[{"type":"link","label":"What is Contrast?","href":"/contrast/pr-preview/pr-1071/0.9/","docId":"intro","unlisted":false},{"type":"category","label":"Basics","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/0.9/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/0.9/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false}],"collapsible":true},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/0.9/deployment","docId":"deployment","unlisted":false},{"type":"link","label":"Troubleshooting","href":"/contrast/pr-preview/pr-1071/0.9/troubleshooting","docId":"troubleshooting","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Overview","href":"/contrast/pr-preview/pr-1071/0.9/components/overview","docId":"components/overview","unlisted":false},{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/0.9/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/0.9/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/0.9/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/0.9/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Secrets & recovery","href":"/contrast/pr-preview/pr-1071/0.9/architecture/secrets","docId":"architecture/secrets","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/0.9/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/0.9/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/0.9/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/0.9/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"architecture/secrets":{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/overview":{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"troubleshooting":{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/927cf76e.29128aa9.js b/pr-preview/pr-1071/assets/js/927cf76e.29128aa9.js deleted file mode 100644 index 7c97156c4a..0000000000 --- a/pr-preview/pr-1071/assets/js/927cf76e.29128aa9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1226],{9902:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/docs/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/next/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/architecture/observability.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Security considerations","permalink":"/contrast/pr-preview/pr-1071/next/architecture/security-considerations"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/next/features-limitations"}}');var s=r(74848),i=r(28453);const o={},c="Observability",a={},d=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function h(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator exports gRPC metrics under the prefix ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_"}),".\nThese metrics are labeled with the gRPC service name and method name.\nMetrics of interest include ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handled_total"}),", which counts\nthe number of requests by return code, and\n",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handling_seconds_bucket"}),", which produces a histogram of",(0,s.jsx)(t.br,{}),"\n","request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["The gRPC service ",(0,s.jsx)(t.code,{children:"userapi.UserAPI"})," records metrics for the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"meshapi.MeshAPI"})," service records metrics for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"}),", which\ngets called by the ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures_total"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9397123b.8b60de82.js b/pr-preview/pr-1071/assets/js/9397123b.8b60de82.js deleted file mode 100644 index 442fdcd7f9..0000000000 --- a/pr-preview/pr-1071/assets/js/9397123b.8b60de82.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2941],{99845:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"architecture/attestation/manifest","title":"manifest","description":"","source":"@site/versioned_docs/version-0.5/architecture/attestation/manifest.md","sourceDirName":"architecture/attestation","slug":"/architecture/attestation/manifest","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/attestation/manifest.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime policies","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies"},"next":{"title":"Coordinator","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator"}}');var s=n(74848),o=n(28453);const i={},a=void 0,c={},u=[];function p(t){return(0,s.jsx)(s.Fragment,{})}function d(t={}){const{wrapper:e}={...(0,o.R)(),...t.components};return e?(0,s.jsx)(e,{...t,children:(0,s.jsx)(p,{...t})}):p()}},28453:(t,e,n)=>{n.d(e,{R:()=>i,x:()=>a});var r=n(96540);const s={},o=r.createContext(s);function i(t){const e=r.useContext(o);return r.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(s):t.components||s:i(t.components),r.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9620adf5.19a314c4.js b/pr-preview/pr-1071/assets/js/9620adf5.19a314c4.js deleted file mode 100644 index aa04d71773..0000000000 --- a/pr-preview/pr-1071/assets/js/9620adf5.19a314c4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[912],{81469:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-1.0/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/basics/security-benefits.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(25217).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(74745).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},74745:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},25217:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/966b9f47.06142c29.js b/pr-preview/pr-1071/assets/js/966b9f47.06142c29.js deleted file mode 100644 index 9e1fc65536..0000000000 --- a/pr-preview/pr-1071/assets/js/966b9f47.06142c29.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1112],{98525:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>i,default:()=>l,frontMatter:()=>s,metadata:()=>r,toc:()=>p});const r=JSON.parse('{"id":"architecture/components/cli","title":"cli","description":"","source":"@site/versioned_docs/version-0.5/architecture/components/cli.md","sourceDirName":"architecture/components","slug":"/architecture/components/cli","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/components/cli.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Init container","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container"},"next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers"}}');var o=n(74848),c=n(28453);const s={},i=void 0,a={},p=[];function u(t){return(0,o.jsx)(o.Fragment,{})}function l(t={}){const{wrapper:e}={...(0,c.R)(),...t.components};return e?(0,o.jsx)(e,{...t,children:(0,o.jsx)(u,{...t})}):u()}},28453:(t,e,n)=>{n.d(e,{R:()=>s,x:()=>i});var r=n(96540);const o={},c=r.createContext(o);function s(t){const e=r.useContext(c);return r.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:s(t.components),r.createElement(c.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/969019ea.13bd2248.js b/pr-preview/pr-1071/assets/js/969019ea.13bd2248.js deleted file mode 100644 index 2d9f4dc0f7..0000000000 --- a/pr-preview/pr-1071/assets/js/969019ea.13bd2248.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[485],{31424:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-1.1/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/1.1/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/components/service-mesh.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/1.1/components/policies"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/attestation"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"CONTRAST_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"CONTRAST_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"<name>#<port>#false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:"<name>"})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"<name>#<port>#true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: CONTRAST_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v1.1.1@sha256:5906c67f89afa7b79bc5e68df523f7f309adf2f66583e5f702ebbcf5545ef0d9"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-secrets\n mountPath: /contrast\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"<name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port>"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:"<name>"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9720.8e4604d2.js b/pr-preview/pr-1071/assets/js/9720.8e4604d2.js deleted file mode 100644 index 605afb06e2..0000000000 --- a/pr-preview/pr-1071/assets/js/9720.8e4604d2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9720],{39720:(c,e,s)=>{s.d(e,{createArchitectureServices:()=>t.S});var t=s(49936);s(19369)}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9732.545304f6.js b/pr-preview/pr-1071/assets/js/9732.545304f6.js deleted file mode 100644 index 849262739d..0000000000 --- a/pr-preview/pr-1071/assets/js/9732.545304f6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9732],{89732:(t,e,a)=>{a.d(e,{diagram:()=>L});var i,n=a(90758),r=(a(96474),a(87308),a(37938),a(1282),a(64532),a(47588),a(33115),a(10483),a(8159)),d=a(10009),s=a(20007),o=a(62334),g=a(697),c={},p=(0,d.K2)(((t,e)=>{c[t]=e}),"set"),h=(0,d.K2)((t=>c[t]),"get"),l=(0,d.K2)((()=>Object.keys(c)),"keys"),x=(0,d.K2)((()=>l().length),"size"),D={get:h,set:p,keys:l,size:x},u=(0,d.K2)((t=>t.append("circle").attr("class","start-state").attr("r",(0,d.D7)().state.sizeUnit).attr("cx",(0,d.D7)().state.padding+(0,d.D7)().state.sizeUnit).attr("cy",(0,d.D7)().state.padding+(0,d.D7)().state.sizeUnit)),"drawStartState"),f=(0,d.K2)((t=>t.append("line").style("stroke","grey").style("stroke-dasharray","3").attr("x1",(0,d.D7)().state.textHeight).attr("class","divider").attr("x2",2*(0,d.D7)().state.textHeight).attr("y1",0).attr("y2",0)),"drawDivider"),y=(0,d.K2)(((t,e)=>{const a=t.append("text").attr("x",2*(0,d.D7)().state.padding).attr("y",(0,d.D7)().state.textHeight+2*(0,d.D7)().state.padding).attr("font-size",(0,d.D7)().state.fontSize).attr("class","state-title").text(e.id),i=a.node().getBBox();return t.insert("rect",":first-child").attr("x",(0,d.D7)().state.padding).attr("y",(0,d.D7)().state.padding).attr("width",i.width+2*(0,d.D7)().state.padding).attr("height",i.height+2*(0,d.D7)().state.padding).attr("rx",(0,d.D7)().state.radius),a}),"drawSimpleState"),w=(0,d.K2)(((t,e)=>{const a=(0,d.K2)((function(t,e,a){const i=t.append("tspan").attr("x",2*(0,d.D7)().state.padding).text(e);a||i.attr("dy",(0,d.D7)().state.textHeight)}),"addTspan"),i=t.append("text").attr("x",2*(0,d.D7)().state.padding).attr("y",(0,d.D7)().state.textHeight+1.3*(0,d.D7)().state.padding).attr("font-size",(0,d.D7)().state.fontSize).attr("class","state-title").text(e.descriptions[0]).node().getBBox(),n=i.height,r=t.append("text").attr("x",(0,d.D7)().state.padding).attr("y",n+.4*(0,d.D7)().state.padding+(0,d.D7)().state.dividerMargin+(0,d.D7)().state.textHeight).attr("class","state-description");let s=!0,o=!0;e.descriptions.forEach((function(t){s||(a(r,t,o),o=!1),s=!1}));const g=t.append("line").attr("x1",(0,d.D7)().state.padding).attr("y1",(0,d.D7)().state.padding+n+(0,d.D7)().state.dividerMargin/2).attr("y2",(0,d.D7)().state.padding+n+(0,d.D7)().state.dividerMargin/2).attr("class","descr-divider"),c=r.node().getBBox(),p=Math.max(c.width,i.width);return g.attr("x2",p+3*(0,d.D7)().state.padding),t.insert("rect",":first-child").attr("x",(0,d.D7)().state.padding).attr("y",(0,d.D7)().state.padding).attr("width",p+2*(0,d.D7)().state.padding).attr("height",c.height+n+2*(0,d.D7)().state.padding).attr("rx",(0,d.D7)().state.radius),t}),"drawDescrState"),m=(0,d.K2)(((t,e,a)=>{const i=(0,d.D7)().state.padding,n=2*(0,d.D7)().state.padding,r=t.node().getBBox(),s=r.width,o=r.x,g=t.append("text").attr("x",0).attr("y",(0,d.D7)().state.titleShift).attr("font-size",(0,d.D7)().state.fontSize).attr("class","state-title").text(e.id),c=g.node().getBBox().width+n;let p,h=Math.max(c,s);h===s&&(h+=n);const l=t.node().getBBox();e.doc,p=o-i,c>s&&(p=(s-h)/2+i),Math.abs(o-l.x)<i&&c>s&&(p=o-(c-s)/2);const x=1-(0,d.D7)().state.textHeight;return t.insert("rect",":first-child").attr("x",p).attr("y",x).attr("class",a?"alt-composit":"composit").attr("width",h).attr("height",l.height+(0,d.D7)().state.textHeight+(0,d.D7)().state.titleShift+1).attr("rx","0"),g.attr("x",p+i),c<=s&&g.attr("x",o+(h-n)/2-c/2+i),t.insert("rect",":first-child").attr("x",p).attr("y",(0,d.D7)().state.titleShift-(0,d.D7)().state.textHeight-(0,d.D7)().state.padding).attr("width",h).attr("height",3*(0,d.D7)().state.textHeight).attr("rx",(0,d.D7)().state.radius),t.insert("rect",":first-child").attr("x",p).attr("y",(0,d.D7)().state.titleShift-(0,d.D7)().state.textHeight-(0,d.D7)().state.padding).attr("width",h).attr("height",l.height+3+2*(0,d.D7)().state.textHeight).attr("rx",(0,d.D7)().state.radius),t}),"addTitleAndBox"),b=(0,d.K2)((t=>(t.append("circle").attr("class","end-state-outer").attr("r",(0,d.D7)().state.sizeUnit+(0,d.D7)().state.miniPadding).attr("cx",(0,d.D7)().state.padding+(0,d.D7)().state.sizeUnit+(0,d.D7)().state.miniPadding).attr("cy",(0,d.D7)().state.padding+(0,d.D7)().state.sizeUnit+(0,d.D7)().state.miniPadding),t.append("circle").attr("class","end-state-inner").attr("r",(0,d.D7)().state.sizeUnit).attr("cx",(0,d.D7)().state.padding+(0,d.D7)().state.sizeUnit+2).attr("cy",(0,d.D7)().state.padding+(0,d.D7)().state.sizeUnit+2))),"drawEndState"),B=(0,d.K2)(((t,e)=>{let a=(0,d.D7)().state.forkWidth,i=(0,d.D7)().state.forkHeight;if(e.parentId){let t=a;a=i,i=t}return t.append("rect").style("stroke","black").style("fill","black").attr("width",a).attr("height",i).attr("x",(0,d.D7)().state.padding).attr("y",(0,d.D7)().state.padding)}),"drawForkJoinState"),k=(0,d.K2)(((t,e,a,i)=>{let n=0;const r=i.append("text");r.style("text-anchor","start"),r.attr("class","noteText");let s=t.replace(/\r\n/g,"<br/>");s=s.replace(/\n/g,"<br/>");const o=s.split(d.Y2.lineBreakRegex);let g=1.25*(0,d.D7)().state.noteMargin;for(const c of o){const t=c.trim();if(t.length>0){const i=r.append("tspan");if(i.text(t),0===g){g+=i.node().getBBox().height}n+=g,i.attr("x",e+(0,d.D7)().state.noteMargin),i.attr("y",a+n+1.25*(0,d.D7)().state.noteMargin)}}return{textWidth:r.node().getBBox().width,textHeight:n}}),"_drawLongText"),S=(0,d.K2)(((t,e)=>{e.attr("class","state-note");const a=e.append("rect").attr("x",0).attr("y",(0,d.D7)().state.padding),i=e.append("g"),{textWidth:n,textHeight:r}=k(t,0,0,i);return a.attr("height",r+2*(0,d.D7)().state.noteMargin),a.attr("width",n+2*(0,d.D7)().state.noteMargin),a}),"drawNote"),N=(0,d.K2)((function(t,e){const a=e.id,i={id:a,label:e.id,width:0,height:0},n=t.append("g").attr("id",a).attr("class","stateGroup");"start"===e.type&&u(n),"end"===e.type&&b(n),"fork"!==e.type&&"join"!==e.type||B(n,e),"note"===e.type&&S(e.note.text,n),"divider"===e.type&&f(n),"default"===e.type&&0===e.descriptions.length&&y(n,e),"default"===e.type&&e.descriptions.length>0&&w(n,e);const r=n.node().getBBox();return i.width=r.width+2*(0,d.D7)().state.padding,i.height=r.height+2*(0,d.D7)().state.padding,D.set(a,i),i}),"drawState"),E=0,K=(0,d.K2)((function(t,e,a){const i=(0,d.K2)((function(t){switch(t){case n.iP.relationType.AGGREGATION:return"aggregation";case n.iP.relationType.EXTENSION:return"extension";case n.iP.relationType.COMPOSITION:return"composition";case n.iP.relationType.DEPENDENCY:return"dependency"}}),"getRelationType");e.points=e.points.filter((t=>!Number.isNaN(t.y)));const o=e.points,g=(0,s.n8j)().x((function(t){return t.x})).y((function(t){return t.y})).curve(s.qrM),c=t.append("path").attr("d",g(o)).attr("id","edge"+E).attr("class","transition");let p="";if((0,d.D7)().state.arrowMarkerAbsolute&&(p=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,p=p.replace(/\(/g,"\\("),p=p.replace(/\)/g,"\\)")),c.attr("marker-end","url("+p+"#"+i(n.iP.relationType.DEPENDENCY)+"End)"),void 0!==a.title){const i=t.append("g").attr("class","stateLabel"),{x:n,y:s}=r._K.calcLabelPosition(e.points),o=d.Y2.getRows(a.title);let g=0;const c=[];let p=0,h=0;for(let t=0;t<=o.length;t++){const e=i.append("text").attr("text-anchor","middle").text(o[t]).attr("x",n).attr("y",s+g),a=e.node().getBBox();if(p=Math.max(p,a.width),h=Math.min(h,a.x),d.Rm.info(a.x,n,s+g),0===g){const t=e.node().getBBox();g=t.height,d.Rm.info("Title height",g,s)}c.push(e)}let l=g*o.length;if(o.length>1){const t=(o.length-1)*g*.5;c.forEach(((e,a)=>e.attr("y",s+a*g-t))),l=g*o.length}const x=i.node().getBBox();i.insert("rect",":first-child").attr("class","box").attr("x",n-p/2-(0,d.D7)().state.padding/2).attr("y",s-l/2-(0,d.D7)().state.padding/2-3.5).attr("width",p+(0,d.D7)().state.padding).attr("height",l+(0,d.D7)().state.padding),d.Rm.info(x)}E++}),"drawEdge"),M={},v=(0,d.K2)((function(){}),"setConf"),R=(0,d.K2)((function(t){t.append("defs").append("marker").attr("id","dependencyEnd").attr("refX",19).attr("refY",7).attr("markerWidth",20).attr("markerHeight",28).attr("orient","auto").append("path").attr("d","M 19,7 L9,13 L14,7 L9,1 Z")}),"insertMarkers"),z=(0,d.K2)((function(t,e,a,n){i=(0,d.D7)().state;const r=(0,d.D7)().securityLevel;let o;"sandbox"===r&&(o=(0,s.Ltv)("#i"+e));const g="sandbox"===r?(0,s.Ltv)(o.nodes()[0].contentDocument.body):(0,s.Ltv)("body"),c="sandbox"===r?o.nodes()[0].contentDocument:document;d.Rm.debug("Rendering diagram "+t);const p=g.select(`[id='${e}']`);R(p);const h=n.db.getRootDoc();T(h,p,void 0,!1,g,c,n);const l=i.padding,x=p.node().getBBox(),D=x.width+2*l,u=x.height+2*l,f=1.75*D;(0,d.a$)(p,u,f,i.useMaxWidth),p.attr("viewBox",`${x.x-i.padding} ${x.y-i.padding} `+D+" "+u)}),"draw"),H=(0,d.K2)((t=>t?t.length*i.fontSizeFactor:1),"getLabelWidth"),T=(0,d.K2)(((t,e,a,n,r,s,c)=>{const p=new g.T({compound:!0,multigraph:!0});let h,l=!0;for(h=0;h<t.length;h++)if("relation"===t[h].stmt){l=!1;break}a?p.setGraph({rankdir:"LR",multigraph:!0,compound:!0,ranker:"tight-tree",ranksep:l?1:i.edgeLengthFactor,nodeSep:l?1:50,isMultiGraph:!0}):p.setGraph({rankdir:"TB",multigraph:!0,compound:!0,ranksep:l?1:i.edgeLengthFactor,nodeSep:l?1:50,ranker:"tight-tree",isMultiGraph:!0}),p.setDefaultEdgeLabel((function(){return{}})),c.db.extract(t);const x=c.db.getStates(),D=c.db.getRelations(),u=Object.keys(x);for(const d of u){const t=x[d];let o;if(a&&(t.parentId=a),t.doc){let a=e.append("g").attr("id",t.id).attr("class","stateGroup");o=T(t.doc,a,t.id,!n,r,s,c);{a=m(a,t,n);let e=a.node().getBBox();o.width=e.width,o.height=e.height+i.padding/2,M[t.id]={y:i.compositTitleSize}}}else o=N(e,t,p);if(t.note){const a={descriptions:[],id:t.id+"-note",note:t.note,type:"note"},i=N(e,a,p);"left of"===t.note.position?(p.setNode(o.id+"-note",i),p.setNode(o.id,o)):(p.setNode(o.id,o),p.setNode(o.id+"-note",i)),p.setParent(o.id,o.id+"-group"),p.setParent(o.id+"-note",o.id+"-group")}else p.setNode(o.id,o)}d.Rm.debug("Count=",p.nodeCount(),p);let f=0;D.forEach((function(t){f++,d.Rm.debug("Setting edge",t),p.setEdge(t.id1,t.id2,{relation:t,width:H(t.title),height:i.labelHeight*d.Y2.getRows(t.title).length,labelpos:"c"},"id"+f)})),(0,o.Zp)(p),d.Rm.debug("Graph after layout",p.nodes());const y=e.node();p.nodes().forEach((function(t){if(void 0!==t&&void 0!==p.node(t)){d.Rm.warn("Node "+t+": "+JSON.stringify(p.node(t))),r.select("#"+y.id+" #"+t).attr("transform","translate("+(p.node(t).x-p.node(t).width/2)+","+(p.node(t).y+(M[t]?M[t].y:0)-p.node(t).height/2)+" )"),r.select("#"+y.id+" #"+t).attr("data-x-shift",p.node(t).x-p.node(t).width/2);s.querySelectorAll("#"+y.id+" #"+t+" .divider").forEach((t=>{const e=t.parentElement;let a=0,i=0;e&&(e.parentElement&&(a=e.parentElement.getBBox().width),i=parseInt(e.getAttribute("data-x-shift"),10),Number.isNaN(i)&&(i=0)),t.setAttribute("x1",0-i+8),t.setAttribute("x2",a-i-8)}))}else d.Rm.debug("No Node "+t+": "+JSON.stringify(p.node(t)))}));let w=y.getBBox();p.edges().forEach((function(t){void 0!==t&&void 0!==p.edge(t)&&(d.Rm.debug("Edge "+t.v+" -> "+t.w+": "+JSON.stringify(p.edge(t))),K(e,p.edge(t),p.edge(t).relation))})),w=y.getBBox();const b={id:a||"root",label:a||"root",width:0,height:0};return b.width=w.width+2*i.padding,b.height=w.height+2*i.padding,d.Rm.debug("Doc rendered",b,p),b}),"renderDoc"),P={setConf:v,draw:z},L={parser:n.Zk,db:n.iP,renderer:P,styles:n.tM,init:(0,d.K2)((t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute,n.iP.clear()}),"init")}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/98367cce.a60fe698.js b/pr-preview/pr-1071/assets/js/98367cce.a60fe698.js deleted file mode 100644 index 5ff3b0b849..0000000000 --- a/pr-preview/pr-1071/assets/js/98367cce.a60fe698.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[133],{71663:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-0.8/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/basics/security-benefits.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.8/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(47262).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(95300).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},95300:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},47262:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/989c6d03.9f3aeec7.js b/pr-preview/pr-1071/assets/js/989c6d03.9f3aeec7.js deleted file mode 100644 index a9411dc932..0000000000 --- a/pr-preview/pr-1071/assets/js/989c6d03.9f3aeec7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[782],{91122:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/docs/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/next/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/components/policies.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/next/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/next/components/service-mesh"}}');var s=n(74848),r=n(28453);const o={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2},{value:"Platform Differences",id:"platform-differences",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," or TDX ",(0,s.jsx)(t.code,{children:"MRCONFIGID"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," or ",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,s.jsx)(t.code,{children:"MRCONFIGID"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."}),"\n",(0,s.jsx)(t.h2,{id:"platform-differences",children:"Platform Differences"}),"\n",(0,s.jsx)(t.p,{children:"Contrast uses different rules and data sections for different platforms.\nThis results in different policy hashes for different platforms."}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"generate"})," command automatically derives the correct set of rules and data sections from the ",(0,s.jsx)(t.code,{children:"reference-values"})," flag."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"verify"}),", ",(0,s.jsx)(t.code,{children:"set"}),", and ",(0,s.jsx)(t.code,{children:"recover"})," commands need to know the coordinator's expected policy hash to verify its identity.\nBy default these commands assume that the coordinator is using the policy for the ",(0,s.jsx)(t.code,{children:"AKS-CLH-SNP"})," platform.\nIf the coordinator is running on a different platform, the correct policy hash can be looked up in the ",(0,s.jsx)(t.code,{children:"coordinator-policy.hash"})," file bundled with the ",(0,s.jsx)(t.a,{href:"https://github.com/edgelesssys/contrast/releases",children:"Contrast release"}),".\nThe coordinator policy hash can be overwritten using the ",(0,s.jsx)(t.code,{children:"--coordinator-policy-hash"})," flag."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const s={},r=i.createContext(s);function o(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9a06ae3d.46bdaeb7.js b/pr-preview/pr-1071/assets/js/9a06ae3d.46bdaeb7.js deleted file mode 100644 index d33984e696..0000000000 --- a/pr-preview/pr-1071/assets/js/9a06ae3d.46bdaeb7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2912],{56704:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>t,toc:()=>l});const t=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/docs/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/getting-started/cluster-setup.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/install"},"next":{"title":"Bare metal setup","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal"}}');var s=r(74848),a=r(28453);const o={},i="Create a cluster",c={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,s.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Install version 2.44.1 or newer of the ",(0,s.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),". Note that your package manager will likely install an outdated version."]}),"\n",(0,s.jsxs)(n.li,{children:["Install a recent version of ",(0,s.jsx)(n.a,{href:"https://kubernetes.io/docs/tasks/tools/",children:"kubectl"}),"."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,s.jsx)(n.p,{children:"First, log in to your Azure subscription:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,s.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,s.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,s.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,s.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,s.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,s.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,s.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,s.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,s.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,s.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,s.jsx)(n.p,{children:"First, create a CoCo enabled AKS cluster with:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.30 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,s.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,s.jsxs)(n.p,{children:["For validation, list the available nodes using ",(0,s.jsx)(n.code,{children:"kubectl"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,s.jsx)(n.p,{children:"It should show a single node:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\n"})}),"\n",(0,s.jsxs)(n.p,{children:["\ud83e\udd73 Congratulations. You're now ready to set up your first application with Contrast. Follow this ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/examples/emojivoto",children:"example"})," to learn how."]}),"\n",(0,s.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,s.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,s.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,s.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>i});var t=r(96540);const s={},a=t.createContext(s);function o(e){const n=t.useContext(a);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9a28f5c4.4a20392f.js b/pr-preview/pr-1071/assets/js/9a28f5c4.4a20392f.js deleted file mode 100644 index 4862372747..0000000000 --- a/pr-preview/pr-1071/assets/js/9a28f5c4.4a20392f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3505],{99764:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-0.9/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/examples/emojivoto.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.9/deployment"}}');var i=n(74848),s=n(28453);const a={},r="Confidential emoji voting",d={},l=[{value:"Motivation",id:"motivation",level:3},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Downloading the deployment",id:"downloading-the-deployment",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Voter's perspective: Verifying the ballot",id:"voters-perspective-verifying-the-ballot",level:2},{value:"Attest the Coordinator",id:"attest-the-coordinator",level:3},{value:"Manifest history and artifact audit",id:"manifest-history-and-artifact-audit",level:3},{value:"Confidential connection to the attested workload",id:"confidential-connection-to-the-attested-workload",level:3},{value:"Certificate SAN and manifest update (optional)",id:"certificate-san-and-manifest-update-optional",level:2},{value:"Configure the service SAN in the manifest",id:"configure-the-service-san-in-the-manifest",level:3},{value:"Update the manifest",id:"update-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(2115).A+"",width:"1503",height:"732"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,i.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voters perspective."]})}),"\n",(0,i.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,i.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,i.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,i.jsx)(t.code,{children:"voting"}),"). The ",(0,i.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,i.jsx)(t.h3,{id:"motivation",children:"Motivation"}),"\n",(0,i.jsx)(t.p,{children:"Using a voting service, users' votes are considered highly sensitive data, as we require\na secret ballot. Also, users are likely interested in the fairness of the ballot. For\nboth requirements, we can use Confidential Computing and, specifically, workload attestation\nto prove to those interested in voting that the app is running in a protected environment\nwhere their votes are processed without leaking to the platform provider or workload owner."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Installed Contrast CLI."}),"\nSee the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/getting-started/install",children:"installation instructions"})," on how to get it."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Running cluster with Confidential Containers support."}),"\nPlease follow the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup",children:"cluster setup instructions"}),"\nto create a cluster."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,i.jsx)(t.h3,{id:"downloading-the-deployment",children:"Downloading the deployment"}),"\n",(0,i.jsx)(t.p,{children:"The emojivoto deployment files are part of Contrast release. You can download the\nlatest deployment by running:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v0.9.0/emojivoto-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,i.jsxs)(t.p,{children:["Contrast depends on a ",(0,i.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/runtime",children:["custom Kubernetes ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," (",(0,i.jsx)(t.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,i.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/runtime.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.9.0/coordinator.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,i.jsxs)(t.p,{children:["Run the ",(0,i.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,i.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})}),"\n",(0,i.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,i.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,i.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/components/runtime",children:"runtime class"})," ",(0,i.jsx)(t.code,{children:"contrast-cc-<platform>-<runtime-hash>"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,i.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,i.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,i.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,i.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,i.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,i.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,i.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,i.jsx)(t.h2,{id:"voters-perspective-verifying-the-ballot",children:"Voter's perspective: Verifying the ballot"}),"\n",(0,i.jsx)(t.p,{children:"As voters, we want to verify the fairness and confidentiality of the deployment before\ndeciding to vote. Regardless of the scale of our distributed deployment, Contrast only\nneeds a single remote attestation step to verify the deployment. By doing remote attestation\nof the Coordinator, we transitively verify those systems the Coordinator has already attested\nor will attest in the future. Successful verification of the Coordinator means that\nwe can be sure it will enforce the configured manifest."}),"\n",(0,i.jsx)(t.h3,{id:"attest-the-coordinator",children:"Attest the Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"A potential voter can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The CLI will attest the Coordinator using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,i.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,i.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,i.jsx)(t.h3,{id:"manifest-history-and-artifact-audit",children:"Manifest history and artifact audit"}),"\n",(0,i.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,i.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,i.jsx)(t.h3,{id:"confidential-connection-to-the-attested-workload",children:"Confidential connection to the attested workload"}),"\n",(0,i.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, you can securely connect\nto the workloads using the Coordinator's ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,i.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,i.jsx)(t.h2,{id:"certificate-san-and-manifest-update-optional",children:"Certificate SAN and manifest update (optional)"}),"\n",(0,i.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,i.jsx)(t.h3,{id:"configure-the-service-san-in-the-manifest",children:"Configure the service SAN in the manifest"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,i.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,i.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n'})}),"\n",(0,i.jsx)(t.h3,{id:"update-the-manifest",children:"Update the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,i.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,i.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,i.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,i.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},2115:(e,t,n)=>{n.d(t,{A:()=>o});const o=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var o=n(96540);const i={},s=o.createContext(i);function a(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9a99019d.eb40f802.js b/pr-preview/pr-1071/assets/js/9a99019d.eb40f802.js deleted file mode 100644 index ef2e7ee5b3..0000000000 --- a/pr-preview/pr-1071/assets/js/9a99019d.eb40f802.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[801],{89293:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-0.7/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/0.7/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/intro.md","tags":[],"version":"0.7","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/getting-started/",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9c6eeb97.6972f46b.js b/pr-preview/pr-1071/assets/js/9c6eeb97.6972f46b.js deleted file mode 100644 index 3c4ab3b0ce..0000000000 --- a/pr-preview/pr-1071/assets/js/9c6eeb97.6972f46b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9377],{97063:t=>{t.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Attestation","slug":"/category/attestation","permalink":"/contrast/pr-preview/pr-1071/0.5/category/attestation","sidebar":"docs","navigation":{"previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers"},"next":{"title":"Hardware","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9ccb1fc6.c7393c04.js b/pr-preview/pr-1071/assets/js/9ccb1fc6.c7393c04.js deleted file mode 100644 index b7e8643ea8..0000000000 --- a/pr-preview/pr-1071/assets/js/9ccb1fc6.c7393c04.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9874],{65339:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-0.8/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/0.8/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/components/runtime.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/0.8/components/overview"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.8/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"<code>cloud-hypervisor</code> virtual machine manager (VMM)",id:"cloud-hypervisor-virtual-machine-manager-vmm",level:3},{value:"<code>Tardev snapshotter</code>",id:"tardev-snapshotter",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(24261).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsxs)(n.h3,{id:"cloud-hypervisor-virtual-machine-manager-vmm",children:[(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," virtual machine manager (VMM)"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})})," to create a confidential virtual machine for every pod.\nThis requires the ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," binary to be installed on every node (responsibility of the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),")."]}),"\n",(0,i.jsx)(n.h3,{id:"tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"Tardev snapshotter"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses a special ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotter"]})," (",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})}),") to provide container images as block devices to the pod-VM. This snapshotter consists of a host component that pulls container images and a guest component (kernel module) used to mount container images.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},24261:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9ce1fd56.a07cbd12.js b/pr-preview/pr-1071/assets/js/9ce1fd56.a07cbd12.js deleted file mode 100644 index 27fc8b8408..0000000000 --- a/pr-preview/pr-1071/assets/js/9ce1fd56.a07cbd12.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[426],{42809:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-0.8/components/overview.md","sourceDirName":"components","slug":"/components/overview","permalink":"/contrast/pr-preview/pr-1071/0.8/components/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/components/overview.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/0.8/troubleshooting"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.8/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},l=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(91175).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},91175:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9d9e06f4.f7d4f664.js b/pr-preview/pr-1071/assets/js/9d9e06f4.f7d4f664.js deleted file mode 100644 index 0a4604792e..0000000000 --- a/pr-preview/pr-1071/assets/js/9d9e06f4.f7d4f664.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4670],{12325:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>n,toc:()=>u});const n=JSON.parse('{"id":"architecture/index","title":"Architecture","description":"","source":"@site/versioned_docs/version-0.5/architecture/index.md","sourceDirName":"architecture","slug":"/architecture/","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/index.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.5/deployment"},"next":{"title":"Components","permalink":"/contrast/pr-preview/pr-1071/0.5/category/components"}}');var c=r(74848),s=r(28453),o=r(44074);const i={},a="Architecture",l={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,s.R)(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(t.header,{children:(0,c.jsx)(t.h1,{id:"architecture",children:"Architecture"})}),"\n","\n",(0,c.jsx)(o.A,{})]})}function m(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(d,{...e})}):d(e)}},44074:(e,t,r)=>{r.d(t,{A:()=>C});var n=r(96540),c=r(34164),s=r(45357),o=r(14783),i=r(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function m(){const e=d();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const c=r.select(t),s=r.pluralForms.indexOf(c);return n[Math.min(s,n.length-1)]}(r,t,e)}}var h=r(40877),p=r(23230),f=r(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=r(74848);function j(e){let{href:t,children:r}=e;return(0,g.jsx)(o.A,{href:t,className:(0,c.A)("card padding--lg",x.cardContainer),children:r})}function v(e){let{href:t,icon:r,title:n,description:s}=e;return(0,g.jsxs)(j,{href:t,children:[(0,g.jsxs)(f.A,{as:"h2",className:(0,c.A)("text--truncate",x.cardTitle),title:n,children:[r," ",n]}),s&&(0,g.jsx)("p",{className:(0,c.A)("text--truncate",x.cardDescription),title:s,children:s})]})}function w(e){let{item:t}=e;const r=(0,s.Nr)(t),n=function(){const{selectMessage:e}=m();return t=>e(t,(0,p.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return r?(0,g.jsx)(v,{href:r,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??n(t.items.length)}):null}function y(e){let{item:t}=e;const r=(0,h.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",n=(0,s.cC)(t.docId??void 0);return(0,g.jsx)(v,{href:t.href,icon:r,title:t.label,description:t.description??n?.description})}function A(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(y,{item:t});case"category":return(0,g.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function k(e){let{className:t}=e;const r=(0,s.$S)();return(0,g.jsx)(C,{items:r.items,className:t})}function C(e){const{items:t,className:r}=e;if(!t)return(0,g.jsx)(k,{...e});const n=(0,s.d1)(t);return(0,g.jsx)("section",{className:(0,c.A)("row",r),children:n.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(A,{item:e})},t)))})}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>i});var n=r(96540);const c={},s=n.createContext(c);function o(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:o(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/9d9f8394.beb73e2b.js b/pr-preview/pr-1071/assets/js/9d9f8394.beb73e2b.js deleted file mode 100644 index 6d335604a6..0000000000 --- a/pr-preview/pr-1071/assets/js/9d9f8394.beb73e2b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9013],{42245:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","source":"@site/docs/troubleshooting.md","sourceDirName":".","slug":"/troubleshooting","permalink":"/contrast/pr-preview/pr-1071/next/troubleshooting","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/troubleshooting.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/next/deployment"},"next":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/next/components/overview"}}');var i=t(74848),s=t(28453);const a={},r="Troubleshooting",c={},l=[{value:"Logging",id:"logging",level:2},{value:"CLI",id:"cli",level:3},{value:"Coordinator and Initializer",id:"coordinator-and-initializer",level:3},{value:"Pod fails to start",id:"pod-fails-to-start",level:2},{value:"Regenerating the policies",id:"regenerating-the-policies",level:3},{value:"Pin container images",id:"pin-container-images",level:3},{value:"Validate Contrast components match",id:"validate-contrast-components-match",level:3}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"troubleshooting",children:"Troubleshooting"})}),"\n",(0,i.jsx)(n.p,{children:"This section contains information on how to debug your Contrast deployment."}),"\n",(0,i.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,i.jsx)(n.p,{children:"Collecting logs can be a good first step to identify problems in your\ndeployment. Both the CLI and the Contrast Coordinator as well as the Initializer\ncan be configured to emit additional logs."}),"\n",(0,i.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,i.jsxs)(n.p,{children:["The CLI logs can be configured with the ",(0,i.jsx)(n.code,{children:"--log-level"})," command-line flag, which\ncan be set to either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"})," or ",(0,i.jsx)(n.code,{children:"error"}),". The default is ",(0,i.jsx)(n.code,{children:"info"}),".\nSetting this to ",(0,i.jsx)(n.code,{children:"debug"})," can get more fine-grained information as to where the\nproblem lies."]}),"\n",(0,i.jsx)(n.h3,{id:"coordinator-and-initializer",children:"Coordinator and Initializer"}),"\n",(0,i.jsxs)(n.p,{children:["The logs from the Coordinator and the Initializer can be configured via the\nenvironment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"}),", ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," and\n",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"})," can be set to one of either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"}),", or\n",(0,i.jsx)(n.code,{children:"error"}),", similar to the CLI (defaults to ",(0,i.jsx)(n.code,{children:"info"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," can be set to ",(0,i.jsx)(n.code,{children:"text"})," or ",(0,i.jsx)(n.code,{children:"json"}),", determining the output\nformat (defaults to ",(0,i.jsx)(n.code,{children:"text"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," is a comma-separated list of subsystems that should\nbe enabled for logging, which are disabled by default. Subsystems include:\n",(0,i.jsx)(n.code,{children:"kds-getter"}),", ",(0,i.jsx)(n.code,{children:"issuer"})," and ",(0,i.jsx)(n.code,{children:"validator"}),".\nTo enable all subsystems, use ",(0,i.jsx)(n.code,{children:"*"})," as the value for this environment variable.\nWarnings and error messages from subsystems get printed regardless of whether\nthe subsystem is listed in the ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," environment variable."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"To configure debug logging with all subsystems for your Coordinator, add the\nfollowing variables to your container definition."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n containers:\n image: "ghcr.io/edgelesssys/contrast/coordinator:latest"\n name: coordinator\n env:\n - name: CONTRAST_LOG_LEVEL\n value: debug\n - name: CONTRAST_LOG_SUBSYSTEMS\n value: "*"\n # ...\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["While the Contrast Coordinator has a policy that allows certain configurations,\nthe Initializer and service mesh don't. When changing environment variables of other\nparts than the Coordinator, ensure to rerun ",(0,i.jsx)(n.code,{children:"contrast generate"})," to update the policy."]})}),"\n",(0,i.jsxs)(n.p,{children:["To access the logs generated by the Coordinator, you can use ",(0,i.jsx)(n.code,{children:"kubectl"})," with the\nfollowing command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl logs <coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.h2,{id:"pod-fails-to-start",children:"Pod fails to start"}),"\n",(0,i.jsxs)(n.p,{children:["If the Coordinator or a workload pod fails to even start, it can be helpful to\nlook at the events of the pod during the startup process using the ",(0,i.jsx)(n.code,{children:"describe"}),"\ncommand."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> events --for pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"Example output:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'LAST SEEN TYPE REASON OBJECT MESSAGE\n32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...\n'})}),"\n",(0,i.jsx)(n.p,{children:"A common error, as in this example, is that the container creation was blocked by the\npolicy. Potential reasons are a modification of the deployment YAML without updating\nthe policies afterward, or a version mismatch between Contrast components."}),"\n",(0,i.jsx)(n.h3,{id:"regenerating-the-policies",children:"Regenerating the policies"}),"\n",(0,i.jsx)(n.p,{children:"To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated\npolicies, rerun"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast generate\n"})}),"\n",(0,i.jsx)(n.p,{children:"on your deployment. If any of the policy annotations change, re-deploy with the updated policies."}),"\n",(0,i.jsx)(n.h3,{id:"pin-container-images",children:"Pin container images"}),"\n",(0,i.jsx)(n.p,{children:"When generating the policies, Contrast will download the images specified in your deployment\nYAML and include their cryptographic identity. If the image tag is moved to another\ncontainer image after the policy has been generated, the image downloaded at deploy time\nwill differ from the one at generation time, and the policy enforcement won't allow the\ncontainer to be started in the pod VM."}),"\n",(0,i.jsxs)(n.p,{children:["To ensure the correct image is always used, pin the container image to a fixed ",(0,i.jsx)(n.code,{children:"sha256"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This way, the same image will still be pulled when the container tag (",(0,i.jsx)(n.code,{children:"22.04"}),") is moved\nto another image."]}),"\n",(0,i.jsx)(n.h3,{id:"validate-contrast-components-match",children:"Validate Contrast components match"}),"\n",(0,i.jsx)(n.p,{children:"A version mismatch between Contrast components can cause policy validation or attestation\nto fail. Each Contrast runtime is identifiable based on its (shortened) measurement value\nused to name the runtime class version."}),"\n",(0,i.jsx)(n.p,{children:"First, analyze which runtime class is currently installed in your cluster by running"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl get runtimeclasses\n"})}),"\n",(0,i.jsx)(n.p,{children:"This should give you output similar to the following one."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"NAME HANDLER AGE\ncontrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h\nkata-cc-isolation kata-cc 45d\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided\nby the AKS CoCo preview, which isn't used by Contrast)."}),"\n",(0,i.jsx)(n.p,{children:"Next, check if the pod that won't start has the correct runtime class configured, and the\nCoordinator uses the exact same runtime:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>\nkubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output should list the runtime class the pod is using:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast-cc-aks-clh-snp-7173acb5\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Version information about the currently used CLI can be obtained via the ",(0,i.jsx)(n.code,{children:"version"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast --version\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast version v0.X.0\n\n runtime handler: contrast-cc-aks-clh-snp-7173acb5\n launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35\n genpolicy version: 3.2.0.azl1.genpolicy0\n image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...\n ghcr.io/edgelesssys/contrast/initializer@sha256:...\n"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(96540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a0a1fd3b.c8af1d49.js b/pr-preview/pr-1071/assets/js/a0a1fd3b.c8af1d49.js deleted file mode 100644 index ca5491fe37..0000000000 --- a/pr-preview/pr-1071/assets/js/a0a1fd3b.c8af1d49.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6755],{92395:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-1.1/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/getting-started/install.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/1.1/basics/features"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup"}}');var r=s(74848),a=s(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v1.1.1/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,s)=>{s.d(e,{R:()=>o,x:()=>i});var n=s(96540);const r={},a=n.createContext(r);function o(t){const e=n.useContext(a);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),n.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a0a4ec6e.a242125e.js b/pr-preview/pr-1071/assets/js/a0a4ec6e.a242125e.js deleted file mode 100644 index bee1169dfc..0000000000 --- a/pr-preview/pr-1071/assets/js/a0a4ec6e.a242125e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4980],{48542:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/versioned_docs/version-0.8/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/examples/emojivoto.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.8/deployment"}}');var i=n(74848),s=n(28453);const a={},r="Confidential emoji voting",d={},l=[{value:"Motivation",id:"motivation",level:3},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Downloading the deployment",id:"downloading-the-deployment",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Voter's perspective: Verifying the ballot",id:"voters-perspective-verifying-the-ballot",level:2},{value:"Attest the Coordinator",id:"attest-the-coordinator",level:3},{value:"Manifest history and artifact audit",id:"manifest-history-and-artifact-audit",level:3},{value:"Confidential connection to the attested workload",id:"confidential-connection-to-the-attested-workload",level:3},{value:"Certificate SAN and manifest update (optional)",id:"certificate-san-and-manifest-update-optional",level:2},{value:"Configure the service SAN in the manifest",id:"configure-the-service-san-in-the-manifest",level:3},{value:"Update the manifest",id:"update-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(88616).A+"",width:"1503",height:"732"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,i.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voters perspective."]})}),"\n",(0,i.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,i.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,i.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,i.jsx)(t.code,{children:"voting"}),"). The ",(0,i.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,i.jsx)(t.h3,{id:"motivation",children:"Motivation"}),"\n",(0,i.jsx)(t.p,{children:"Using a voting service, users' votes are considered highly sensitive data, as we require\na secret ballot. Also, users are likely interested in the fairness of the ballot. For\nboth requirements, we can use Confidential Computing and, specifically, workload attestation\nto prove to those interested in voting that the app is running in a protected environment\nwhere their votes are processed without leaking to the platform provider or workload owner."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Installed Contrast CLI."}),"\nSee the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/getting-started/install",children:"installation instructions"})," on how to get it."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Running cluster with Confidential Containers support."}),"\nPlease follow the ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup",children:"cluster setup instructions"}),"\nto create a cluster."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,i.jsx)(t.h3,{id:"downloading-the-deployment",children:"Downloading the deployment"}),"\n",(0,i.jsx)(t.p,{children:"The emojivoto deployment files are part of Contrast release. You can download the\nlatest deployment by running:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v0.8.1/emojivoto-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,i.jsxs)(t.p,{children:["Contrast depends on a ",(0,i.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:["custom Kubernetes ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," (",(0,i.jsx)(t.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,i.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,i.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/runtime.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/coordinator.yml\n"})}),"\n",(0,i.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,i.jsxs)(t.p,{children:["Run the ",(0,i.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,i.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})}),"\n",(0,i.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,i.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,i.jsx)(t.a,{href:"https://docs.edgeless.systems/contrast/components/runtime",children:"runtime class"})," ",(0,i.jsx)(t.code,{children:"contrast-cc-<VERSIONHASH>"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,i.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,i.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,i.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,i.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,i.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,i.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,i.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,i.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,i.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,i.jsx)(t.h2,{id:"voters-perspective-verifying-the-ballot",children:"Voter's perspective: Verifying the ballot"}),"\n",(0,i.jsx)(t.p,{children:"As voters, we want to verify the fairness and confidentiality of the deployment before\ndeciding to vote. Regardless of the scale of our distributed deployment, Contrast only\nneeds a single remote attestation step to verify the deployment. By doing remote attestation\nof the Coordinator, we transitively verify those systems the Coordinator has already attested\nor will attest in the future. Successful verification of the Coordinator means that\nwe can be sure it will enforce the configured manifest."}),"\n",(0,i.jsx)(t.h3,{id:"attest-the-coordinator",children:"Attest the Coordinator"}),"\n",(0,i.jsx)(t.p,{children:"A potential voter can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The CLI will attest the Coordinator using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,i.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,i.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,i.jsx)(t.h3,{id:"manifest-history-and-artifact-audit",children:"Manifest history and artifact audit"}),"\n",(0,i.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,i.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,i.jsx)(t.h3,{id:"confidential-connection-to-the-attested-workload",children:"Confidential connection to the attested workload"}),"\n",(0,i.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, you can securely connect\nto the workloads using the Coordinator's ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,i.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,i.jsx)(t.h2,{id:"certificate-san-and-manifest-update-optional",children:"Certificate SAN and manifest update (optional)"}),"\n",(0,i.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,i.jsx)(t.h3,{id:"configure-the-service-san-in-the-manifest",children:"Configure the service SAN in the manifest"}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,i.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,i.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n'})}),"\n",(0,i.jsx)(t.h3,{id:"update-the-manifest",children:"Update the manifest"}),"\n",(0,i.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,i.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,i.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,i.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,i.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,i.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,i.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},88616:(e,t,n)=>{n.d(t,{A:()=>o});const o=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var o=n(96540);const i={},s=o.createContext(i);function a(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a161c24f.b698442f.js b/pr-preview/pr-1071/assets/js/a161c24f.b698442f.js deleted file mode 100644 index b3cf08b099..0000000000 --- a/pr-preview/pr-1071/assets/js/a161c24f.b698442f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1575],{82560:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the bundle from the URL you received:","source":"@site/versioned_docs/version-0.5/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/getting-started/install.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Getting started","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup"}}');var r=n(74848),a=n(28453);const o={},l="Installation",i={},c=[];function d(e){const t={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components},{TabItem:n,Tabs:s}=t;return n||u("TabItem",!0),s||u("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsxs)(s,{groupId:"method",queryString:!0,children:[(0,r.jsxs)(n,{value:"private-preview",label:"Private preview bundle",children:[(0,r.jsx)(t.p,{children:"Download the bundle from the URL you received:"}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"curl -fLO <URL>\n"})}),(0,r.jsx)(t.p,{children:"Then unpack the unpack the downloaded archive:"}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"unzip contrast.zip\n"})})]}),(0,r.jsxs)(n,{value:"release",label:"Release",children:[(0,r.jsx)(t.p,{children:"Download the Contrast CLI from the latest release:"}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"curl -fLo contrast https://github.com/edgelesssys/contrast/releases/latest/download/contrast\n"})})]})]}),"\n",(0,r.jsx)(t.p,{children:"Install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"mv contrast /usr/local/bin/contrast\n"})})]})}function p(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function u(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>l});var s=n(96540);const r={},a=s.createContext(r);function o(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a2899f6e.1e5e2cad.js b/pr-preview/pr-1071/assets/js/a2899f6e.1e5e2cad.js deleted file mode 100644 index 82bfe237e6..0000000000 --- a/pr-preview/pr-1071/assets/js/a2899f6e.1e5e2cad.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1861],{51866:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>i});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-1.0/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/getting-started/cluster-setup.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/1.0/getting-started/install"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto"}}');var t=r(74848),a=r(28453);const o={},c="Create a cluster",l={},i=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.p,{children:["Install the latest version of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli",children:"Login to your account"}),", which needs\nto have the permissions to create an AKS cluster, by executing:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a\nnon-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool."}),"\n",(0,t.jsx)(n.p,{children:"We'll first start by creating the non-CoCo cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.29 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"We then add a second node pool with CoCo support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool add \\\n --resource-group "${azResourceGroup:?}" \\\n --name nodepool2 \\\n --cluster-name "${azClusterName:?}" \\\n --node-count 1 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation\n'})}),"\n",(0,t.jsx)(n.p,{children:"Optionally, we can now remove the non-CoCo node pool:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool delete \\\n --resource-group "${azResourceGroup:?}" \\\n --cluster-name "${azClusterName:?}" \\\n --name nodepool1\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"For validation, list the available nodes using kubectl:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show two nodes:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\naks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>c});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a3713279.46fb5390.js b/pr-preview/pr-1071/assets/js/a3713279.46fb5390.js deleted file mode 100644 index fca6576b03..0000000000 --- a/pr-preview/pr-1071/assets/js/a3713279.46fb5390.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9588],{33745:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/docs/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/next/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/deployment.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Encrypted volume mount","permalink":"/contrast/pr-preview/pr-1071/next/examples/mysql"},"next":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/next/troubleshooting"}}');var r=t(74848),a=t(28453);const i={},o="Workload deployment",l={},c=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"Security review",id:"security-review",level:3},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2},{value:"Recover the Coordinator",id:"recover-the-coordinator",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components},{TabItem:t,Tabs:s}=n;return t||u("TabItem",!0),s||u("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,r.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup",children:"setup guide"})," on how to set up a cluster on AKS."]})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal",children:"setup guide"})," on how to set up a bare-metal cluster."]})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal",children:"setup guide"})," on how to set up a bare-metal cluster."]})})]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast depends on a ",(0,r.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:["custom Kubernetes ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," (",(0,r.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,r.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-aks-clh-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-aks-clh-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,r.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,r.jsx)(n.h3,{id:"security-review",children:"Security review"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast ensures integrity and confidentiality of the applications, but interactions with untrusted systems require the developers' attention.\nReview the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/security-considerations",children:"security considerations"})," and the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates",children:"certificates"})," section for writing secure Contrast application."]}),"\n",(0,r.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,r.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,r.jsxs)(s,{groupId:"yaml-source",children:[(0,r.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"helm",label:"helm",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"copy",label:"copy",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,r.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,r.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,r.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,r.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,r.jsxs)(n.p,{children:["In the initialization process, the ",(0,r.jsx)(n.code,{children:"contrast-secrets"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,r.jsxs)(s,{groupId:"tls",children:[(0,r.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,r.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,r.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,r.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,r.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,r.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,r.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,r.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,r.jsxs)(n.p,{children:["During the ",(0,r.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,r.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,r.jsxs)(t,{value:"go",label:"Go integration",children:[(0,r.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,r.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,r.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,r.jsxs)(s,{groupId:"golang-tls-setup",children:[(0,r.jsx)(t,{value:"client",label:"Client",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,r.jsx)(t,{value:"server",label:"Server",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/contrast/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/contrast/tls-config/certChain.pem", "/contrast/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(n.p,{children:["Run the ",(0,r.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,r.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp resources/\n"})})}),(0,r.jsxs)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp resources/\n"})}),(0,r.jsx)(n.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(n.p,{children:["On bare-metal SEV-SNP, ",(0,r.jsx)(n.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(n.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(n.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,r.jsxs)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx resources/\n"})}),(0,r.jsx)(n.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(n.p,{children:["On bare-metal TDX, ",(0,r.jsx)(n.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(n.code,{children:"MinimumTeeTcbSvn"})," and ",(0,r.jsx)(n.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(n.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,r.jsx)(n.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,r.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,r.jsxs)(s,{groupId:"injection",children:[(0,r.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,r.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,r.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,r.jsx)(n.code,{children:"generate"})," command."]}),(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(t,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp --skip-initializer resources/\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp --skip-initializer resources/\n"})})}),(0,r.jsx)(t,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx --skip-initializer resources/\n"})})})]})]}),(0,r.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,r.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,r.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,r.jsx)(n.code,{children:"contrast-secrets"})," ",(0,r.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:latest"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /contrast\n name: contrast-secrets\n volumes:\n - emptyDir: {}\n name: contrast-secrets\n'})}),"\n",(0,r.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,r.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,r.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,r.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,r.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,r.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,r.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,r.jsx)(n.p,{children:"This will use the reference values from the manifest file to attest the Coordinator.\nAfter this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,r.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,r.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the\nservice mesh root certificate and the history of manifests into the ",(0,r.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies\nreferenced in the active manifest are also written to the directory. The verification will fail if the active\nmanifest at the Coordinator doesn't match the manifest passed to the CLI."]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,r.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,r.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, attempting to connect with curl and the mesh CA certificate will throw the following error:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,r.jsxs)(n.p,{children:["Using ",(0,r.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,r.jsx)(n.h2,{id:"recover-the-coordinator",children:"Recover the Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material.\nFor demonstration purposes, you can simulate this scenario by deleting the Coordinator pod."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl delete pod -l app.kubernetes.io/name=coordinator\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet.\nYou can confirm this by running ",(0,r.jsx)(n.code,{children:"verify"})," again, or you can restart a workload pod, which should stay in the initialization phase.\nHowever, the secret seed in your working directory is sufficient to recover the coordinator."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast recover -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsx)(n.p,{children:"Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state.\nYou can now verify the Coordinator again, which should return the same manifest you set before."}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The recovery process invalidates the mesh CA certificate:\nexisting workloads won't be able to communicate with workloads newly spawned.\nAll workloads should be restarted after the recovery succeeded."})}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["On bare metal, the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(n.code,{children:"--coordinator-policy-hash"}),"."]})})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function u(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>o});var s=t(96540);const r={},a=s.createContext(r);function i(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a66d714b.813b3c04.js b/pr-preview/pr-1071/assets/js/a66d714b.813b3c04.js deleted file mode 100644 index ef6fbe9cb1..0000000000 --- a/pr-preview/pr-1071/assets/js/a66d714b.813b3c04.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9974],{91304:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});const r=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-0.8/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/0.8/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/deployment.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto"},"next":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/0.8/troubleshooting"}}');var o=t(74848),s=t(28453);const i={},a="Workload deployment",c={},l=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2},{value:"Recover the Coordinator",id:"recover-the-coordinator",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components},{TabItem:t,Tabs:r}=n;return t||p("TabItem",!0),r||p("Tabs",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.header,{children:(0,o.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,o.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,o.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup",children:"setup guide"})," on how to set it up."]}),"\n",(0,o.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,o.jsxs)(n.p,{children:["Contrast depends on a ",(0,o.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/runtime",children:["custom Kubernetes ",(0,o.jsx)(n.code,{children:"RuntimeClass"})," (",(0,o.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,o.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,o.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/runtime.yml\n"})}),"\n",(0,o.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.8.1/coordinator.yml\n"})}),"\n",(0,o.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,o.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,o.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,o.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,o.jsxs)(r,{groupId:"yaml-source",children:[(0,o.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,o.jsx)(t,{value:"helm",label:"helm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,o.jsx)(t,{value:"copy",label:"copy",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,o.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,o.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,o.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,o.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,o.jsxs)(n.p,{children:["In the initialization process, the ",(0,o.jsx)(n.code,{children:"contrast-tls-certs"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,o.jsxs)(r,{groupId:"tls",children:[(0,o.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,o.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,o.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,o.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,o.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,o.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,o.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,o.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,o.jsxs)(n.p,{children:["During the ",(0,o.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,o.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,o.jsxs)(t,{value:"go",label:"Go integration",children:[(0,o.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,o.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,o.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,o.jsxs)(r,{groupId:"golang-tls-setup",children:[(0,o.jsx)(t,{value:"client",label:"Client",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,o.jsx)(t,{value:"server",label:"Server",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,o.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,o.jsxs)(n.p,{children:["Run the ",(0,o.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,o.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,o.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp resources/\n"})}),"\n",(0,o.jsx)(n.admonition,{type:"warning",children:(0,o.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,o.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,o.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,o.jsxs)(r,{groupId:"injection",children:[(0,o.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,o.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,o.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,o.jsx)(n.code,{children:"generate"})," command."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp --skip-initializer resources/\n"})})]}),(0,o.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,o.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,o.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,o.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,o.jsx)(n.code,{children:"contrast-tls-certs"})," ",(0,o.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:v0.8.1@sha256:6260af0b4ee2b5e583970aaa74ba6f5cbaa4d2029bc2aef947987d2398f1164f"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /tls-config\n name: contrast-tls-certs\n volumes:\n - emptyDir: {}\n name: contrast-tls-certs\n'})}),"\n",(0,o.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,o.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,o.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,o.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,o.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,o.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,o.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,o.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,o.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,o.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,o.jsx)(n.p,{children:"This will use the reference values from the manifest file to attest the Coordinator.\nAfter this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,o.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,o.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,o.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,o.jsxs)(n.p,{children:["The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the\nservice mesh root certificate and the history of manifests into the ",(0,o.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies\nreferenced in the active manifest are also written to the directory. The verification will fail if the active\nmanifest at the Coordinator doesn't match the manifest passed to the CLI."]}),"\n",(0,o.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,o.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,o.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,o.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,o.jsxs)(n.p,{children:["Using ",(0,o.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,o.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,o.jsx)(n.h2,{id:"recover-the-coordinator",children:"Recover the Coordinator"}),"\n",(0,o.jsx)(n.p,{children:"If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material.\nFor demonstration purposes, you can simulate this scenario by deleting the Coordinator pod."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:"kubectl delete pod -l app.kubernetes.io/name=coordinator\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet.\nYou can confirm this by running ",(0,o.jsx)(n.code,{children:"verify"})," again, or you can restart a workload pod, which should stay in the initialization phase.\nHowever, the secret seed in your working directory is sufficient to recover the coordinator."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'contrast recover -c "${coordinator}:1313"\n'})}),"\n",(0,o.jsx)(n.p,{children:"Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state.\nYou can now verify the Coordinator again, which should return the same manifest you set before."}),"\n",(0,o.jsx)(n.admonition,{type:"warning",children:(0,o.jsx)(n.p,{children:"The recovery process invalidates the mesh CA certificate:\nexisting workloads won't be able to communicate with workloads newly spawned.\nAll workloads should be restarted after the recovery succeeded."})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}function p(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>a});var r=t(96540);const o={},s=r.createContext(o);function i(e){const n=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),r.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a71cbd8f.85849cbe.js b/pr-preview/pr-1071/assets/js/a71cbd8f.85849cbe.js deleted file mode 100644 index d00d60d947..0000000000 --- a/pr-preview/pr-1071/assets/js/a71cbd8f.85849cbe.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5003],{91238:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","source":"@site/versioned_docs/version-0.8/architecture/secrets.md","sourceDirName":"architecture","slug":"/architecture/secrets","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/secrets","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/architecture/secrets.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/attestation"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/certificates"}}');var i=r(74848),n=r(28453);const o={},a="Secrets & recovery",c={},d=[{value:"Persistence",id:"persistence",level:2},{value:"Recovery",id:"recovery",level:2}];function h(e){const t={code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,n.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.header,{children:(0,i.jsx)(t.h1,{id:"secrets--recovery",children:"Secrets & recovery"})}),"\n",(0,i.jsx)(t.p,{children:"When the Coordinator is configured with the initial manifest, it generates a random secret seed.\nFrom this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history.\nThis derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state."}),"\n",(0,i.jsxs)(t.p,{children:["The secret seed is returned to the user on the first call to ",(0,i.jsx)(t.code,{children:"contrast set"}),", encrypted with the user's public seed share owner key.\nIf no seed share owner key is provided, a key is generated and stored in the working directory."]}),"\n",(0,i.jsx)(t.h2,{id:"persistence",children:"Persistence"}),"\n",(0,i.jsxs)(t.p,{children:["The Coordinator runs as a ",(0,i.jsx)(t.code,{children:"StatefulSet"})," with a dynamically provisioned persistent volume.\nThis volume stores the manifest history and the associated runtime policies.\nThe manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads.\nHowever, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users.\nThus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed."]}),"\n",(0,i.jsx)(t.h2,{id:"recovery",children:"Recovery"}),"\n",(0,i.jsxs)(t.p,{children:["When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests.\nIt needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures.\nThis procedure is called recovery and is initiated by the workload owner.\nThe CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the ",(0,i.jsx)(t.code,{children:"Recover"})," method.\nThe Coordinator recovers its key material and verifies the manifest history signature."]})]})}function u(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>a});var s=r(96540);const i={},n=s.createContext(i);function o(e){const t=s.useContext(n);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(n.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a7bd4aaa.59fbdee5.js b/pr-preview/pr-1071/assets/js/a7bd4aaa.59fbdee5.js deleted file mode 100644 index 6bfa53347b..0000000000 --- a/pr-preview/pr-1071/assets/js/a7bd4aaa.59fbdee5.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7098],{22881:(n,s,e)=>{e.r(s),e.d(s,{default:()=>d});e(96540);var r=e(69817),o=e(73718),t=e(91704),c=e(22831),i=e(51210),a=e(74848);function u(n){const{version:s}=n;return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(i.A,{version:s.version,tag:(0,o.k)(s.pluginId,s.version)}),(0,a.jsx)(r.be,{children:s.noIndex&&(0,a.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})]})}function l(n){const{version:s,route:e}=n;return(0,a.jsx)(r.e3,{className:s.className,children:(0,a.jsx)(t.n,{version:s,children:(0,c.v)(e.routes)})})}function d(n){return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(u,{...n}),(0,a.jsx)(l,{...n})]})}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a86a94ce.1fdc663f.js b/pr-preview/pr-1071/assets/js/a86a94ce.1fdc663f.js deleted file mode 100644 index 34ebc4d2d1..0000000000 --- a/pr-preview/pr-1071/assets/js/a86a94ce.1fdc663f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[212],{55850:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-1.1/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/1.1/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/about/telemetry.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/1.1/features-limitations"}}');var r=n(74848),o=n(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a92f10fb.7eb02298.js b/pr-preview/pr-1071/assets/js/a92f10fb.7eb02298.js deleted file mode 100644 index 3e5d6abc82..0000000000 --- a/pr-preview/pr-1071/assets/js/a92f10fb.7eb02298.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5806],{94203:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-1.2/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/basics/confidential-containers.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"What is Contrast?","permalink":"/contrast/pr-preview/pr-1071/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/a94703ab.5e2b26dd.js b/pr-preview/pr-1071/assets/js/a94703ab.5e2b26dd.js deleted file mode 100644 index abce163732..0000000000 --- a/pr-preview/pr-1071/assets/js/a94703ab.5e2b26dd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9048],{88001:(e,t,n)=>{n.r(t),n.d(t,{default:()=>pe});var a=n(96540),o=n(34164),i=n(69817),s=n(18630),l=n(45357),r=n(20040),c=n(23230),d=n(24245),u=n(54067);const m={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};var b=n(74848);function h(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),i=(0,a.useRef)(!1),{startScroll:s,cancelScroll:l}=(0,d.gk)();return(0,d.Mq)(((e,n)=>{let{scrollY:a}=e;const s=n?.scrollY;s&&(i.current?i.current=!1:a>=s?(l(),o(!1)):a<t?o(!1):a+window.innerHeight<document.documentElement.scrollHeight&&o(!0))})),(0,u.$)((e=>{e.location.hash&&(i.current=!0,o(!1))})),{shown:n,scrollToTop:()=>s(0)}}({threshold:300});return(0,b.jsx)("button",{"aria-label":(0,c.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.A)("clean-btn",s.G.common.backToTopButton,m.backToTopButton,e&&m.backToTopButtonShow),type:"button",onClick:t})}var p=n(36350),x=n(56347),f=n(82216),j=n(86957),v=n(20020);function _(e){return(0,b.jsx)("svg",{width:"20",height:"20","aria-hidden":"true",...e,children:(0,b.jsxs)("g",{fill:"#7a7a7a",children:[(0,b.jsx)("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),(0,b.jsx)("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})]})})}const g="collapseSidebarButton_PEFL",A="collapseSidebarButtonIcon_kv0_";function C(e){let{onClick:t}=e;return(0,b.jsx)("button",{type:"button",title:(0,c.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.A)("button button--secondary button--outline",g),onClick:t,children:(0,b.jsx)(_,{className:A})})}var k=n(40002),S=n(4799);const T=Symbol("EmptyContext"),N=a.createContext(T);function I(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),i=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return(0,b.jsx)(N.Provider,{value:i,children:t})}var y=n(94549),B=n(80260),w=n(14783),L=n(11062);function E(e){let{collapsed:t,categoryLabel:n,onClick:a}=e;return(0,b.jsx)("button",{"aria-label":t?(0,c.T)({id:"theme.DocSidebarItem.expandCategoryAriaLabel",message:"Expand sidebar category '{label}'",description:"The ARIA label to expand the sidebar category"},{label:n}):(0,c.T)({id:"theme.DocSidebarItem.collapseCategoryAriaLabel",message:"Collapse sidebar category '{label}'",description:"The ARIA label to collapse the sidebar category"},{label:n}),"aria-expanded":!t,type:"button",className:"clean-btn menu__caret",onClick:a})}function M(e){let{item:t,onItemClick:n,activePath:i,level:r,index:c,...d}=e;const{items:u,label:m,collapsible:h,className:p,href:x}=t,{docs:{sidebar:{autoCollapseCategories:f}}}=(0,j.p)(),v=function(e){const t=(0,L.A)();return(0,a.useMemo)((()=>e.href&&!e.linkUnlisted?e.href:!t&&e.collapsible?(0,l.Nr)(e):void 0),[e,t])}(t),_=(0,l.w8)(t,i),g=(0,B.ys)(x,i),{collapsed:A,setCollapsed:C}=(0,y.u)({initialState:()=>!!h&&(!_&&t.collapsed)}),{expandedItem:k,setExpandedItem:I}=function(){const e=(0,a.useContext)(N);if(e===T)throw new S.dV("DocSidebarItemsExpandedStateProvider");return e}(),M=function(e){void 0===e&&(e=!A),I(e?null:c),C(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const i=(0,S.ZC)(t);(0,a.useEffect)((()=>{t&&!i&&n&&o(!1)}),[t,i,n,o])}({isActive:_,collapsed:A,updateCollapsed:M}),(0,a.useEffect)((()=>{h&&null!=k&&k!==c&&f&&C(!0)}),[h,k,c,C,f]),(0,b.jsxs)("li",{className:(0,o.A)(s.G.docs.docSidebarItemCategory,s.G.docs.docSidebarItemCategoryLevel(r),"menu__list-item",{"menu__list-item--collapsed":A},p),children:[(0,b.jsxs)("div",{className:(0,o.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":g}),children:[(0,b.jsx)(w.A,{className:(0,o.A)("menu__link",{"menu__link--sublist":h,"menu__link--sublist-caret":!x&&h,"menu__link--active":_}),onClick:h?e=>{n?.(t),x?M(!1):(e.preventDefault(),M())}:()=>{n?.(t)},"aria-current":g?"page":void 0,role:h&&!x?"button":void 0,"aria-expanded":h&&!x?!A:void 0,href:h?v??"#":v,...d,children:m}),x&&h&&(0,b.jsx)(E,{collapsed:A,categoryLabel:m,onClick:e=>{e.preventDefault(),M()}})]}),(0,b.jsx)(y.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:A,children:(0,b.jsx)(V,{items:u,tabIndex:A?-1:0,onItemClick:n,activePath:i,level:r+1})})]})}var H=n(40877),G=n(90716);const P="menuExternalLink_NmtK";function R(e){let{item:t,onItemClick:n,activePath:a,level:i,index:r,...c}=e;const{href:d,label:u,className:m,autoAddBaseUrl:h}=t,p=(0,l.w8)(t,a),x=(0,H.A)(d);return(0,b.jsx)("li",{className:(0,o.A)(s.G.docs.docSidebarItemLink,s.G.docs.docSidebarItemLinkLevel(i),"menu__list-item",m),children:(0,b.jsxs)(w.A,{className:(0,o.A)("menu__link",!x&&P,{"menu__link--active":p}),autoAddBaseUrl:h,"aria-current":p?"page":void 0,to:d,...x&&{onClick:n?()=>n(t):void 0},...c,children:[u,!x&&(0,b.jsx)(G.A,{})]})},u)}const W="menuHtmlItem_M9Kj";function D(e){let{item:t,level:n,index:a}=e;const{value:i,defaultStyle:l,className:r}=t;return(0,b.jsx)("li",{className:(0,o.A)(s.G.docs.docSidebarItemLink,s.G.docs.docSidebarItemLinkLevel(n),l&&[W,"menu__list-item"],r),dangerouslySetInnerHTML:{__html:i}},a)}function F(e){let{item:t,...n}=e;switch(t.type){case"category":return(0,b.jsx)(M,{item:t,...n});case"html":return(0,b.jsx)(D,{item:t,...n});default:return(0,b.jsx)(R,{item:t,...n})}}function U(e){let{items:t,...n}=e;const a=(0,l.Y)(t,n.activePath);return(0,b.jsx)(I,{children:a.map(((e,t)=>(0,b.jsx)(F,{item:e,index:t,...n},t)))})}const V=(0,a.memo)(U),Y="menu_SIkG",K="menuWithAnnouncementBar_GW3s";function z(e){let{path:t,sidebar:n,className:i}=e;const l=function(){const{isActive:e}=(0,k.M)(),[t,n]=(0,a.useState)(e);return(0,d.Mq)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return(0,b.jsx)("nav",{"aria-label":(0,c.T)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.A)("menu thin-scrollbar",Y,l&&K,i),children:(0,b.jsx)("ul",{className:(0,o.A)(s.G.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(V,{items:n,activePath:t,level:1})})})}const q="sidebar_njMd",O="sidebarWithHideableNavbar_wUlq",J="sidebarHidden_VK0M",Q="sidebarLogo_isFc";function X(e){let{path:t,sidebar:n,onCollapse:a,isHidden:i}=e;const{navbar:{hideOnScroll:s},docs:{sidebar:{hideable:l}}}=(0,j.p)();return(0,b.jsxs)("div",{className:(0,o.A)(q,s&&O,i&&J),children:[s&&(0,b.jsx)(v.A,{tabIndex:-1,className:Q}),(0,b.jsx)(z,{path:t,sidebar:n}),l&&(0,b.jsx)(C,{onClick:a})]})}const Z=a.memo(X);var $=n(70763),ee=n(61938);const te=e=>{let{sidebar:t,path:n}=e;const a=(0,ee.M)();return(0,b.jsx)("ul",{className:(0,o.A)(s.G.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(V,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&a.toggle(),"link"===e.type&&a.toggle()},level:1})})};function ne(e){return(0,b.jsx)($.GX,{component:te,props:e})}const ae=a.memo(ne);function oe(e){const t=(0,f.l)(),n="desktop"===t||"ssr"===t,a="mobile"===t;return(0,b.jsxs)(b.Fragment,{children:[n&&(0,b.jsx)(Z,{...e}),a&&(0,b.jsx)(ae,{...e})]})}const ie={expandButton:"expandButton_TmdG",expandButtonIcon:"expandButtonIcon_i1dp"};function se(e){let{toggleSidebar:t}=e;return(0,b.jsx)("div",{className:ie.expandButton,title:(0,c.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t,children:(0,b.jsx)(_,{className:ie.expandButtonIcon})})}const le={docSidebarContainer:"docSidebarContainer_YfHR",docSidebarContainerHidden:"docSidebarContainerHidden_DPk8",sidebarViewport:"sidebarViewport_aRkj"};function re(e){let{children:t}=e;const n=(0,r.t)();return(0,b.jsx)(a.Fragment,{children:t},n?.name??"noSidebar")}function ce(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:i}=e;const{pathname:l}=(0,x.zy)(),[r,c]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{r&&c(!1),!r&&(0,p.O)()&&c(!0),i((e=>!e))}),[i,r]);return(0,b.jsx)("aside",{className:(0,o.A)(s.G.docs.docSidebarContainer,le.docSidebarContainer,n&&le.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(le.docSidebarContainer)&&n&&c(!0)},children:(0,b.jsx)(re,{children:(0,b.jsxs)("div",{className:(0,o.A)(le.sidebarViewport,r&&le.sidebarViewportHidden),children:[(0,b.jsx)(oe,{sidebar:t,path:l,onCollapse:d,isHidden:r}),r&&(0,b.jsx)(se,{toggleSidebar:d})]})})})}const de={docMainContainer:"docMainContainer_TBSr",docMainContainerEnhanced:"docMainContainerEnhanced_lQrH",docItemWrapperEnhanced:"docItemWrapperEnhanced_JWYK"};function ue(e){let{hiddenSidebarContainer:t,children:n}=e;const a=(0,r.t)();return(0,b.jsx)("main",{className:(0,o.A)(de.docMainContainer,(t||!a)&&de.docMainContainerEnhanced),children:(0,b.jsx)("div",{className:(0,o.A)("container padding-top--md padding-bottom--lg",de.docItemWrapper,t&&de.docItemWrapperEnhanced),children:n})})}const me={docRoot:"docRoot_UBD9",docsWrapper:"docsWrapper_hBAB"};function be(e){let{children:t}=e;const n=(0,r.t)(),[o,i]=(0,a.useState)(!1);return(0,b.jsxs)("div",{className:me.docsWrapper,children:[(0,b.jsx)(h,{}),(0,b.jsxs)("div",{className:me.docRoot,children:[n&&(0,b.jsx)(ce,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:i}),(0,b.jsx)(ue,{hiddenSidebarContainer:o,children:t})]})]})}var he=n(83510);function pe(e){const t=(0,l.B5)(e);if(!t)return(0,b.jsx)(he.A,{});const{docElement:n,sidebarName:a,sidebarItems:c}=t;return(0,b.jsx)(i.e3,{className:(0,o.A)(s.G.page.docsDocPage),children:(0,b.jsx)(r.V,{name:a,items:c,children:(0,b.jsx)(be,{children:n})})})}},83510:(e,t,n)=>{n.d(t,{A:()=>l});n(96540);var a=n(34164),o=n(23230),i=n(85225),s=n(74848);function l(e){let{className:t}=e;return(0,s.jsx)("main",{className:(0,a.A)("container margin-vert--xl",t),children:(0,s.jsx)("div",{className:"row",children:(0,s.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,s.jsx)(i.A,{as:"h1",className:"hero__title",children:(0,s.jsx)(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/aa0f7abf.fbffcf0c.js b/pr-preview/pr-1071/assets/js/aa0f7abf.fbffcf0c.js deleted file mode 100644 index 3d7929608b..0000000000 --- a/pr-preview/pr-1071/assets/js/aa0f7abf.fbffcf0c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8295],{40593:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>n,toc:()=>u});const n=JSON.parse('{"id":"architecture/index","title":"Architecture","description":"","source":"@site/versioned_docs/version-0.7/architecture/index.md","sourceDirName":"architecture","slug":"/architecture/","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/architecture/index.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.7/components/service-mesh"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/attestation"}}');var c=r(74848),s=r(28453),o=r(44074);const i={},a="Architecture",l={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,s.R)(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(t.header,{children:(0,c.jsx)(t.h1,{id:"architecture",children:"Architecture"})}),"\n","\n",(0,c.jsx)(o.A,{})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(d,{...e})}):d(e)}},44074:(e,t,r)=>{r.d(t,{A:()=>b});var n=r(96540),c=r(34164),s=r(45357),o=r(14783),i=r(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function h(){const e=d();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const c=r.select(t),s=r.pluralForms.indexOf(c);return n[Math.min(s,n.length-1)]}(r,t,e)}}var m=r(40877),p=r(23230),f=r(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=r(74848);function j(e){let{href:t,children:r}=e;return(0,g.jsx)(o.A,{href:t,className:(0,c.A)("card padding--lg",x.cardContainer),children:r})}function v(e){let{href:t,icon:r,title:n,description:s}=e;return(0,g.jsxs)(j,{href:t,children:[(0,g.jsxs)(f.A,{as:"h2",className:(0,c.A)("text--truncate",x.cardTitle),title:n,children:[r," ",n]}),s&&(0,g.jsx)("p",{className:(0,c.A)("text--truncate",x.cardDescription),title:s,children:s})]})}function w(e){let{item:t}=e;const r=(0,s.Nr)(t),n=function(){const{selectMessage:e}=h();return t=>e(t,(0,p.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return r?(0,g.jsx)(v,{href:r,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??n(t.items.length)}):null}function A(e){let{item:t}=e;const r=(0,m.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",n=(0,s.cC)(t.docId??void 0);return(0,g.jsx)(v,{href:t.href,icon:r,title:t.label,description:t.description??n?.description})}function y(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(A,{item:t});case"category":return(0,g.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const r=(0,s.$S)();return(0,g.jsx)(b,{items:r.items,className:t})}function b(e){const{items:t,className:r}=e;if(!t)return(0,g.jsx)(N,{...e});const n=(0,s.d1)(t);return(0,g.jsx)("section",{className:(0,c.A)("row",r),children:n.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(y,{item:e})},t)))})}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>i});var n=r(96540);const c={},s=n.createContext(c);function o(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:o(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/aaa7edc4.6002bcd0.js b/pr-preview/pr-1071/assets/js/aaa7edc4.6002bcd0.js deleted file mode 100644 index 5c02b74c5a..0000000000 --- a/pr-preview/pr-1071/assets/js/aaa7edc4.6002bcd0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[315],{16796:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-1.2/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/architecture/attestation.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/components/service-mesh"},"next":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/architecture/secrets"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(25577).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(46664).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nThe hypervisor adds the hash of the policy to the attestation report via the HOSTDATA (on AMD SEV-SNP) or MRCONFIGID (Intel TDX) fields.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"}),"/",(0,r.jsx)(t.code,{children:"MRCONFIGID"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(73439).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP or Intel TDX to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},73439:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},46664:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},25577:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/aaec90ae.8196ad9c.js b/pr-preview/pr-1071/assets/js/aaec90ae.8196ad9c.js deleted file mode 100644 index 0a03d0b3ca..0000000000 --- a/pr-preview/pr-1071/assets/js/aaec90ae.8196ad9c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4304],{19947:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/versioned_docs/version-1.0/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/1.0/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/features-limitations.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/observability"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/1.0/about/telemetry"}}');var r=t(74848),s=t(28453);const o={},a="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2},{value:"Automatic recovery and high availability",id:"automatic-recovery-and-high-availability",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,r.jsx)(n.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,r.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,r.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Bare-metal support"}),": Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Persistent volumes"}),": Contrast only supports volumes with ",(0,r.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode",children:(0,r.jsx)(n.code,{children:"volumeMode: Block"})}),". These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Port forwarding"}),": This feature ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,r.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,r.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,r.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Volume integrity checks"}),": While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ",(0,r.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,r.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,r.jsx)(n.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"automatic-recovery-and-high-availability",children:"Automatic recovery and high availability"}),"\n",(0,r.jsx)(n.p,{children:"The Contrast Coordinator is a singleton and can't be scaled to more than one instance.\nWhen this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually.\nIn a future release, we plan to support distributed Coordinator instances that can recover automatically."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var i=t(96540);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/aafa6b90.8ef6dd98.js b/pr-preview/pr-1071/assets/js/aafa6b90.8ef6dd98.js deleted file mode 100644 index 5d5c20a7bd..0000000000 --- a/pr-preview/pr-1071/assets/js/aafa6b90.8ef6dd98.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6645],{55633:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-0.8/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/architecture/certificates.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/secrets"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/observability"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(720).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},720:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ab09c42c.cce7684d.js b/pr-preview/pr-1071/assets/js/ab09c42c.cce7684d.js deleted file mode 100644 index 1dc960f950..0000000000 --- a/pr-preview/pr-1071/assets/js/ab09c42c.cce7684d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8683],{99437:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-0.7/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/architecture/attestation.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Architecture","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/certificates"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(55689).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(98568).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nOn AMD SEV-SNP the hash of the policy is then added to the attestation report via the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field by the hypervisor.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(61631).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},61631:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},98568:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},55689:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/aba21aa0.0f4e95f1.js b/pr-preview/pr-1071/assets/js/aba21aa0.0f4e95f1.js deleted file mode 100644 index a33e31ad59..0000000000 --- a/pr-preview/pr-1071/assets/js/aba21aa0.0f4e95f1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5742],{27093:s=>{s.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/abfbdc79.c9cb51c7.js b/pr-preview/pr-1071/assets/js/abfbdc79.c9cb51c7.js deleted file mode 100644 index 77be990db3..0000000000 --- a/pr-preview/pr-1071/assets/js/abfbdc79.c9cb51c7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2045],{71925:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"components/index","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-0.7/components/index.md","sourceDirName":"components","slug":"/components/","permalink":"/contrast/pr-preview/pr-1071/0.7/components/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/components/index.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/0.7/deployment"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.7/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},d=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(56356).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},56356:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ac3e6feb.7733ee05.js b/pr-preview/pr-1071/assets/js/ac3e6feb.7733ee05.js deleted file mode 100644 index b08a7ad87f..0000000000 --- a/pr-preview/pr-1071/assets/js/ac3e6feb.7733ee05.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3074],{25315:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-0.8/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/0.8/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/about/telemetry.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/0.8/features-limitations"}}');var r=n(74848),o=n(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ae6c0c68.8cc47233.js b/pr-preview/pr-1071/assets/js/ae6c0c68.8cc47233.js deleted file mode 100644 index 1144a04168..0000000000 --- a/pr-preview/pr-1071/assets/js/ae6c0c68.8cc47233.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2729],{32113:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-0.8/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/0.8/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/components/policies.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.8/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.8/components/service-mesh"}}');var s=n(74848),o=n(28453);const r={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(96540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/b0cb3eb4.017aa338.js b/pr-preview/pr-1071/assets/js/b0cb3eb4.017aa338.js deleted file mode 100644 index b1615d4be6..0000000000 --- a/pr-preview/pr-1071/assets/js/b0cb3eb4.017aa338.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2132],{81850:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"architecture/security-considerations","title":"Security Considerations","description":"Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits).","source":"@site/docs/architecture/security-considerations.md","sourceDirName":"architecture","slug":"/architecture/security-considerations","permalink":"/contrast/pr-preview/pr-1071/next/architecture/security-considerations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/architecture/security-considerations.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/next/architecture/certificates"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/next/architecture/observability"}}');var r=n(74848),s=n(28453);const o={},a="Security Considerations",c={},d=[{value:"General recommendations",id:"general-recommendations",level:2},{value:"Authentication",id:"authentication",level:3},{value:"Encryption",id:"encryption",level:3},{value:"Contrast security guarantees",id:"contrast-security-guarantees",level:2},{value:"Limitations inherent to policy checking",id:"limitations-inherent-to-policy-checking",level:3},{value:"Logs",id:"logs",level:3}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"security-considerations",children:"Security Considerations"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast ensures application integrity and provides secure means of communication and bootstrapping (see ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",children:"security benefits"}),").\nHowever, care must be taken when interacting with the outside of Contrast's confidential environment.\nThis page presents some tips for writing secure applications and outlines the trust boundaries app developers need to know."]}),"\n",(0,r.jsx)(t.h2,{id:"general-recommendations",children:"General recommendations"}),"\n",(0,r.jsx)(t.h3,{id:"authentication",children:"Authentication"}),"\n",(0,r.jsx)(t.p,{children:"The application receives credentials from the Contrast Coordinator during initialization.\nThis allows to authenticate towards peers and to verify credentials received from peers.\nThe application should use the certificate bundle to authenticate incoming requests and be wary of unauthenticated requests or requests with a different root of trust (for example the internet PKI)."}),"\n",(0,r.jsx)(t.p,{children:"The recommendation to authenticate not only applies to network traffic, but also to volumes, GPUs and other devices.\nGenerally speaking, all information provided by the world outside the confidential VM should be treated with due scepticism, especially if it's not authenticated.\nCommon cases where Kubernetes apps interact with external services include DNS, Kubernetes API clients and cloud storage endpoints."}),"\n",(0,r.jsx)(t.h3,{id:"encryption",children:"Encryption"}),"\n",(0,r.jsx)(t.p,{children:"Any external persistence should be encrypted with an authenticated cipher.\nThis recommendation applies to block devices or filesystems mounted into the container, but also to cloud blob storage or external databases."}),"\n",(0,r.jsx)(t.h2,{id:"contrast-security-guarantees",children:"Contrast security guarantees"}),"\n",(0,r.jsx)(t.p,{children:"If an application authenticates with a certificate signed by the Contrast Mesh CA of a given manifest, Contrast provides the following guarantees:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"The container images used by the app are the images specified in the resource definitions."}),"\n",(0,r.jsx)(t.li,{children:"The command line arguments of containers are exactly the arguments specified in the resource definitions."}),"\n",(0,r.jsx)(t.li,{children:"All environment variables are either specified in resource definitions, in the container image manifest or in a settings file for the Contrast CLI."}),"\n",(0,r.jsx)(t.li,{children:"The containers run in a confidential VM that matches the reference values in the manifest."}),"\n",(0,r.jsx)(t.li,{children:"The containers' root filesystems are mounted in encrypted memory."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"limitations-inherent-to-policy-checking",children:"Limitations inherent to policy checking"}),"\n",(0,r.jsx)(t.p,{children:"Workload policies serve as workload identities.\nFrom the perspective of the Contrast Coordinator, all workloads that authenticate with the same policy are equal.\nThus, it's not possible to disambiguate, for example, pods spawned from a deployment or to limit the amount of certificates issued per policy."}),"\n",(0,r.jsxs)(t.p,{children:["Container image references from Kubernetes resource definitions are taken into account when generating the policy.\nA mutable reference may lead to policy failures or unverified image content, depending on the Contrast runtime.\nReliability and security can only be ensured with a full image reference, including digest.\nThe ",(0,r.jsxs)(t.a,{href:"https://docs.docker.com/reference/cli/docker/image/pull/#pull-an-image-by-digest-immutable-identifier",children:[(0,r.jsx)(t.code,{children:"docker pull"})," documentation"]})," explains pinned image references in detail."]}),"\n",(0,r.jsxs)(t.p,{children:["Policies can only verify what can be inferred at generation time.\nSome attributes of Kubernetes pods can't be predicted and thus can't be verified.\nParticularly the ",(0,r.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/downward-api/",children:"downward API"})," contains many fields that are dynamic or depend on the host environment, rendering it unsafe for process environment or arguments.\nThe same goes for ",(0,r.jsx)(t.code,{children:"ConfigMap"})," and ",(0,r.jsx)(t.code,{children:"Secret"})," resources, which can also be used to populate container fields.\nIf the application requires such external information, it should be injected as a mount point and carefully inspected before use."]}),"\n",(0,r.jsx)(t.p,{children:"Another type of dynamic content are persistent volumes.\nAny volumes mounted to the pod need to be scrutinized, and sensitive data must not be written to unprotected volumes.\nIdeally, a volume is mounted as a raw block device and authenticated encryption is added within the confidential container."}),"\n",(0,r.jsx)(t.h3,{id:"logs",children:"Logs"}),"\n",(0,r.jsx)(t.p,{children:"By default, container logs are visible to the host.\nSensitive information shouldn't be logged."}),"\n",(0,r.jsxs)(t.p,{children:["As of right now, hiding logs isn't natively supported.\nIf ",(0,r.jsx)(t.code,{children:"ReadStreamRequest"})," is denied in the policy, the Kata Agent stops reading the logs.\nThis causes the pipes used for standard out and standard error to fill up and potentially deadlock the container.\nIf absolutely required, standard out and standard error should be manually redirected to ",(0,r.jsx)(t.code,{children:"/dev/null"})," inside the container."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const r={},s=i.createContext(r);function o(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/b27c3275.3ddae91c.js b/pr-preview/pr-1071/assets/js/b27c3275.3ddae91c.js deleted file mode 100644 index 6e35e04057..0000000000 --- a/pr-preview/pr-1071/assets/js/b27c3275.3ddae91c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3690],{40497:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/docs/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/next/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/basics/confidential-containers.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"What is Contrast?","permalink":"/contrast/pr-preview/pr-1071/next/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/next/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/b3916dd3.db62ca4d.js b/pr-preview/pr-1071/assets/js/b3916dd3.db62ca4d.js deleted file mode 100644 index cb24778823..0000000000 --- a/pr-preview/pr-1071/assets/js/b3916dd3.db62ca4d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[89],{34806:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>u,frontMatter:()=>s,metadata:()=>n,toc:()=>p});const n=JSON.parse('{"id":"architecture/network-encryption/sidecar","title":"sidecar","description":"","source":"@site/versioned_docs/version-0.5/architecture/network-encryption/sidecar.md","sourceDirName":"architecture/network-encryption","slug":"/architecture/network-encryption/sidecar","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/network-encryption/sidecar.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Network Encryption","permalink":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption"},"next":{"title":"Protocols and Keys","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys"}}');var o=r(74848),c=r(28453);const s={},i=void 0,a={},p=[];function d(e){return(0,o.jsx)(o.Fragment,{})}function u(e={}){const{wrapper:t}={...(0,c.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d()}},28453:(e,t,r)=>{r.d(t,{R:()=>s,x:()=>i});var n=r(96540);const o={},c=n.createContext(o);function s(e){const t=n.useContext(c);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),n.createElement(c.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/b451d7c3.21c2b095.js b/pr-preview/pr-1071/assets/js/b451d7c3.21c2b095.js deleted file mode 100644 index 2e321438ad..0000000000 --- a/pr-preview/pr-1071/assets/js/b451d7c3.21c2b095.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[234],{90961:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"getting-started/bare-metal","title":"Prepare a bare-metal instance","description":"Hardware and firmware setup","source":"@site/versioned_docs/version-1.1/getting-started/bare-metal.md","sourceDirName":"getting-started","slug":"/getting-started/bare-metal","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/getting-started/bare-metal.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto"}}');var r=n(74848),a=n(28453);const i={},o="Prepare a bare-metal instance",l={},c=[{value:"Hardware and firmware setup",id:"hardware-and-firmware-setup",level:2},{value:"Kernel Setup",id:"kernel-setup",level:2},{value:"K3s Setup",id:"k3s-setup",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",...(0,a.R)(),...e.components},{TabItem:n,Tabs:s}=t;return n||u("TabItem",!0),s||u("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"prepare-a-bare-metal-instance",children:"Prepare a bare-metal instance"})}),"\n",(0,r.jsx)(t.h2,{id:"hardware-and-firmware-setup",children:"Hardware and firmware setup"}),"\n",(0,r.jsxs)(s,{queryString:"vendor",children:[(0,r.jsxs)(n,{value:"amd",label:"AMD SEV-SNP",children:[(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"Update your BIOS to a version that supports AMD SEV-SNP. Updating to the latest available version is recommended as newer versions will likely contain security patches for AMD SEV-SNP."}),"\n",(0,r.jsx)(t.li,{children:"Enter BIOS setup to enable SMEE, IOMMU, RMP coverage, and SEV-SNP. Set the SEV-ES ASID Space Limit to a non-zero number (higher is better)."}),"\n",(0,r.jsxs)(t.li,{children:["Download the latest firmware version for your processor from ",(0,r.jsx)(t.a,{href:"https://www.amd.com/de/developer/sev.html",children:"AMD"}),", unpack it, and place it in ",(0,r.jsx)(t.code,{children:"/lib/firmware/amd"}),"."]}),"\n"]}),(0,r.jsxs)(t.p,{children:["Consult AMD's ",(0,r.jsx)(t.a,{href:"https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/tuning-guides/58207-using-sev-with-amd-epyc-processors.pdf",children:"Using SEV with AMD EPYC Processors user guide"})," for more information."]})]}),(0,r.jsx)(n,{value:"intel",label:"Intel TDX",children:(0,r.jsxs)(t.p,{children:["Follow Canonical's instructions on ",(0,r.jsx)(t.a,{href:"https://github.com/canonical/tdx?tab=readme-ov-file#43-enable-intel-tdx-in-the-hosts-bios",children:"setting up Intel TDX in the host's BIOS"}),"."]})})]}),"\n",(0,r.jsx)(t.h2,{id:"kernel-setup",children:"Kernel Setup"}),"\n",(0,r.jsxs)(s,{queryString:"vendor",children:[(0,r.jsx)(n,{value:"amd",label:"AMD SEV-SNP",children:(0,r.jsx)(t.p,{children:"Install a kernel with version 6.11 or greater. If you're following this guide before 6.11 has been released, use 6.11-rc3. Don't use 6.11-rc4 - 6.11-rc6 as they contain a regression. 6.11-rc7+ might work."})}),(0,r.jsx)(n,{value:"intel",label:"Intel TDX",children:(0,r.jsxs)(t.p,{children:["Follow Canonical's instructions on ",(0,r.jsx)(t.a,{href:"https://github.com/canonical/tdx?tab=readme-ov-file#41-install-ubuntu-2404-server-image",children:"setting up Intel TDX on Ubuntu 24.04"}),". Note that Contrast currently only supports Intel TDX with Ubuntu 24.04."]})})]}),"\n",(0,r.jsxs)(t.p,{children:["Increase the ",(0,r.jsx)(t.code,{children:"user.max_inotify_instances"})," sysctl limit by adding ",(0,r.jsx)(t.code,{children:"user.max_inotify_instances=8192"})," to ",(0,r.jsx)(t.code,{children:"/etc/sysctl.d/99-sysctl.conf"})," and running ",(0,r.jsx)(t.code,{children:"sysctl --system"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"k3s-setup",children:"K3s Setup"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["Follow the ",(0,r.jsx)(t.a,{href:"https://docs.k3s.io/",children:"K3s setup instructions"})," to create a cluster."]}),"\n",(0,r.jsxs)(t.li,{children:["Install a block storage provider such as ",(0,r.jsx)(t.a,{href:"https://docs.k3s.io/storage#setting-up-longhorn",children:"Longhorn"})," and mark it as the default storage class."]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function u(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(96540);const r={},a=s.createContext(r);function i(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ba2406d8.c3b0175b.js b/pr-preview/pr-1071/assets/js/ba2406d8.c3b0175b.js deleted file mode 100644 index 94f9edf156..0000000000 --- a/pr-preview/pr-1071/assets/js/ba2406d8.c3b0175b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2476],{56218:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>i});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-0.8/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/getting-started/cluster-setup.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.8/getting-started/install"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto"}}');var t=r(74848),a=r(28453);const o={},c="Create a cluster",l={},i=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.p,{children:["Install the latest version of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli",children:"Login to your account"}),", which needs\nto have the permissions to create an AKS cluster, by executing:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a\nnon-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool."}),"\n",(0,t.jsx)(n.p,{children:"We'll first start by creating the non-CoCo cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.29 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"We then add a second node pool with CoCo support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool add \\\n --resource-group "${azResourceGroup:?}" \\\n --name nodepool2 \\\n --cluster-name "${azClusterName:?}" \\\n --node-count 1 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation\n'})}),"\n",(0,t.jsx)(n.p,{children:"Optionally, we can now remove the non-CoCo node pool:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool delete \\\n --resource-group "${azResourceGroup:?}" \\\n --cluster-name "${azClusterName:?}" \\\n --name nodepool1\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"For validation, list the available nodes using kubectl:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show two nodes:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\naks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>c});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/baef5027.689d327f.js b/pr-preview/pr-1071/assets/js/baef5027.689d327f.js deleted file mode 100644 index 71cf639755..0000000000 --- a/pr-preview/pr-1071/assets/js/baef5027.689d327f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9103],{51760:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>c,metadata:()=>r,toc:()=>d});const r=JSON.parse('{"id":"getting-started/index","title":"Getting started","description":"","source":"@site/versioned_docs/version-0.5/getting-started/index.md","sourceDirName":"getting-started","slug":"/getting-started/","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/getting-started/index.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/features"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.5/getting-started/install"}}');var s=n(74848),o=n(28453),i=n(44074);const c={},a="Getting started",l={},d=[];function u(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"getting-started",children:"Getting started"})}),"\n","\n",(0,s.jsx)(i.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>k});var r=n(96540),s=n(34164),o=n(45357),i=n(14783),c=n(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const d={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function u(){const{i18n:{currentLocale:e}}=(0,c.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),d}}),[e])}function m(){const e=u();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const g={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var x=n(74848);function j(e){let{href:t,children:n}=e;return(0,x.jsx)(i.A,{href:t,className:(0,s.A)("card padding--lg",g.cardContainer),children:n})}function v(e){let{href:t,icon:n,title:r,description:o}=e;return(0,x.jsxs)(j,{href:t,children:[(0,x.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",g.cardTitle),title:r,children:[n," ",r]}),o&&(0,x.jsx)("p",{className:(0,s.A)("text--truncate",g.cardDescription),title:o,children:o})]})}function w(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,x.jsx)(v,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function y(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,x.jsx)(v,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function b(e){let{item:t}=e;switch(t.type){case"link":return(0,x.jsx)(y,{item:t});case"category":return(0,x.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const n=(0,o.$S)();return(0,x.jsx)(k,{items:n.items,className:t})}function k(e){const{items:t,className:n}=e;if(!t)return(0,x.jsx)(N,{...e});const r=(0,o.d1)(t);return(0,x.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,x.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,x.jsx)(b,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>c});var r=n(96540);const s={},o=r.createContext(s);function i(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/bced0f3c.261c5a1b.js b/pr-preview/pr-1071/assets/js/bced0f3c.261c5a1b.js deleted file mode 100644 index 3d557598b0..0000000000 --- a/pr-preview/pr-1071/assets/js/bced0f3c.261c5a1b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8001],{33221:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-0.7/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/basics/security-benefits.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.7/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(80455).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(78807).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},78807:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},80455:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/bd029836.fddf79c6.js b/pr-preview/pr-1071/assets/js/bd029836.fddf79c6.js deleted file mode 100644 index 4dc39f8681..0000000000 --- a/pr-preview/pr-1071/assets/js/bd029836.fddf79c6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1047],{74283:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-1.0/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/1.0/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/components/policies.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/1.0/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/1.0/components/service-mesh"}}');var s=n(74848),o=n(28453);const r={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(96540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/bd625abb.dca62902.js b/pr-preview/pr-1071/assets/js/bd625abb.dca62902.js deleted file mode 100644 index 9025150810..0000000000 --- a/pr-preview/pr-1071/assets/js/bd625abb.dca62902.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4415],{89939:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-1.0/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/architecture/attestation.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/1.0/components/service-mesh"},"next":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/secrets"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(84191).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(36546).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nOn AMD SEV-SNP the hash of the policy is then added to the attestation report via the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field by the hypervisor.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(95449).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/components/overview#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},95449:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},36546:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},84191:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/bedb5cc1.f06c512b.js b/pr-preview/pr-1071/assets/js/bedb5cc1.f06c512b.js deleted file mode 100644 index 7de41f95f8..0000000000 --- a/pr-preview/pr-1071/assets/js/bedb5cc1.f06c512b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3098],{64922:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","source":"@site/versioned_docs/version-1.2/architecture/observability.md","sourceDirName":"architecture","slug":"/architecture/observability","permalink":"/contrast/pr-preview/pr-1071/architecture/observability","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/architecture/observability.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Security considerations","permalink":"/contrast/pr-preview/pr-1071/architecture/security-considerations"},"next":{"title":"Planned features and limitations","permalink":"/contrast/pr-preview/pr-1071/features-limitations"}}');var s=r(74848),i=r(28453);const o={},c="Observability",a={},d=[{value:"Exposed metrics",id:"exposed-metrics",level:2},{value:"Service mesh metrics",id:"service-mesh-metrics",level:2}];function h(e){const t={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"observability",children:"Observability"})}),"\n",(0,s.jsxs)(t.p,{children:["The Contrast Coordinator can expose metrics in the\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/",children:"Prometheus"})," format. These can be monitored to quickly\nidentify problems in the gRPC layer or attestation errors. Prometheus metrics\nare numerical values associated with a name and additional key/values pairs,\ncalled labels."]}),"\n",(0,s.jsx)(t.h2,{id:"exposed-metrics",children:"Exposed metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The metrics can be accessed at the Coordinator pod at the port specified in the\n",(0,s.jsx)(t.code,{children:"CONTRAST_METRICS_PORT"})," environment variable under the ",(0,s.jsx)(t.code,{children:"/metrics"})," endpoint. By\ndefault, this environment variable isn't specified, hence no metrics will be\nexposed."]}),"\n",(0,s.jsxs)(t.p,{children:["The Coordinator exports gRPC metrics under the prefix ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_"}),".\nThese metrics are labeled with the gRPC service name and method name.\nMetrics of interest include ",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handled_total"}),", which counts\nthe number of requests by return code, and\n",(0,s.jsx)(t.code,{children:"contrast_grpc_server_handling_seconds_bucket"}),", which produces a histogram of",(0,s.jsx)(t.br,{}),"\n","request latency."]}),"\n",(0,s.jsxs)(t.p,{children:["The gRPC service ",(0,s.jsx)(t.code,{children:"userapi.UserAPI"})," records metrics for the methods\n",(0,s.jsx)(t.code,{children:"SetManifest"})," and ",(0,s.jsx)(t.code,{children:"GetManifest"}),", which get called when ",(0,s.jsx)(t.a,{href:"../deployment#set-the-manifest",children:"setting the\nmanifest"})," and ",(0,s.jsx)(t.a,{href:"../deployment#verify-the-coordinator",children:"verifying the\nCoordinator"})," respectively."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"meshapi.MeshAPI"})," service records metrics for the method ",(0,s.jsx)(t.code,{children:"NewMeshCert"}),", which\ngets called by the ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-initializer",children:"Initializer"})," when starting a\nnew workload. Attestation failures from workloads to the Coordinator can be\ntracked with the counter ",(0,s.jsx)(t.code,{children:"contrast_meshapi_attestation_failures_total"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The current manifest generation is exposed as a\n",(0,s.jsx)(t.a,{href:"https://prometheus.io/docs/concepts/metric_types/#gauge",children:"gauge"})," with the metric\nname ",(0,s.jsx)(t.code,{children:"contrast_coordinator_manifest_generation"}),". If no manifest is set at the\nCoordinator, this counter will be zero."]}),"\n",(0,s.jsx)(t.h2,{id:"service-mesh-metrics",children:"Service mesh metrics"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"Service Mesh"})," can be configured to expose\nmetrics via its ",(0,s.jsx)(t.a,{href:"https://www.envoyproxy.io/docs/envoy/latest/operations/admin",children:"Envoy admin\ninterface"}),". Be\naware that the admin interface can expose private information and allows\ndestructive operations to be performed. To enable the admin interface for the\nService Mesh, set the annotation\n",(0,s.jsx)(t.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," in the configuration\nof your workload. If this annotation is set, the admin interface will be started\non this port."]}),"\n",(0,s.jsxs)(t.p,{children:["To access the admin interface, the ingress settings of the Service Mesh have to\nbe configured to allow access to the specified port (see ",(0,s.jsx)(t.a,{href:"../components/service-mesh#configuring-the-proxy",children:"Configuring the\nProxy"}),"). All metrics will be\nexposed under the ",(0,s.jsx)(t.code,{children:"/stats"})," endpoint. Metrics in Prometheus format can be scraped\nfrom the ",(0,s.jsx)(t.code,{children:"/stats/prometheus"})," endpoint."]})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var n=r(96540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/bf823012.bbc65b50.js b/pr-preview/pr-1071/assets/js/bf823012.bbc65b50.js deleted file mode 100644 index 4fae8db034..0000000000 --- a/pr-preview/pr-1071/assets/js/bf823012.bbc65b50.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5225],{32615:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-0.7/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/getting-started/install.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Getting started","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup"}}');var r=n(74848),a=n(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v0.7.3/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>i});var s=n(96540);const r={},a=s.createContext(r);function o(t){const e=s.useContext(a);return s.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),s.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/bfdb605f.8b4e7cf0.js b/pr-preview/pr-1071/assets/js/bfdb605f.8b4e7cf0.js deleted file mode 100644 index 2b52c1a1a2..0000000000 --- a/pr-preview/pr-1071/assets/js/bfdb605f.8b4e7cf0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3610],{52055:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"examples/mysql","title":"Encrypted volume mount","description":"This tutorial guides you through deploying a simple application with an","source":"@site/versioned_docs/version-1.2/examples/mysql.md","sourceDirName":"examples","slug":"/examples/mysql","permalink":"/contrast/pr-preview/pr-1071/examples/mysql","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/examples/mysql.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/examples/emojivoto"},"next":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/deployment"}}');var r=n(74848),o=n(28453);const i={},a="Encrypted volume mount",l={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy MySQL with Contrast",id:"steps-to-deploy-mysql-with-contrast",level:2},{value:"Download the deployment files",id:"download-the-deployment-files",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy MySQL",id:"deploy-mysql",level:3},{value:"Verifying the deployment as a user",id:"verifying-the-deployment-as-a-user",level:2},{value:"Verifying the Coordinator",id:"verifying-the-coordinator",level:3},{value:"Auditing the manifest history and artifacts",id:"auditing-the-manifest-history-and-artifacts",level:3},{value:"Connecting to the application",id:"connecting-to-the-application",level:3},{value:"Updating the deployment",id:"updating-the-deployment",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components},{TabItem:n,Tabs:s}=t;return n||p("TabItem",!0),s||p("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"encrypted-volume-mount",children:"Encrypted volume mount"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsxs)(t.strong,{children:["This tutorial guides you through deploying a simple application with an\nencrypted MySQL database using the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/secrets#workload-secrets",children:"workload\nsecret"}),"."]})}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.a,{href:"https://mysql.com",children:"MySQL"})," is an open-source database used to organize data into\ntables and quickly retrieve information about its content. All of the data in a\nMySQL database is stored in the ",(0,r.jsx)(t.code,{children:"/var/lib/mysql"})," directory. In this example, we\nuse the workload secret to setup an encrypted LUKS mount for the\n",(0,r.jsx)(t.code,{children:"/var/lib/mysql"})," directory to easily deploy an application with encrypted\npersistent storage using Contrast."]}),"\n",(0,r.jsxs)(t.p,{children:["The resources provided in this demo are designed for educational purposes and\nshouldn't be used in a production environment without proper evaluation. When\nworking with persistent storage, regular backups are recommended in order to\nprevent data loss. For confidential applications, please also refer to the\n",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/security-considerations",children:"security considerations"}),". Also be\naware of the differences in security implications of the workload secrets for\nthe data owner and the workload owner. For more details, see the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/secrets#workload-secrets",children:"Workload\nSecrets"})," documentation."]}),"\n",(0,r.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Installed Contrast CLI"}),"\n",(0,r.jsxs)(t.li,{children:["A running Kubernetes cluster with support for confidential containers, either on ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/getting-started/cluster-setup",children:"AKS"})," or on ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/getting-started/bare-metal",children:"bare metal"})]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"steps-to-deploy-mysql-with-contrast",children:"Steps to deploy MySQL with Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"download-the-deployment-files",children:"Download the deployment files"}),"\n",(0,r.jsx)(t.p,{children:"The MySQL deployment files are part of the Contrast release. You can download them by running:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.2.0/mysql-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,r.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast depends on a ",(0,r.jsxs)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:["custom Kubernetes ",(0,r.jsx)(t.code,{children:"RuntimeClass"})]}),",\nwhich needs to be installed to the cluster initially.\nThis consists of a ",(0,r.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,r.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(n,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-aks-clh-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsxs)(t.p,{children:["Deploy the Contrast Coordinator, comprising a single replica deployment and a\n",(0,r.jsx)(t.code,{children:"LoadBalancer"})," service, into your cluster:"]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(n,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-aks-clh-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-k3s-qemu-snp.yml\n"})})}),(0,r.jsx)(n,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,r.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(t.p,{children:["Run the ",(0,r.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,r.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,r.jsxs)(s,{queryString:"platform",children:[(0,r.jsx)(n,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})})}),(0,r.jsxs)(n,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp deployment/\n"})}),(0,r.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(t.p,{children:["On bare-metal SEV-SNP, ",(0,r.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(t.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(t.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,r.jsxs)(n,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx deployment/\n"})}),(0,r.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,r.jsxs)(t.p,{children:["On bare-metal TDX, ",(0,r.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,r.jsx)(t.code,{children:"MinimumTeeTcbSvn"})," and ",(0,r.jsx)(t.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,r.jsx)(t.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,r.jsx)(t.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,r.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,r.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,r.jsx)(t.a,{href:"../components/runtime",children:"runtime class"})," ",(0,r.jsx)(t.code,{children:"contrast-cc"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads. It will attest the pod to the Coordinator and fetch the workload certificates and the workload secret."]}),(0,r.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe MySQL server and client."]})]}),"\n",(0,r.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,r.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsxs)(t.p,{children:["On bare metal, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(t.h3,{id:"deploy-mysql",children:"Deploy MySQL"}),"\n",(0,r.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the MySQL deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,r.jsx)(t.admonition,{title:"Persistent workload secrets",type:"note",children:(0,r.jsxs)(t.p,{children:["During the initialization process of the workload pod, the Contrast Initializer\nsends an attestation report to the Coordinator and receives a workload secret\nderived from the Coordinator's secret seed and the workload secret ID specified in the\nmanifest, and writes it to a secure in-memory ",(0,r.jsx)(t.code,{children:"volumeMount"}),"."]})}),"\n",(0,r.jsxs)(t.p,{children:["The MySQL deployment is declared as a StatefulSet with a mounted block device.\nAn init container running ",(0,r.jsx)(t.code,{children:"cryptsetup"})," uses the workload secret at\n",(0,r.jsx)(t.code,{children:"/contrast/secrets/workload-secret-seed"})," to generate a key and setup the block\ndevice as a LUKS partition. Before starting the MySQL container, the init\ncontainer uses the generated key to open the LUKS device, which is then mounted\nby the MySQL container. For the MySQL container, this process is completely\ntransparent and works like mounting any other volume. The ",(0,r.jsx)(t.code,{children:"cryptsetup"})," container\nwill remain running to provide the necessary decryption context for the workload\ncontainer."]}),"\n",(0,r.jsx)(t.h2,{id:"verifying-the-deployment-as-a-user",children:"Verifying the deployment as a user"}),"\n",(0,r.jsx)(t.p,{children:"In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before connecting to the database.\nWith Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment.\nContrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future.\nSuccessful verification of the Coordinator means that the user can be sure that the given manifest will be enforced."}),"\n",(0,r.jsx)(t.h3,{id:"verifying-the-coordinator",children:"Verifying the Coordinator"}),"\n",(0,r.jsx)(t.p,{children:"A user can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,r.jsxs)(t.p,{children:["The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,r.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,r.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,r.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsxs)(t.p,{children:["On bare metal, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,r.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,r.jsx)(t.h3,{id:"auditing-the-manifest-history-and-artifacts",children:"Auditing the manifest history and artifacts"}),"\n",(0,r.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,r.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA user of the application should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,r.jsx)(t.h3,{id:"connecting-to-the-application",children:"Connecting to the application"}),"\n",(0,r.jsxs)(t.p,{children:["Other confidential containers can securely connect to the MySQL server via the\n",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"Service Mesh"}),". The configured ",(0,r.jsx)(t.code,{children:"mysql-client"}),"\ndeployment connects to the MySQL server and inserts test data into a table. To\nview the logs of the ",(0,r.jsx)(t.code,{children:"mysql-client"})," deployment, use the following commands:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl logs -l app.kubernetes.io/name=mysql-client -c mysql-client\n"})}),"\n",(0,r.jsx)(t.p,{children:"The Service Mesh ensures an mTLS connection between the MySQL client and server\nusing the mesh certificates. As a result, no other workload can connect to the\nMySQL server unless explicitly allowed in the manifest."}),"\n",(0,r.jsx)(t.h2,{id:"updating-the-deployment",children:"Updating the deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Because the workload secret is derived from the ",(0,r.jsx)(t.code,{children:"WorkloadSecredID"})," specified in\nthe manifest and not to an individual pod, once the pod restarts, the\n",(0,r.jsx)(t.code,{children:"cryptsetup"})," init container can deterministically generate the same key again\nand open the already partitioned LUKS device.\nFor more information on using the workload secret, see ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/secrets#workload-secrets",children:"Workload\nSecrets"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["For example, after making changes to the deployment files, the runtime policies\nneed to be regenerated with ",(0,r.jsx)(t.code,{children:"contrast generate"})," and the new manifest needs to be\nset using ",(0,r.jsx)(t.code,{children:"contrast set"}),"."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:'contrast generate deployment/\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,r.jsx)(t.p,{children:"The new deployment can then be applied by running:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart statefulset/mysql-backend\nkubectl rollout restart deployment/mysql-client\n"})}),"\n",(0,r.jsxs)(t.p,{children:["The new MySQL backend pod will then start up the ",(0,r.jsx)(t.code,{children:"cryptsetup"})," init container which\nreceives the same workload secret as before and can therefore generate the\ncorrect key to open the LUKS device. All previously stored data in the MySQL\ndatabase is available in the newly created pod in an encrypted volume mount."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}function p(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>a});var s=n(96540);const r={},o=s.createContext(r);function i(e){const t=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c09e49b9.62585cb6.js b/pr-preview/pr-1071/assets/js/c09e49b9.62585cb6.js deleted file mode 100644 index d54aa420ac..0000000000 --- a/pr-preview/pr-1071/assets/js/c09e49b9.62585cb6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[390],{82693:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-0.6/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/architecture/certificates.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation"},"next":{"title":"Known limitations","permalink":"/contrast/pr-preview/pr-1071/0.6/known-limitations"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(59862).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},59862:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c1fac065.b45a35ee.js b/pr-preview/pr-1071/assets/js/c1fac065.b45a35ee.js deleted file mode 100644 index 343dd83f91..0000000000 --- a/pr-preview/pr-1071/assets/js/c1fac065.b45a35ee.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4206],{69006:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>c,metadata:()=>r,toc:()=>d});const r=JSON.parse('{"id":"getting-started/index","title":"Getting started","description":"","source":"@site/versioned_docs/version-0.6/getting-started/index.md","sourceDirName":"getting-started","slug":"/getting-started/","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/getting-started/index.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/features"},"next":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/install"}}');var s=n(74848),o=n(28453),i=n(44074);const c={},a="Getting started",l={},d=[];function u(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"getting-started",children:"Getting started"})}),"\n","\n",(0,s.jsx)(i.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>k});var r=n(96540),s=n(34164),o=n(45357),i=n(14783),c=n(97639);const a=["zero","one","two","few","many","other"];function l(e){return a.filter((t=>e.includes(t)))}const d={locale:"en",pluralForms:l(["one","other"]),select:e=>1===e?"one":"other"};function u(){const{i18n:{currentLocale:e}}=(0,c.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:l(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),d}}),[e])}function m(){const e=u();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const g={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var x=n(74848);function j(e){let{href:t,children:n}=e;return(0,x.jsx)(i.A,{href:t,className:(0,s.A)("card padding--lg",g.cardContainer),children:n})}function v(e){let{href:t,icon:n,title:r,description:o}=e;return(0,x.jsxs)(j,{href:t,children:[(0,x.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",g.cardTitle),title:r,children:[n," ",r]}),o&&(0,x.jsx)("p",{className:(0,s.A)("text--truncate",g.cardDescription),title:o,children:o})]})}function w(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,x.jsx)(v,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function y(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,x.jsx)(v,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function b(e){let{item:t}=e;switch(t.type){case"link":return(0,x.jsx)(y,{item:t});case"category":return(0,x.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const n=(0,o.$S)();return(0,x.jsx)(k,{items:n.items,className:t})}function k(e){const{items:t,className:n}=e;if(!t)return(0,x.jsx)(N,{...e});const r=(0,o.d1)(t);return(0,x.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,x.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,x.jsx)(b,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>c});var r=n(96540);const s={},o=r.createContext(s);function i(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c2ce05d5.e81b5ad2.js b/pr-preview/pr-1071/assets/js/c2ce05d5.e81b5ad2.js deleted file mode 100644 index b0b4a6a52b..0000000000 --- a/pr-preview/pr-1071/assets/js/c2ce05d5.e81b5ad2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8024],{94003:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","source":"@site/versioned_docs/version-1.0/troubleshooting.md","sourceDirName":".","slug":"/troubleshooting","permalink":"/contrast/pr-preview/pr-1071/1.0/troubleshooting","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/troubleshooting.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/1.0/deployment"},"next":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/1.0/components/overview"}}');var i=t(74848),s=t(28453);const a={},r="Troubleshooting",c={},l=[{value:"Logging",id:"logging",level:2},{value:"CLI",id:"cli",level:3},{value:"Coordinator and Initializer",id:"coordinator-and-initializer",level:3},{value:"Pod fails to start",id:"pod-fails-to-start",level:2},{value:"Regenerating the policies",id:"regenerating-the-policies",level:3},{value:"Pin container images",id:"pin-container-images",level:3},{value:"Validate Contrast components match",id:"validate-contrast-components-match",level:3}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"troubleshooting",children:"Troubleshooting"})}),"\n",(0,i.jsx)(n.p,{children:"This section contains information on how to debug your Contrast deployment."}),"\n",(0,i.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,i.jsx)(n.p,{children:"Collecting logs can be a good first step to identify problems in your\ndeployment. Both the CLI and the Contrast Coordinator as well as the Initializer\ncan be configured to emit additional logs."}),"\n",(0,i.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,i.jsxs)(n.p,{children:["The CLI logs can be configured with the ",(0,i.jsx)(n.code,{children:"--log-level"})," command-line flag, which\ncan be set to either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"})," or ",(0,i.jsx)(n.code,{children:"error"}),". The default is ",(0,i.jsx)(n.code,{children:"info"}),".\nSetting this to ",(0,i.jsx)(n.code,{children:"debug"})," can get more fine-grained information as to where the\nproblem lies."]}),"\n",(0,i.jsx)(n.h3,{id:"coordinator-and-initializer",children:"Coordinator and Initializer"}),"\n",(0,i.jsxs)(n.p,{children:["The logs from the Coordinator and the Initializer can be configured via the\nenvironment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"}),", ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," and\n",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"})," can be set to one of either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"}),", or\n",(0,i.jsx)(n.code,{children:"error"}),", similar to the CLI (defaults to ",(0,i.jsx)(n.code,{children:"info"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," can be set to ",(0,i.jsx)(n.code,{children:"text"})," or ",(0,i.jsx)(n.code,{children:"json"}),", determining the output\nformat (defaults to ",(0,i.jsx)(n.code,{children:"text"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," is a comma-seperated list of subsystems that should\nbe enabled for logging, which are disabled by default. Subsystems include:\n",(0,i.jsx)(n.code,{children:"kds-getter"}),", ",(0,i.jsx)(n.code,{children:"issuer"})," and ",(0,i.jsx)(n.code,{children:"validator"}),".\nTo enable all subsystems, use ",(0,i.jsx)(n.code,{children:"*"})," as the value for this environment variable.\nWarnings and error messages from subsystems get printed regardless of whether\nthe subsystem is listed in the ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," environment variable."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"To configure debug logging with all subsystems for your Coordinator, add the\nfollowing variables to your container definition."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n containers:\n image: "ghcr.io/edgelesssys/contrast/coordinator:v1.0.0@sha256:36766ae51dbafa4ef5e90c3e24698bdfbb3b4d765e13c14bdee190a1a7638c35"\n name: coordinator\n env:\n - name: CONTRAST_LOG_LEVEL\n value: debug\n - name: CONTRAST_LOG_SUBSYSTEMS\n value: "*"\n # ...\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["While the Contrast Coordinator has a policy that allows certain configurations,\nthe Initializer and service mesh don't. When changing environment variables of other\nparts than the Coordinator, ensure to rerun ",(0,i.jsx)(n.code,{children:"contrast generate"})," to update the policy."]})}),"\n",(0,i.jsxs)(n.p,{children:["To access the logs generated by the Coordinator, you can use ",(0,i.jsx)(n.code,{children:"kubectl"})," with the\nfollowing command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl logs <coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.h2,{id:"pod-fails-to-start",children:"Pod fails to start"}),"\n",(0,i.jsxs)(n.p,{children:["If the Coordinator or a workload pod fails to even start, it can be helpful to\nlook at the events of the pod during the startup process using the ",(0,i.jsx)(n.code,{children:"describe"}),"\ncommand."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> events --for pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"Example output:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'LAST SEEN TYPE REASON OBJECT MESSAGE\n32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...\n'})}),"\n",(0,i.jsx)(n.p,{children:"A common error, as in this example, is that the container creation was blocked by the\npolicy. Potential reasons are a modification of the deployment YAML without updating\nthe policies afterward, or a version mismatch between Contrast components."}),"\n",(0,i.jsx)(n.h3,{id:"regenerating-the-policies",children:"Regenerating the policies"}),"\n",(0,i.jsx)(n.p,{children:"To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated\npolicies, rerun"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast generate\n"})}),"\n",(0,i.jsx)(n.p,{children:"on your deployment. If any of the policy annotations change, re-deploy with the updated policies."}),"\n",(0,i.jsx)(n.h3,{id:"pin-container-images",children:"Pin container images"}),"\n",(0,i.jsx)(n.p,{children:"When generating the policies, Contrast will download the images specified in your deployment\nYAML and include their cryptographic identity. If the image tag is moved to another\ncontainer image after the policy has been generated, the image downloaded at deploy time\nwill differ from the one at generation time, and the policy enforcement won't allow the\ncontainer to be started in the pod VM."}),"\n",(0,i.jsxs)(n.p,{children:["To ensure the correct image is always used, pin the container image to a fixed ",(0,i.jsx)(n.code,{children:"sha256"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This way, the same image will still be pulled when the container tag (",(0,i.jsx)(n.code,{children:"22.04"}),") is moved\nto another image."]}),"\n",(0,i.jsx)(n.h3,{id:"validate-contrast-components-match",children:"Validate Contrast components match"}),"\n",(0,i.jsx)(n.p,{children:"A version mismatch between Contrast components can cause policy validation or attestation\nto fail. Each Contrast runtime is identifiable based on its (shortened) measurement value\nused to name the runtime class version."}),"\n",(0,i.jsx)(n.p,{children:"First, analyze which runtime class is currently installed in your cluster by running"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl get runtimeclasses\n"})}),"\n",(0,i.jsx)(n.p,{children:"This should give you output similar to the following one."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"NAME HANDLER AGE\ncontrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h\nkata-cc-isolation kata-cc 45d\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided\nby the AKS CoCo preview, which isn't used by Contrast)."}),"\n",(0,i.jsx)(n.p,{children:"Next, check if the pod that won't start has the correct runtime class configured, and the\nCoordinator uses the exact same runtime:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>\nkubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output should list the runtime class the pod is using:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast-cc-aks-clh-snp-7173acb5\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Version information about the currently used CLI can be obtained via the ",(0,i.jsx)(n.code,{children:"version"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast --version\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast version v0.X.0\n\n runtime handler: contrast-cc-aks-clh-snp-7173acb5\n launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35\n genpolicy version: 3.2.0.azl1.genpolicy0\n image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...\n ghcr.io/edgelesssys/contrast/initializer@sha256:...\n"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(96540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c3a9f66a.e329e9c2.js b/pr-preview/pr-1071/assets/js/c3a9f66a.e329e9c2.js deleted file mode 100644 index 09eaa357e9..0000000000 --- a/pr-preview/pr-1071/assets/js/c3a9f66a.e329e9c2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7832],{8032:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/versioned_docs/version-0.9/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/0.9/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/components/service-mesh.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/0.9/components/policies"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/attestation"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"CONTRAST_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"CONTRAST_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"<name>#<port>#false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:"<name>"})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"<name>#<port>#true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: CONTRAST_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v0.9.0@sha256:d97397770b8ea13082eab96099629f971688508e5b0cc1596df07aa5510d5972"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-tls-certs\n mountPath: /tls-config\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"<name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port>"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:"<name>"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c3f66d9e.f9b116f8.js b/pr-preview/pr-1071/assets/js/c3f66d9e.f9b116f8.js deleted file mode 100644 index 1dd623c945..0000000000 --- a/pr-preview/pr-1071/assets/js/c3f66d9e.f9b116f8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[13],{1570:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.6","label":"0.6","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.6","isLast":false,"docsSidebars":{"docs":[{"type":"category","label":"What is Contrast?","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/0.6/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.6/"},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/0.6/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false}],"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.6/getting-started/"},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.6/examples/"},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/0.6/deployment","docId":"deployment","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/0.6/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/0.6/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.6/components/"},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates","docId":"architecture/certificates","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.6/architecture/"},{"type":"link","label":"Known limitations","href":"/contrast/pr-preview/pr-1071/0.6/known-limitations","docId":"known-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/0.6/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true,"href":"/contrast/pr-preview/pr-1071/0.6/about/"}]},"docs":{"about/index":{"id":"about/index","title":"About","description":"","sidebar":"docs"},"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/index":{"id":"architecture/index","title":"Architecture","description":"","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/index":{"id":"components/index","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service Mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"examples/index":{"id":"examples/index","title":"Examples","description":"","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/index":{"id":"getting-started/index","title":"Getting started","description":"","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"known-limitations":{"id":"known-limitations","title":"Known Limitations","description":"As Contrast is currently in an early development stage, it\'s built on several projects that are also under active development.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c4b4ced0.b12602ed.js b/pr-preview/pr-1071/assets/js/c4b4ced0.b12602ed.js deleted file mode 100644 index 5ce7b0786a..0000000000 --- a/pr-preview/pr-1071/assets/js/c4b4ced0.b12602ed.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2564],{58505:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/docs/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/next/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/components/runtime.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/next/components/overview"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/next/components/policies"}}');var i=t(74848),r=t(28453);const a={},o="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"Virtual machine manager (VMM)",id:"virtual-machine-manager-vmm",level:3},{value:"Snapshotters",id:"snapshotters",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled/TDX-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(30487).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"virtual-machine-manager-vmm",children:"Virtual machine manager (VMM)"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses a virtual machine monitor to create a confidential virtual machine for every pod.\nOn AKS, Contrast uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})}),".\nOn bare metal, Contrast uses ",(0,i.jsx)(n.a,{href:"https://www.qemu.org/",children:(0,i.jsx)(n.code,{children:"QEMU"})}),".\nThe appropriate files are installed on every node by the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"snapshotters",children:"Snapshotters"}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotters"]})," to provide container images to the pod-VM.\nEach snapshotter consists of a host component that pulls container images and a guest component used to mount/pull container images."]}),"\n",(0,i.jsxs)(n.p,{children:["On AKS, Contrast uses the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})})," snapshotter to provide container images as block devices to the pod-VM.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsxs)(n.p,{children:["On bare metal, Contrast uses the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/nydus-snapshotter",children:(0,i.jsx)(n.code,{children:"nydus"})})," snapshotter to store metadata about the images. This metadata is communicated to the guest, so that it can pull the images itself."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," or ",(0,i.jsx)(n.code,{children:"QEMU"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file or separate firmware and kernel files for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},30487:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var s=t(96540);const i={},r=s.createContext(i);function a(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/c7462af2.58bb49ad.js b/pr-preview/pr-1071/assets/js/c7462af2.58bb49ad.js deleted file mode 100644 index 6946f9d952..0000000000 --- a/pr-preview/pr-1071/assets/js/c7462af2.58bb49ad.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2540],{56473:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","source":"@site/versioned_docs/version-0.9/components/policies.md","sourceDirName":"components","slug":"/components/policies","permalink":"/contrast/pr-preview/pr-1071/0.9/components/policies","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/components/policies.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/0.9/components/runtime"},"next":{"title":"Service mesh","permalink":"/contrast/pr-preview/pr-1071/0.9/components/service-mesh"}}');var s=n(74848),o=n(28453);const r={},a="Policies",c={},l=[{value:"Structure",id:"structure",level:2},{value:"Generation",id:"generation",level:2},{value:"Evaluation",id:"evaluation",level:2},{value:"Guarantees",id:"guarantees",level:2},{value:"Trust",id:"trust",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"policies",children:"Policies"})}),"\n",(0,s.jsx)(t.p,{children:"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.\nThey prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM.\nIn Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment.\nVerification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations."}),"\n",(0,s.jsx)(t.h2,{id:"structure",children:"Structure"}),"\n",(0,s.jsxs)(t.p,{children:["The Kata agent running in the confidential micro-VM exposes an RPC service ",(0,s.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers/blob/e5e0983/src/libs/protocols/protos/agent.proto#L21-L76",children:(0,s.jsx)(t.code,{children:"AgentService"})})," to the Kata runtime.\nThis service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy."]}),"\n",(0,s.jsxs)(t.p,{children:["Kata runtime policies are written in the policy language ",(0,s.jsx)(t.a,{href:"https://www.openpolicyagent.org/docs/latest/policy-language/",children:"Rego"}),".\nThey specify what ",(0,s.jsx)(t.code,{children:"AgentService"})," methods can be called, and the permissible parameters for each call."]}),"\n",(0,s.jsxs)(t.p,{children:["Policies consist of two parts: a list of rules and a data section.\nWhile the list of rules is static, the data section is populated with information from the ",(0,s.jsx)(t.code,{children:"PodSpec"})," and other sources."]}),"\n",(0,s.jsx)(t.h2,{id:"generation",children:"Generation"}),"\n",(0,s.jsxs)(t.p,{children:["Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI.\nThe ",(0,s.jsx)(t.code,{children:"generate"})," subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent.\nThere are two important integrity checks: container image checksums and OCI runtime parameters."]}),"\n",(0,s.jsxs)(t.p,{children:["For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic ",(0,s.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," checksum.\nThese checksums are the basis for the policy's ",(0,s.jsx)(t.em,{children:"storage data"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The CLI combines information from the ",(0,s.jsx)(t.code,{children:"PodSpec"}),", ",(0,s.jsx)(t.code,{children:"ConfigMaps"}),", and ",(0,s.jsx)(t.code,{children:"Secrets"})," in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables.\nThese constitute the policy's ",(0,s.jsx)(t.em,{children:"OCI data"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"evaluation",children:"Evaluation"}),"\n",(0,s.jsxs)(t.p,{children:["The generated policy document is annotated to the pod definitions in Base64 encoding.\nThis annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," for the confidential micro-VM."]}),"\n",(0,s.jsxs)(t.p,{children:["After the VM launched, the runtime calls the agent's ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method with the full policy document.\nIf the policy doesn't match the checksum in ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),", the agent rejects the policy.\nOtherwise, it applies the policy to all future ",(0,s.jsx)(t.code,{children:"AgentService"})," requests."]}),"\n",(0,s.jsx)(t.h2,{id:"guarantees",children:"Guarantees"}),"\n",(0,s.jsx)(t.p,{children:"The policy evaluation provides the following guarantees for pods launched with the correct generated policy:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Command and its arguments are set as specified in the resources."}),"\n",(0,s.jsx)(t.li,{children:"There are no unexpected additional environment variables."}),"\n",(0,s.jsx)(t.li,{children:"The container image layers correspond to the layers observed at policy generation time.\nThus, only the expected workload image can be instantiated."}),"\n",(0,s.jsx)(t.li,{children:"Executing additional processes in a container is prohibited."}),"\n",(0,s.jsx)(t.li,{children:"Sending data to a container's standard input is prohibited."}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The current implementation of policy checking has some blind spots:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Containers can be started in any order, or be omitted entirely."}),"\n",(0,s.jsx)(t.li,{children:"Environment variables may be missing."}),"\n",(0,s.jsxs)(t.li,{children:["Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ",(0,s.jsx)(t.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(t.code,{children:"Secrets"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"trust",children:"Trust"}),"\n",(0,s.jsx)(t.p,{children:"Contrast verifies its confidential containers following these steps:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"The Contrast CLI generates a policy and attaches it to the pod definition."}),"\n",(0,s.jsx)(t.li,{children:"Kubernetes schedules the pod on a node with the confidential computing runtime."}),"\n",(0,s.jsx)(t.li,{children:"Containerd invokes the Kata runtime to create the pod sandbox."}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime starts a CVM with the policy's digest as ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata runtime sets the policy using the ",(0,s.jsx)(t.code,{children:"SetPolicy"})," method."]}),"\n",(0,s.jsxs)(t.li,{children:["The Kata agent verifies that the incoming policy's digest matches ",(0,s.jsx)(t.code,{children:"HOSTDATA"}),"."]}),"\n",(0,s.jsx)(t.li,{children:"The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies."}),"\n",(0,s.jsx)(t.li,{children:"The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate."}),"\n",(0,s.jsxs)(t.li,{children:["The Contrast Coordinator verifies that the started pod has a permitted policy hash in its ",(0,s.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates."})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(96540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ca5b6702.9ab781f2.js b/pr-preview/pr-1071/assets/js/ca5b6702.9ab781f2.js deleted file mode 100644 index 8f7f977bcc..0000000000 --- a/pr-preview/pr-1071/assets/js/ca5b6702.9ab781f2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5945],{95477:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","source":"@site/docs/components/service-mesh.md","sourceDirName":"components","slug":"/components/service-mesh","permalink":"/contrast/pr-preview/pr-1071/next/components/service-mesh","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/components/service-mesh.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/next/components/policies"},"next":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/next/architecture/attestation"}}');var i=t(74848),r=t(28453);const o={},c="Service mesh",a={},h=[{value:"Configuring the proxy",id:"configuring-the-proxy",level:2},{value:"Ingress",id:"ingress",level:3},{value:"Egress",id:"egress",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"service-mesh",children:"Service mesh"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast service mesh secures the communication of the workload by automatically\nwrapping the network traffic inside mutual TLS (mTLS) connections. The\nverification of the endpoints in the connection establishment is based on\ncertificates that are part of the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates",children:"PKI of the Coordinator"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The service mesh can be enabled on a per-workload basis by adding a service mesh\nconfiguration to the workload's object annotations. During the ",(0,i.jsx)(n.code,{children:"contrast generate"}),"\nstep, the service mesh is added as a ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/",children:"sidecar\ncontainer"})," to\nall workloads which have a specified configuration. The service mesh container first\nsets up ",(0,i.jsx)(n.code,{children:"iptables"})," rules based on its configuration and then starts\n",(0,i.jsx)(n.a,{href:"https://www.envoyproxy.io/",children:"Envoy"})," for TLS origination and termination."]}),"\n",(0,i.jsx)(n.h2,{id:"configuring-the-proxy",children:"Configuring the proxy"}),"\n",(0,i.jsx)(n.p,{children:"The service mesh container can be configured using the following object annotations:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," to configure ingress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," to configure egress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-admin-interface-port"})," to configure the Envoy\nadmin interface. If not specified, no admin interface will be started."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you aren't using the automatic service mesh injection and want to configure the\nservice mesh manually, set the environment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_INGRESS_PROXY_CONFIG"}),",\n",(0,i.jsx)(n.code,{children:"CONTRAST_EGRESS_PROXY_CONFIG"})," and ",(0,i.jsx)(n.code,{children:"CONTRAST_ADMIN_PORT"})," in the service mesh sidecar directly."]}),"\n",(0,i.jsx)(n.h3,{id:"ingress",children:"Ingress"}),"\n",(0,i.jsxs)(n.p,{children:["All TCP ingress traffic is routed over Envoy by default. Since we use\n",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/networking/tproxy.html",children:"TPROXY"}),", the destination address\nremains the same throughout the packet handling."]}),"\n",(0,i.jsxs)(n.p,{children:["Any incoming connection is required to present a client certificate signed by the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nEnvoy presents a certificate chain of the mesh\ncertificate of the workload and the intermediate CA certificate as the server certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["If the deployment contains workloads which should be reachable from outside the\nService Mesh, while still handing out the certificate chain, disable client\nauthentication by setting the annotation ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-ingress"})," as\n",(0,i.jsx)(n.code,{children:"<name>#<port>#false"}),". Separate multiple entries with ",(0,i.jsx)(n.code,{children:"##"}),". You can choose any\ndescriptive string identifying the service on the given port for the ",(0,i.jsx)(n.code,{children:"<name>"})," field,\nas it's only informational."]}),"\n",(0,i.jsxs)(n.p,{children:["Disable redirection and TLS termination altogether by specifying\n",(0,i.jsx)(n.code,{children:"<name>#<port>#true"}),". This can be beneficial if the workload itself handles TLS\non that port or if the information exposed on this port is non-sensitive."]}),"\n",(0,i.jsx)(n.p,{children:"The following example workload exposes a web service on port 8080 and metrics on\nport 7890. The web server is exposed to a 3rd party end-user which wants to\nverify the deployment, therefore it's still required that the server hands out\nit certificate chain signed by the mesh CA certificate. The metrics should be\nexposed via TCP without TLS."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: web-svc\n image: ghcr.io/edgelesssys/frontend:v1.2.3@...\n ports:\n - containerPort: 8080\n name: web\n - containerPort: 7890\n name: metrics\n'})}),"\n",(0,i.jsxs)(n.p,{children:["When invoking ",(0,i.jsx)(n.code,{children:"contrast generate"}),", the resulting deployment will be injected with the\nContrast service mesh as an init container."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# ...\n initContainers:\n - env:\n - name: CONTRAST_INGRESS_PROXY_CONFIG\n value: "web#8080#false##metrics#7890#true"\n image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:latest"\n name: contrast-service-mesh\n restartPolicy: Always\n securityContext:\n capabilities:\n add:\n - NET_ADMIN\n privileged: true\n volumeMounts:\n - name: contrast-secrets\n mountPath: /contrast\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Note, that changing the environment variables of the sidecar container directly will\nonly have an effect if the workload isn't configured to automatically generate a\nservice mesh component on ",(0,i.jsx)(n.code,{children:"contrast generate"}),". Otherwise, the service mesh sidecar\ncontainer will be regenerated on every invocation of the command."]}),"\n",(0,i.jsx)(n.h3,{id:"egress",children:"Egress"}),"\n",(0,i.jsx)(n.p,{children:"To be able to route the egress traffic of the workload through Envoy, the remote\nendpoints' IP address and port must be configurable."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Choose an IP address inside the ",(0,i.jsx)(n.code,{children:"127.0.0.0/8"})," CIDR and a port not yet in use\nby the pod."]}),"\n",(0,i.jsx)(n.li,{children:"Configure the workload to connect to this IP address and port."}),"\n",(0,i.jsxs)(n.li,{children:["Set ",(0,i.jsx)(n.code,{children:"<name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port>"}),"\nas the ",(0,i.jsx)(n.code,{children:"contrast.edgeless.systems/servicemesh-egress"})," workload annotation. Separate multiple\nentries with ",(0,i.jsx)(n.code,{children:"##"}),". Choose any string identifying the service on the given port as\n",(0,i.jsx)(n.code,{children:"<name>"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["This redirects the traffic over Envoy. The endpoint must present a valid\ncertificate chain which must be verifiable with the\n",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/next/architecture/certificates#usage-of-the-different-certificates",children:"mesh CA certificate"}),".\nFurthermore, Envoy uses a certificate chain with the mesh certificate of the workload\nand the intermediate CA certificate as the client certificate."]}),"\n",(0,i.jsxs)(n.p,{children:["The following example workload has no ingress connections and two egress\nconnection to different microservices. The microservices are part\nof the confidential deployment. One is reachable under ",(0,i.jsx)(n.code,{children:"billing-svc:8080"})," and\nthe other under ",(0,i.jsx)(n.code,{children:"cart-svc:8080"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web\n annotations:\n contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"\nspec:\n replicas: 1\n template:\n spec:\n runtimeClassName: contrast-cc\n containers:\n - name: currency-conversion\n image: ghcr.io/edgelesssys/conversion:v1.2.3@...\n'})})]})}function l(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>c});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/cc4abb91.ccd0339e.js b/pr-preview/pr-1071/assets/js/cc4abb91.ccd0339e.js deleted file mode 100644 index af48cc8c57..0000000000 --- a/pr-preview/pr-1071/assets/js/cc4abb91.ccd0339e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[7234],{92898:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-1.2/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/getting-started/cluster-setup.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/getting-started/install"},"next":{"title":"Bare metal setup","permalink":"/contrast/pr-preview/pr-1071/getting-started/bare-metal"}}');var t=r(74848),a=r(28453);const o={},i="Create a cluster",c={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Install version 2.44.1 or newer of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),". Note that your package manager will likely install an outdated version."]}),"\n",(0,t.jsxs)(n.li,{children:["Install a recent version of ",(0,t.jsx)(n.a,{href:"https://kubernetes.io/docs/tasks/tools/",children:"kubectl"}),"."]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsx)(n.p,{children:"First, log in to your Azure subscription:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First, create a CoCo enabled AKS cluster with:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.30 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["For validation, list the available nodes using ",(0,t.jsx)(n.code,{children:"kubectl"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show a single node:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\n"})}),"\n",(0,t.jsxs)(n.p,{children:["\ud83e\udd73 Congratulations. You're now ready to set up your first application with Contrast. Follow this ",(0,t.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/examples/emojivoto",children:"example"})," to learn how."]}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>i});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ccad6777.80d23dee.js b/pr-preview/pr-1071/assets/js/ccad6777.80d23dee.js deleted file mode 100644 index c24269a95b..0000000000 --- a/pr-preview/pr-1071/assets/js/ccad6777.80d23dee.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9033],{38028:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-1.2/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/architecture/certificates.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/architecture/secrets"},"next":{"title":"Security considerations","permalink":"/contrast/pr-preview/pr-1071/architecture/security-considerations"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(86433).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},86433:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/cdb2b1a5.e36333bf.js b/pr-preview/pr-1071/assets/js/cdb2b1a5.e36333bf.js deleted file mode 100644 index 5f9c90cbd2..0000000000 --- a/pr-preview/pr-1071/assets/js/cdb2b1a5.e36333bf.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9119],{78496:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"examples/index","title":"Examples","description":"","source":"@site/versioned_docs/version-0.6/examples/index.md","sourceDirName":"examples","slug":"/examples/","permalink":"/contrast/pr-preview/pr-1071/0.6/examples/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/examples/index.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto"}}');var s=n(74848),o=n(28453),c=n(44074);const i={},l="Examples",a={},u=[];function d(e){const t={h1:"h1",header:"header",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"examples",children:"Examples"})}),"\n","\n",(0,s.jsx)(c.A,{})]})}function m(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},44074:(e,t,n)=>{n.d(t,{A:()=>b});var r=n(96540),s=n(34164),o=n(45357),c=n(14783),i=n(97639);const l=["zero","one","two","few","many","other"];function a(e){return l.filter((t=>e.includes(t)))}const u={locale:"en",pluralForms:a(["one","other"]),select:e=>1===e?"one":"other"};function d(){const{i18n:{currentLocale:e}}=(0,i.A)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:a(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),u}}),[e])}function m(){const e=d();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const s=n.select(t),o=n.pluralForms.indexOf(s);return r[Math.min(o,r.length-1)]}(n,t,e)}}var p=n(40877),f=n(23230),h=n(85225);const x={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};var g=n(74848);function j(e){let{href:t,children:n}=e;return(0,g.jsx)(c.A,{href:t,className:(0,s.A)("card padding--lg",x.cardContainer),children:n})}function v(e){let{href:t,icon:n,title:r,description:o}=e;return(0,g.jsxs)(j,{href:t,children:[(0,g.jsxs)(h.A,{as:"h2",className:(0,s.A)("text--truncate",x.cardTitle),title:r,children:[n," ",r]}),o&&(0,g.jsx)("p",{className:(0,s.A)("text--truncate",x.cardDescription),title:o,children:o})]})}function w(e){let{item:t}=e;const n=(0,o.Nr)(t),r=function(){const{selectMessage:e}=m();return t=>e(t,(0,f.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t}))}();return n?(0,g.jsx)(v,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??r(t.items.length)}):null}function y(e){let{item:t}=e;const n=(0,p.A)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,o.cC)(t.docId??void 0);return(0,g.jsx)(v,{href:t.href,icon:n,title:t.label,description:t.description??r?.description})}function C(e){let{item:t}=e;switch(t.type){case"link":return(0,g.jsx)(y,{item:t});case"category":return(0,g.jsx)(w,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function N(e){let{className:t}=e;const n=(0,o.$S)();return(0,g.jsx)(b,{items:n.items,className:t})}function b(e){const{items:t,className:n}=e;if(!t)return(0,g.jsx)(N,{...e});const r=(0,o.d1)(t);return(0,g.jsx)("section",{className:(0,s.A)("row",n),children:r.map(((e,t)=>(0,g.jsx)("article",{className:"col col--6 margin-bottom--lg",children:(0,g.jsx)(C,{item:e})},t)))})}},28453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>i});var r=n(96540);const s={},o=r.createContext(s);function c(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/cf49aa2b.a24fb11d.js b/pr-preview/pr-1071/assets/js/cf49aa2b.a24fb11d.js deleted file mode 100644 index 51e9555ed8..0000000000 --- a/pr-preview/pr-1071/assets/js/cf49aa2b.a24fb11d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4703],{18803:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>c});const r=JSON.parse('{"id":"getting-started/bare-metal","title":"Prepare a bare-metal instance","description":"Hardware and firmware setup","source":"@site/docs/getting-started/bare-metal.md","sourceDirName":"getting-started","slug":"/getting-started/bare-metal","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/getting-started/bare-metal.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/next/examples/emojivoto"}}');var s=n(74848),a=n(28453);const i={},o="Prepare a bare-metal instance",l={},c=[{value:"Hardware and firmware setup",id:"hardware-and-firmware-setup",level:2},{value:"Kernel Setup",id:"kernel-setup",level:2},{value:"K3s Setup",id:"k3s-setup",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",...(0,a.R)(),...e.components},{TabItem:n,Tabs:r}=t;return n||u("TabItem",!0),r||u("Tabs",!0),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"prepare-a-bare-metal-instance",children:"Prepare a bare-metal instance"})}),"\n",(0,s.jsx)(t.h2,{id:"hardware-and-firmware-setup",children:"Hardware and firmware setup"}),"\n",(0,s.jsxs)(r,{queryString:"vendor",children:[(0,s.jsxs)(n,{value:"amd",label:"AMD SEV-SNP",children:[(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsx)(t.li,{children:"Update your BIOS to a version that supports AMD SEV-SNP. Updating to the latest available version is recommended as newer versions will likely contain security patches for AMD SEV-SNP."}),"\n",(0,s.jsx)(t.li,{children:"Enter BIOS setup to enable SMEE, IOMMU, RMP coverage, and SEV-SNP. Set the SEV-ES ASID Space Limit to a non-zero number (higher is better)."}),"\n",(0,s.jsxs)(t.li,{children:["Download the latest firmware version for your processor from ",(0,s.jsx)(t.a,{href:"https://www.amd.com/de/developer/sev.html",children:"AMD"}),", unpack it, and place it in ",(0,s.jsx)(t.code,{children:"/lib/firmware/amd"}),"."]}),"\n"]}),(0,s.jsxs)(t.p,{children:["Consult AMD's ",(0,s.jsx)(t.a,{href:"https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/tuning-guides/58207-using-sev-with-amd-epyc-processors.pdf",children:"Using SEV with AMD EPYC Processors user guide"})," for more information."]})]}),(0,s.jsx)(n,{value:"intel",label:"Intel TDX",children:(0,s.jsxs)(t.p,{children:["Follow Canonical's instructions on ",(0,s.jsx)(t.a,{href:"https://github.com/canonical/tdx?tab=readme-ov-file#43-enable-intel-tdx-in-the-hosts-bios",children:"setting up Intel TDX in the host's BIOS"}),"."]})})]}),"\n",(0,s.jsx)(t.h2,{id:"kernel-setup",children:"Kernel Setup"}),"\n",(0,s.jsxs)(r,{queryString:"vendor",children:[(0,s.jsx)(n,{value:"amd",label:"AMD SEV-SNP",children:(0,s.jsx)(t.p,{children:"Install a kernel with version 6.11 or greater. If you're following this guide before 6.11 has been released, use 6.11-rc3. Don't use 6.11-rc4 - 6.11-rc6 as they contain a regression. 6.11-rc7+ might work."})}),(0,s.jsx)(n,{value:"intel",label:"Intel TDX",children:(0,s.jsxs)(t.p,{children:["Follow Canonical's instructions on ",(0,s.jsx)(t.a,{href:"https://github.com/canonical/tdx?tab=readme-ov-file#41-install-ubuntu-2404-server-image",children:"setting up Intel TDX on Ubuntu 24.04"}),". Note that Contrast currently only supports Intel TDX with Ubuntu 24.04."]})})]}),"\n",(0,s.jsxs)(t.p,{children:["Increase the ",(0,s.jsx)(t.code,{children:"user.max_inotify_instances"})," sysctl limit by adding ",(0,s.jsx)(t.code,{children:"user.max_inotify_instances=8192"})," to ",(0,s.jsx)(t.code,{children:"/etc/sysctl.d/99-sysctl.conf"})," and running ",(0,s.jsx)(t.code,{children:"sysctl --system"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"k3s-setup",children:"K3s Setup"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:["Follow the ",(0,s.jsx)(t.a,{href:"https://docs.k3s.io/",children:"K3s setup instructions"})," to create a cluster."]}),"\n",(0,s.jsxs)(t.li,{children:["Install a block storage provider such as ",(0,s.jsx)(t.a,{href:"https://docs.k3s.io/storage#setting-up-longhorn",children:"Longhorn"})," and mark it as the default storage class."]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}function u(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var r=n(96540);const s={},a=r.createContext(s);function i(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d18a22d8.846e7193.js b/pr-preview/pr-1071/assets/js/d18a22d8.846e7193.js deleted file mode 100644 index 7927f15ca9..0000000000 --- a/pr-preview/pr-1071/assets/js/d18a22d8.846e7193.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[447],{7939:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","source":"@site/versioned_docs/version-1.2/components/runtime.md","sourceDirName":"components","slug":"/components/runtime","permalink":"/contrast/pr-preview/pr-1071/components/runtime","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/components/runtime.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/components/overview"},"next":{"title":"Policies","permalink":"/contrast/pr-preview/pr-1071/components/policies"}}');var i=t(74848),r=t(28453);const o={},a="Contrast Runtime",d={},c=[{value:"Node-level components",id:"node-level-components",level:2},{value:"Containerd shim",id:"containerd-shim",level:3},{value:"Virtual machine manager (VMM)",id:"virtual-machine-manager-vmm",level:3},{value:"Snapshotters",id:"snapshotters",level:3},{value:"Pod-VM image",id:"pod-vm-image",level:3},{value:"Node installer DaemonSet",id:"node-installer-daemonset",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"contrast-runtime",children:"Contrast Runtime"})}),"\n",(0,i.jsxs)(n.p,{children:["The Contrast runtime is responsible for starting pods as confidential virtual machines.\nThis works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver.\nThe ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource defines a name for referencing the class and\na handler used by the container runtime (",(0,i.jsx)(n.code,{children:"containerd"}),") to identify the class."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: node.k8s.io/v1\nkind: RuntimeClass\nmetadata:\n # This name is used by pods in the runtimeClassName field\n name: contrast-cc-abcdef\n# This name is used by the\n# container runtime interface implementation (containerd)\nhandler: contrast-cc-abcdef\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Confidential pods that are part of a Contrast deployment need to specify the\nsame runtime class in the ",(0,i.jsx)(n.code,{children:"runtimeClassName"})," field, so Kubernetes uses the\nContrast runtime instead of the default ",(0,i.jsx)(n.code,{children:"containerd"})," / ",(0,i.jsx)(n.code,{children:"runc"})," handler."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v1\nkind: Pod\nspec:\n runtimeClassName: contrast-cc-abcdef\n # ...\n"})}),"\n",(0,i.jsx)(n.h2,{id:"node-level-components",children:"Node-level components"}),"\n",(0,i.jsxs)(n.p,{children:["The runtime consists of additional software components that need to be installed\nand configured on every SEV-SNP-enabled/TDX-enabled worker node.\nThis installation is performed automatically by the ",(0,i.jsxs)(n.a,{href:"#node-installer-daemonset",children:[(0,i.jsx)(n.code,{children:"node-installer"})," DaemonSet"]}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Runtime components",src:t(16548).A+"",width:"3814",height:"1669"})}),"\n",(0,i.jsx)(n.h3,{id:"containerd-shim",children:"Containerd shim"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"handler"})," field in the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," instructs containerd not to use the default ",(0,i.jsx)(n.code,{children:"runc"})," implementation.\nInstead, containerd invokes a custom plugin called ",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),".\nThis shim is described in more detail in the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/tree/3.4.0/src/runtime",children:"upstream source repository"})," and in the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md",children:"containerd documentation"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"virtual-machine-manager-vmm",children:"Virtual machine manager (VMM)"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"containerd"})," shim uses a virtual machine monitor to create a confidential virtual machine for every pod.\nOn AKS, Contrast uses ",(0,i.jsx)(n.a,{href:"https://www.cloudhypervisor.org",children:(0,i.jsx)(n.code,{children:"cloud-hypervisor"})}),".\nOn bare metal, Contrast uses ",(0,i.jsx)(n.a,{href:"https://www.qemu.org/",children:(0,i.jsx)(n.code,{children:"QEMU"})}),".\nThe appropriate files are installed on every node by the ",(0,i.jsx)(n.a,{href:"#node-installer-daemonset",children:(0,i.jsx)(n.code,{children:"node-installer"})}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"snapshotters",children:"Snapshotters"}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses ",(0,i.jsxs)(n.a,{href:"https://github.com/containerd/containerd/tree/v1.7.16/docs/snapshotters/README.md",children:[(0,i.jsx)(n.code,{children:"containerd"})," snapshotters"]})," to provide container images to the pod-VM.\nEach snapshotter consists of a host component that pulls container images and a guest component used to mount/pull container images."]}),"\n",(0,i.jsxs)(n.p,{children:["On AKS, Contrast uses the ",(0,i.jsx)(n.a,{href:"https://github.com/kata-containers/tardev-snapshotter",children:(0,i.jsx)(n.code,{children:"tardev"})})," snapshotter to provide container images as block devices to the pod-VM.\nThe ",(0,i.jsx)(n.code,{children:"tardev"})," snapshotter uses ",(0,i.jsx)(n.a,{href:"https://docs.kernel.org/admin-guide/device-mapper/verity.html",children:(0,i.jsx)(n.code,{children:"dm-verity"})})," to protect the integrity of container images.\nExpected ",(0,i.jsx)(n.code,{children:"dm-verity"})," container image hashes are part of Contrast runtime policies and are enforced by the kata-agent.\nThis enables workload attestation by specifying the allowed container image as part of the policy. Read ",(0,i.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/components/policies",children:"the chapter on policies"})," for more information."]}),"\n",(0,i.jsxs)(n.p,{children:["On bare metal, Contrast uses the ",(0,i.jsx)(n.a,{href:"https://github.com/containerd/nydus-snapshotter",children:(0,i.jsx)(n.code,{children:"nydus"})})," snapshotter to store metadata about the images. This metadata is communicated to the guest, so that it can pull the images itself."]}),"\n",(0,i.jsx)(n.h3,{id:"pod-vm-image",children:"Pod-VM image"}),"\n",(0,i.jsx)(n.p,{children:"Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem.\nThe IGVM file describes the initial memory contents of a pod-VM and consists of:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Linux kernel image"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"initrd"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.code,{children:"kernel commandline"})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem.\nThe root filesystem contains systemd as the init system, and the kata agent for managing the pod."}),"\n",(0,i.jsx)(n.p,{children:"This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime."}),"\n",(0,i.jsx)(n.h2,{id:"node-installer-daemonset",children:"Node installer DaemonSet"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"RuntimeClass"})," resource above registers the runtime with the Kubernetes api.\nThe node-level installation is carried out by the Contrast node-installer\n",(0,i.jsx)(n.code,{children:"DaemonSet"})," that ships with every Contrast release."]}),"\n",(0,i.jsx)(n.p,{children:"After deploying the installer, it performs the following steps on each node:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Install the Contrast containerd shim (",(0,i.jsx)(n.code,{children:"containerd-shim-contrast-cc-v2"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"cloud-hypervisor"})," or ",(0,i.jsx)(n.code,{children:"QEMU"})," as the virtual machine manager (VMM)"]}),"\n",(0,i.jsx)(n.li,{children:"Install an IGVM file or separate firmware and kernel files for pod-VMs of this class"}),"\n",(0,i.jsx)(n.li,{children:"Install a read only root filesystem disk image for the pod-VMs of this class"}),"\n",(0,i.jsxs)(n.li,{children:["Reconfigure ",(0,i.jsx)(n.code,{children:"containerd"})," by adding a runtime plugin that corresponds to the ",(0,i.jsx)(n.code,{children:"handler"})," field of the Kubernetes ",(0,i.jsx)(n.code,{children:"RuntimeClass"})]}),"\n",(0,i.jsxs)(n.li,{children:["Restart ",(0,i.jsx)(n.code,{children:"containerd"})," to make it aware of the new plugin"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},16548:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/runtime-c41c29928f42a90474f03213074a5f97.svg"},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const i={},r=s.createContext(i);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d1a11e04.07257942.js b/pr-preview/pr-1071/assets/js/d1a11e04.07257942.js deleted file mode 100644 index 64a55dde6e..0000000000 --- a/pr-preview/pr-1071/assets/js/d1a11e04.07257942.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8902],{97232:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/versioned_docs/version-0.8/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/0.8/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.8/features-limitations.md","tags":[],"version":"0.8","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/0.8/architecture/observability"},"next":{"title":"Telemetry","permalink":"/contrast/pr-preview/pr-1071/0.8/about/telemetry"}}');var r=t(74848),s=t(28453);const o={},a="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2},{value:"Automatic recovery and high availability",id:"automatic-recovery-and-high-availability",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,r.jsx)(n.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,r.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,r.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Bare-metal support"}),": Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Persistent volumes"}),": Contrast only supports volumes with ",(0,r.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-mode",children:(0,r.jsx)(n.code,{children:"volumeMode: Block"})}),". These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Port forwarding"}),": This feature ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,r.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,r.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,r.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Volume integrity checks"}),": While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ",(0,r.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,r.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,r.jsx)(n.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"automatic-recovery-and-high-availability",children:"Automatic recovery and high availability"}),"\n",(0,r.jsx)(n.p,{children:"The Contrast Coordinator is a singleton and can't be scaled to more than one instance.\nWhen this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually.\nIn a future release, we plan to support distributed Coordinator instances that can recover automatically."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var i=t(96540);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d2630e76.f829190e.js b/pr-preview/pr-1071/assets/js/d2630e76.f829190e.js deleted file mode 100644 index e9ee9cfee3..0000000000 --- a/pr-preview/pr-1071/assets/js/d2630e76.f829190e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[9634],{22846:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>u,frontMatter:()=>s,metadata:()=>n,toc:()=>p});const n=JSON.parse('{"id":"architecture/network-encryption/protocols-and-keys","title":"protocols-and-keys","description":"","source":"@site/versioned_docs/version-0.5/architecture/network-encryption/protocols-and-keys.md","sourceDirName":"architecture/network-encryption","slug":"/architecture/network-encryption/protocols-and-keys","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/network-encryption/protocols-and-keys.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Sidecar","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar"}}');var o=r(74848),c=r(28453);const s={},i=void 0,a={},p=[];function d(e){return(0,o.jsx)(o.Fragment,{})}function u(e={}){const{wrapper:t}={...(0,c.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d()}},28453:(e,t,r)=>{r.d(t,{R:()=>s,x:()=>i});var n=r(96540);const o={},c=n.createContext(o);function s(e){const t=n.useContext(c);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),n.createElement(c.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d28f01c4.deb2a417.js b/pr-preview/pr-1071/assets/js/d28f01c4.deb2a417.js deleted file mode 100644 index d6c5006735..0000000000 --- a/pr-preview/pr-1071/assets/js/d28f01c4.deb2a417.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2759],{55045:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"architecture/security-considerations","title":"Security Considerations","description":"Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits).","source":"@site/versioned_docs/version-1.2/architecture/security-considerations.md","sourceDirName":"architecture","slug":"/architecture/security-considerations","permalink":"/contrast/pr-preview/pr-1071/architecture/security-considerations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/architecture/security-considerations.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/architecture/certificates"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/architecture/observability"}}');var r=n(74848),s=n(28453);const o={},a="Security Considerations",c={},d=[{value:"General recommendations",id:"general-recommendations",level:2},{value:"Authentication",id:"authentication",level:3},{value:"Encryption",id:"encryption",level:3},{value:"Contrast security guarantees",id:"contrast-security-guarantees",level:2},{value:"Limitations inherent to policy checking",id:"limitations-inherent-to-policy-checking",level:3},{value:"Logs",id:"logs",level:3}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"security-considerations",children:"Security Considerations"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast ensures application integrity and provides secure means of communication and bootstrapping (see ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"security benefits"}),").\nHowever, care must be taken when interacting with the outside of Contrast's confidential environment.\nThis page presents some tips for writing secure applications and outlines the trust boundaries app developers need to know."]}),"\n",(0,r.jsx)(t.h2,{id:"general-recommendations",children:"General recommendations"}),"\n",(0,r.jsx)(t.h3,{id:"authentication",children:"Authentication"}),"\n",(0,r.jsx)(t.p,{children:"The application receives credentials from the Contrast Coordinator during initialization.\nThis allows to authenticate towards peers and to verify credentials received from peers.\nThe application should use the certificate bundle to authenticate incoming requests and be wary of unauthenticated requests or requests with a different root of trust (for example the internet PKI)."}),"\n",(0,r.jsx)(t.p,{children:"The recommendation to authenticate not only applies to network traffic, but also to volumes, GPUs and other devices.\nGenerally speaking, all information provided by the world outside the confidential VM should be treated with due scepticism, especially if it's not authenticated.\nCommon cases where Kubernetes apps interact with external services include DNS, Kubernetes API clients and cloud storage endpoints."}),"\n",(0,r.jsx)(t.h3,{id:"encryption",children:"Encryption"}),"\n",(0,r.jsx)(t.p,{children:"Any external persistence should be encrypted with an authenticated cipher.\nThis recommendation applies to block devices or filesystems mounted into the container, but also to cloud blob storage or external databases."}),"\n",(0,r.jsx)(t.h2,{id:"contrast-security-guarantees",children:"Contrast security guarantees"}),"\n",(0,r.jsx)(t.p,{children:"If an application authenticates with a certificate signed by the Contrast Mesh CA of a given manifest, Contrast provides the following guarantees:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:"The container images used by the app are the images specified in the resource definitions."}),"\n",(0,r.jsx)(t.li,{children:"The command line arguments of containers are exactly the arguments specified in the resource definitions."}),"\n",(0,r.jsx)(t.li,{children:"All environment variables are either specified in resource definitions, in the container image manifest or in a settings file for the Contrast CLI."}),"\n",(0,r.jsx)(t.li,{children:"The containers run in a confidential VM that matches the reference values in the manifest."}),"\n",(0,r.jsx)(t.li,{children:"The containers' root filesystems are mounted in encrypted memory."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"limitations-inherent-to-policy-checking",children:"Limitations inherent to policy checking"}),"\n",(0,r.jsx)(t.p,{children:"Workload policies serve as workload identities.\nFrom the perspective of the Contrast Coordinator, all workloads that authenticate with the same policy are equal.\nThus, it's not possible to disambiguate, for example, pods spawned from a deployment or to limit the amount of certificates issued per policy."}),"\n",(0,r.jsxs)(t.p,{children:["Container image references from Kubernetes resource definitions are taken into account when generating the policy.\nA mutable reference may lead to policy failures or unverified image content, depending on the Contrast runtime.\nReliability and security can only be ensured with a full image reference, including digest.\nThe ",(0,r.jsxs)(t.a,{href:"https://docs.docker.com/reference/cli/docker/image/pull/#pull-an-image-by-digest-immutable-identifier",children:[(0,r.jsx)(t.code,{children:"docker pull"})," documentation"]})," explains pinned image references in detail."]}),"\n",(0,r.jsxs)(t.p,{children:["Policies can only verify what can be inferred at generation time.\nSome attributes of Kubernetes pods can't be predicted and thus can't be verified.\nParticularly the ",(0,r.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/workloads/pods/downward-api/",children:"downward API"})," contains many fields that are dynamic or depend on the host environment, rendering it unsafe for process environment or arguments.\nThe same goes for ",(0,r.jsx)(t.code,{children:"ConfigMap"})," and ",(0,r.jsx)(t.code,{children:"Secret"})," resources, which can also be used to populate container fields.\nIf the application requires such external information, it should be injected as a mount point and carefully inspected before use."]}),"\n",(0,r.jsx)(t.p,{children:"Another type of dynamic content are persistent volumes.\nAny volumes mounted to the pod need to be scrutinized, and sensitive data must not be written to unprotected volumes.\nIdeally, a volume is mounted as a raw block device and authenticated encryption is added within the confidential container."}),"\n",(0,r.jsx)(t.h3,{id:"logs",children:"Logs"}),"\n",(0,r.jsx)(t.p,{children:"By default, container logs are visible to the host.\nSensitive information shouldn't be logged."}),"\n",(0,r.jsxs)(t.p,{children:["As of right now, hiding logs isn't natively supported.\nIf ",(0,r.jsx)(t.code,{children:"ReadStreamRequest"})," is denied in the policy, the Kata Agent stops reading the logs.\nThis causes the pipes used for standard out and standard error to fill up and potentially deadlock the container.\nIf absolutely required, standard out and standard error should be manually redirected to ",(0,r.jsx)(t.code,{children:"/dev/null"})," inside the container."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(96540);const r={},s=i.createContext(r);function o(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d43358e1.90202999.js b/pr-preview/pr-1071/assets/js/d43358e1.90202999.js deleted file mode 100644 index 5bee705202..0000000000 --- a/pr-preview/pr-1071/assets/js/d43358e1.90202999.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3024],{61156:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>s,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","source":"@site/versioned_docs/version-1.2/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/basics/security-benefits.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/basics/features"}}');var r=n(74848),a=n(28453);const s={},o="Contrast security overview",c={},d=[{value:"Confidential computing foundation",id:"confidential-computing-foundation",level:2},{value:"Components of a Contrast deployment",id:"components-of-a-contrast-deployment",level:2},{value:"Personas in a Contrast deployment",id:"personas-in-a-contrast-deployment",level:2},{value:"Threat model and mitigations",id:"threat-model-and-mitigations",level:2},{value:"Possible attacks",id:"possible-attacks",level:3},{value:"Attack surfaces",id:"attack-surfaces",level:3},{value:"Threats and mitigations",id:"threats-and-mitigations",level:3},{value:"Attacks on the confidential container environment",id:"attacks-on-the-confidential-container-environment",level:4},{value:"Attacks on the Coordinator attestation service",id:"attacks-on-the-coordinator-attestation-service",level:4},{value:"Attacks on workloads",id:"attacks-on-workloads",level:4},{value:"Examples of Contrast's threat model in practice",id:"examples-of-contrasts-threat-model-in-practice",level:2}];function h(e){const t={a:"a",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast-security-overview",children:"Contrast security overview"})}),"\n",(0,r.jsx)(t.p,{children:"This document outlines the security measures of Contrast and its capability to counter various threats.\nContrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership."}),"\n",(0,r.jsx)(t.p,{children:"Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging.\nThis is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance.\nIt allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider."}),"\n",(0,r.jsx)(t.h2,{id:"confidential-computing-foundation",children:"Confidential computing foundation"}),"\n",(0,r.jsx)(t.p,{children:"Leveraging Confidential Computing technology, Contrast provides three defining security properties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Encryption of data in use"}),": Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Workload isolation"}),": Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime.\nThe workload isolation and remote attestation involves two phases:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation."}),"\n",(0,r.jsx)(t.li,{children:"A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation."}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["For more details on confidential computing see our ",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"}),".\nThe ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"attestation architecture"})," describes Contrast's attestation process and the resulting chain of trust in detail."]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-a-contrast-deployment",children:"Components of a Contrast deployment"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses the Kubernetes runtime of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/confidential-containers",children:"Confidential Containers"})," project.\nConfidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment.\nThe TCB is the totality of elements in a computing environment that must be trusted not to be compromised.\nA smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the ",(0,r.jsx)(t.em,{children:"cloud & datacenter infrastructure"})," and the ",(0,r.jsx)(t.em,{children:"physical hosts"}),", including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red).\nIn the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB.\nTheir integrity is ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"verifiable through remote attestation"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Contrast uses ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/confidential-containers",children:"hardware-based mechanisms"}),", specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload.\nThis implies that both the CPU and its microcode are integral components of the TCB.\nHowever, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"TCB comparison",src:n(60455).A+"",width:"4052",height:"1380"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast adds the following components to a deployment that become part of the TCB.\nThe components that are part of the TCB are:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The workload containers"}),": Container images that run the actual application."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"The runtime environment"})}),": The confidential micro-VM that acts as the container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"The sidecar containers"})}),": Containers that provide additional functionality such as ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-initializer",children:"initialization"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies",children:"The runtime policies"})}),": Policies that enforce the runtime environments for the workload containers during their lifetime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-manifest",children:"The manifest"})}),": A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-coordinator",children:"The Coordinator"})}),": An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"personas-in-a-contrast-deployment",children:"Personas in a Contrast deployment"}),"\n",(0,r.jsx)(t.p,{children:"In a Contrast deployment, there are three parties:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The container image provider"}),", who creates the container images that represent the application that has access to the protected data."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The workload operator"}),", who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"The data owner"}),", who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties."}),"\n",(0,r.jsx)(t.p,{children:"The following diagram shows the system components and parties."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Components and parties",src:n(32983).A+"",width:"3588",height:"2017"})}),"\n",(0,r.jsx)(t.h2,{id:"threat-model-and-mitigations",children:"Threat model and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"This section describes the threat vectors that Contrast helps to mitigate."}),"\n",(0,r.jsx)(t.p,{children:"The following attacks are out of scope for this document:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the application code itself, such as insufficient access controls."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the Confidential Computing hardware directly, such as side-channel attacks."}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the availability, such as denial-of-service (DOS) attacks."}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"possible-attacks",children:"Possible attacks"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to defend against five possible attacks:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud insider"}),": malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious cloud co-tenant"}),': malicious cloud user ("hackers") may break out of their tenancy and access other tenants\' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the ',(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, without the physical access."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious workload operator"}),": malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the ",(0,r.jsx)(t.em,{children:"cloud insider access"})," scenario, with access to everything that's above the hypervisor level."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious attestation client"}),": this attacker connects to the attestation service and sends malformed request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"A malicious container image provider"}),": a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"attack-surfaces",children:"Attack surfaces"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes the attack surfaces that are available to attackers."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Attacker"}),(0,r.jsx)(t.th,{children:"Target"}),(0,r.jsx)(t.th,{children:"Attack surface"}),(0,r.jsx)(t.th,{children:"Risks"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Physical memory"}),(0,r.jsx)(t.td,{children:"Attacker can dump the physical memory of the workloads."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk reads"}),(0,r.jsx)(t.td,{children:"Anything read from the disk is within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Disk writes"}),(0,r.jsx)(t.td,{children:"Anything written to disk is visible to an attacker."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Kubernetes Control Plane"}),(0,r.jsx)(t.td,{children:"Instance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Container Runtime"}),(0,r.jsx)(t.td,{children:'The attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Cloud insider, cloud hacker, workload operator"}),(0,r.jsx)(t.td,{children:"Confidential Container, Workload"}),(0,r.jsx)(t.td,{children:"Network"}),(0,r.jsx)(t.td,{children:"Intra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Attestation client"}),(0,r.jsx)(t.td,{children:"Coordinator attestation service"}),(0,r.jsx)(t.td,{children:"Attestation requests"}),(0,r.jsx)(t.td,{children:"The attestation service has complex, crypto-heavy logic that's challenging to write defensively."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Container image provider"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"Workload"}),(0,r.jsx)(t.td,{children:"This attacker might release an upgrade to the workload containing harmful changes, such as a backdoor."})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"threats-and-mitigations",children:"Threats and mitigations"}),"\n",(0,r.jsx)(t.p,{children:"Contrast shields a workload from the aforementioned threats with three main components:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"runtime environment"})," safeguards against the physical memory and disk attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies",children:"runtime policies"})," safeguard against the Kubernetes control plane and container runtime attack surface."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh"})," safeguards against the network attack surface."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on the attestation service"}),"\n",(0,r.jsx)(t.li,{children:"Attacks on workloads"}),"\n"]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-confidential-container-environment",children:"Attacks on the confidential container environment"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to the confidential container environment."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection of the launcher or image repository."}),(0,r.jsx)(t.td,{children:"An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies the workload image on disk after it was downloaded and measured."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker modifies a container's runtime environment configuration in the Kubernetes control plane."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/policies",children:"runtime policies"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-the-coordinator-attestation-service",children:"Attacks on the Coordinator attestation service"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies to the attestation service."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"attestation"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol."}),(0,r.jsx)(t.td,{children:"Within the network between your workload and the Coordinator."})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process."}),(0,r.jsx)(t.td,{children:"This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-coordinator",children:"Coordinator"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack."}),(0,r.jsx)(t.td,{children:"In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/overview#the-coordinator",children:"Coordinator"})]})]})]})]}),"\n",(0,r.jsx)(t.h4,{id:"attacks-on-workloads",children:"Attacks on workloads"}),"\n",(0,r.jsx)(t.p,{children:"This table describes potential threats and mitigation strategies related to workloads."}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Threat"}),(0,r.jsx)(t.th,{children:"Mitigation"}),(0,r.jsx)(t.th,{children:"Mitigation implementation"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker intercepts the network connection between two workload containers."}),(0,r.jsx)(t.td,{children:"This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/service-mesh",children:"service mesh"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker reads or modifies data written to disk via persistent volumes."}),(0,r.jsx)(t.td,{children:"Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts."}),(0,r.jsxs)(t.td,{children:["Within the Contrast ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/components/runtime",children:"runtime environment"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"An attacker publishes a new image version containing malicious code."}),(0,r.jsx)(t.td,{children:"The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged."}),(0,r.jsxs)(t.td,{children:["Within the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"attestation"})]})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:"examples-of-contrasts-threat-model-in-practice",children:"Examples of Contrast's threat model in practice"}),"\n",(0,r.jsx)(t.p,{children:"The following table describes three example use cases and how they map to the defined threat model in this document:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Use Case"}),(0,r.jsx)(t.th,{children:"Example Scenario"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Migrate sensitive workloads to the cloud"}),(0,r.jsxs)(t.td,{children:["TechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"attestation terminology"}),", they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Make your SaaS more trustworthy"}),(0,r.jsxs)(t.td,{children:["SaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/architecture/attestation",children:"relying party"})," is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator."]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"Simplify regulatory compliance"}),(0,r.jsx)(t.td,{children:"HealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator."})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data."})]})}function l(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},32983:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/personas-0d51d0cc03b37c9f45b914bbea163646.svg"},60455:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/tcb-eebc94816125417eaf55b0e5e96bba37.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(96540);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d580a1fd.eecaa741.js b/pr-preview/pr-1071/assets/js/d580a1fd.eecaa741.js deleted file mode 100644 index 1963ef5cee..0000000000 --- a/pr-preview/pr-1071/assets/js/d580a1fd.eecaa741.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1734],{42533:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>s,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>p});const r=JSON.parse('{"id":"architecture/components/init-container","title":"init-container","description":"","source":"@site/versioned_docs/version-0.5/architecture/components/init-container.md","sourceDirName":"architecture/components","slug":"/architecture/components/init-container","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/components/init-container.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Coordinator","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator"},"next":{"title":"CLI","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli"}}');var o=n(74848),c=n(28453);const i={},s=void 0,a={},p=[];function u(t){return(0,o.jsx)(o.Fragment,{})}function d(t={}){const{wrapper:e}={...(0,c.R)(),...t.components};return e?(0,o.jsx)(e,{...t,children:(0,o.jsx)(u,{...t})}):u()}},28453:(t,e,n)=>{n.d(e,{R:()=>i,x:()=>s});var r=n(96540);const o={},c=r.createContext(o);function i(t){const e=r.useContext(c);return r.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function s(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:i(t.components),r.createElement(c.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/d77304ba.d5619a4f.js b/pr-preview/pr-1071/assets/js/d77304ba.d5619a4f.js deleted file mode 100644 index a4befb59e4..0000000000 --- a/pr-preview/pr-1071/assets/js/d77304ba.d5619a4f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4233],{15796:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-1.0/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/basics/confidential-containers.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"What is Contrast?","permalink":"/contrast/pr-preview/pr-1071/1.0/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/dacf14a0.ff767a68.js b/pr-preview/pr-1071/assets/js/dacf14a0.ff767a68.js deleted file mode 100644 index 65841f8bcd..0000000000 --- a/pr-preview/pr-1071/assets/js/dacf14a0.ff767a68.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[101],{48763:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-0.9/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/0.9/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/getting-started/install.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/features"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup"}}');var r=s(74848),a=s(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v0.9.0/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,s)=>{s.d(e,{R:()=>o,x:()=>i});var n=s(96540);const r={},a=n.createContext(r);function o(t){const e=n.useContext(a);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),n.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/de615ffd.5ba725be.js b/pr-preview/pr-1071/assets/js/de615ffd.5ba725be.js deleted file mode 100644 index 43d668d2c0..0000000000 --- a/pr-preview/pr-1071/assets/js/de615ffd.5ba725be.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1321],{85230:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","source":"@site/versioned_docs/version-0.7/deployment.md","sourceDirName":".","slug":"/deployment","permalink":"/contrast/pr-preview/pr-1071/0.7/deployment","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/deployment.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto"},"next":{"title":"Components","permalink":"/contrast/pr-preview/pr-1071/0.7/components/"}}');var r=t(74848),i=t(28453);const o={},a="Workload deployment",c={},l=[{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:2},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:2},{value:"Prepare your Kubernetes resources",id:"prepare-your-kubernetes-resources",level:2},{value:"RuntimeClass",id:"runtimeclass",level:3},{value:"Handling TLS",id:"handling-tls",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:2},{value:"Apply the resources",id:"apply-the-resources",level:2},{value:"Connect to the Contrast Coordinator",id:"connect-to-the-contrast-coordinator",level:2},{value:"Set the manifest",id:"set-the-manifest",level:2},{value:"Verify the Coordinator",id:"verify-the-coordinator",level:2},{value:"Communicate with workloads",id:"communicate-with-workloads",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components},{TabItem:t,Tabs:s}=n;return t||p("TabItem",!0),s||p("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"workload-deployment",children:"Workload deployment"})}),"\n",(0,r.jsx)(n.p,{children:"The following instructions will guide you through the process of making an existing Kubernetes deployment\nconfidential and deploying it together with Contrast."}),"\n",(0,r.jsxs)(n.p,{children:["A running CoCo-enabled cluster is required for these steps, see the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup",children:"setup guide"})," on how to set it up."]}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,r.jsxs)(n.p,{children:["Contrast depends on a ",(0,r.jsxs)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/runtime",children:["custom Kubernetes ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," (",(0,r.jsx)(n.code,{children:"contrast-cc"}),")"]}),",\nwhich needs to be installed in the cluster prior to the Coordinator or any confidential workloads.\nThis consists of a ",(0,r.jsx)(n.code,{children:"RuntimeClass"})," resource and a ",(0,r.jsx)(n.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/runtime.yml\n"})}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"Install the latest Contrast Coordinator release, comprising a single replica deployment and a\nLoadBalancer service, into your cluster."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v0.7.3/coordinator.yml\n"})}),"\n",(0,r.jsx)(n.h2,{id:"prepare-your-kubernetes-resources",children:"Prepare your Kubernetes resources"}),"\n",(0,r.jsx)(n.p,{children:"Your Kubernetes resources need some modifications to run as Confidential Containers.\nThis section guides you through the process and outlines the necessary changes."}),"\n",(0,r.jsx)(n.h3,{id:"runtimeclass",children:"RuntimeClass"}),"\n",(0,r.jsx)(n.p,{children:"Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files\nunchanged, you can copy the files into a separate local directory.\nYou can also generate files from a Helm chart or from a Kustomization."}),"\n",(0,r.jsxs)(s,{groupId:"yaml-source",children:[(0,r.jsx)(t,{value:"kustomize",label:"kustomize",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nkustomize build $MY_RESOURCE_DIR > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"helm",label:"helm",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir resources\nhelm template $RELEASE_NAME $CHART_NAME > resources/all.yml\n"})})}),(0,r.jsx)(t,{value:"copy",label:"copy",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"cp -R $MY_RESOURCE_DIR resources/\n"})})})]}),"\n",(0,r.jsxs)(n.p,{children:["To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers,\nadd ",(0,r.jsx)(n.code,{children:"runtimeClassName: contrast-cc"})," to the pod spec (pod definition or template).\nThis is a placeholder name that will be replaced by a versioned ",(0,r.jsx)(n.code,{children:"runtimeClassName"})," when generating policies."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"spec: # v1.PodSpec\n runtimeClassName: contrast-cc\n"})}),"\n",(0,r.jsx)(n.h3,{id:"handling-tls",children:"Handling TLS"}),"\n",(0,r.jsxs)(n.p,{children:["In the initialization process, the ",(0,r.jsx)(n.code,{children:"contrast-tls-certs"})," shared volume is populated with X.509 certificates for your workload.\nThese certificates are used by the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"Contrast Service Mesh"}),", but can also be used by your application directly.\nThe following tab group explains the setup for both scenarios."]}),"\n",(0,r.jsxs)(s,{groupId:"tls",children:[(0,r.jsxs)(t,{value:"mesh",label:"Drop-in service mesh",children:[(0,r.jsx)(n.p,{children:"Contrast can be configured to handle TLS in a sidecar container.\nThis is useful for workloads that are hard to configure with custom certificates, like Java applications."}),(0,r.jsx)(n.p,{children:"Configuration of the sidecar depends heavily on the application.\nThe following example is for an application with these properties:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication."}),"\n",(0,r.jsx)(n.li,{children:"The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text."}),"\n",(0,r.jsx)(n.li,{children:"All other endpoints require client authentication."}),"\n",(0,r.jsxs)(n.li,{children:["The app connects to a Kubernetes service ",(0,r.jsx)(n.code,{children:"backend.default:4001"}),", which requires client authentication."]}),"\n"]}),(0,r.jsx)(n.p,{children:"Add the following annotations to your workload:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"\n contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"\n'})}),(0,r.jsxs)(n.p,{children:["During the ",(0,r.jsx)(n.code,{children:"generate"})," step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically.\nThe only change required to the app itself is to let it connect to ",(0,r.jsx)(n.code,{children:"127.0.0.2:4001"})," to reach the backend service.\nYou can find more detailed documentation in the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"Service Mesh chapter"}),"."]})]}),(0,r.jsxs)(t,{value:"go",label:"Go integration",children:[(0,r.jsxs)(n.p,{children:["The mesh certificate contained in ",(0,r.jsx)(n.code,{children:"certChain.pem"})," authenticates this workload, while the mesh CA certificate ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," authenticates its peers.\nYour app should turn on client authentication to ensure peers are running as confidential containers, too.\nSee the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates",children:"Certificate Authority"})," section for detailed information about these certificates."]}),(0,r.jsx)(n.p,{children:"The following example shows how to configure a Golang app, with error handling omitted for clarity."}),(0,r.jsxs)(s,{groupId:"golang-tls-setup",children:[(0,r.jsx)(t,{value:"client",label:"Client",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n RootCAs: caCerts,\n}\n'})})}),(0,r.jsx)(t,{value:"server",label:"Server",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-go",children:'caCerts := x509.NewCertPool()\ncaCert, _ := os.ReadFile("/tls-config/mesh-ca.pem")\ncaCerts.AppendCertsFromPEM(caCert)\ncert, _ := tls.LoadX509KeyPair("/tls-config/certChain.pem", "/tls-config/key.pem")\ncfg := &tls.Config{\n Certificates: []tls.Certificate{cert},\n ClientAuth: tls.RequireAndVerifyClientCert,\n ClientCAs: caCerts,\n}\n'})})})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,r.jsxs)(n.p,{children:["Run the ",(0,r.jsx)(n.code,{children:"generate"})," command to add the necessary components to your deployment files.\nThis will add the Contrast Initializer to every workload with the specified ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class\nand the Contrast Service Mesh to all workloads that have a specified configuration.\nAfter that, it will generate the execution policies and add them as annotations to your deployment files.\nA ",(0,r.jsx)(n.code,{children:"manifest.json"})," with the reference values of your deployment will be created."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate resources/\n"})}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the ",(0,r.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/features-limitations#runtime-policies",children:"current limitations"})," for more details."]})}),"\n",(0,r.jsx)(n.p,{children:"If you don't want the Contrast Initializer to automatically be added to your\nworkloads, there are two ways you can skip the Initializer injection step,\ndepending on how you want to customize your deployment."}),"\n",(0,r.jsxs)(s,{groupId:"injection",children:[(0,r.jsxs)(t,{value:"flag",label:"Command-line flag",children:[(0,r.jsxs)(n.p,{children:["You can disable the Initializer injection completely by specifying the\n",(0,r.jsx)(n.code,{children:"--skip-initializer"})," flag in the ",(0,r.jsx)(n.code,{children:"generate"})," command."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"contrast generate --skip-initializer resources/\n"})})]}),(0,r.jsxs)(t,{value:"annotation",label:"Per-workload annotation",children:[(0,r.jsxs)(n.p,{children:["If you want to disable the Initializer injection for a specific workload with\nthe ",(0,r.jsx)(n.code,{children:"contrast-cc"})," runtime class, you can do so by adding an annotation to the workload."]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...\n annotations:\n contrast.edgeless.systems/skip-initializer: "true"\n'})})]})]}),"\n",(0,r.jsxs)(n.p,{children:["When disabling the automatic Initializer injection, you can manually add the\nInitializer as a sidecar container to your workload before generating the\npolicies. Configure the workload to use the certificates written to the\n",(0,r.jsx)(n.code,{children:"contrast-tls-certs"})," ",(0,r.jsx)(n.code,{children:"volumeMount"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'# v1.PodSpec\nspec:\n initContainers:\n - env:\n - name: COORDINATOR_HOST\n value: coordinator\n image: "ghcr.io/edgelesssys/contrast/initializer:v0.7.3@sha256:55475365c8177420ff3b27ad48bb0f38f8a92bfe754f50f1ed97f50f17ee23b8"\n name: contrast-initializer\n volumeMounts:\n - mountPath: /tls-config\n name: contrast-tls-certs\n volumes:\n - emptyDir: {}\n name: contrast-tls-certs\n'})}),"\n",(0,r.jsx)(n.h2,{id:"apply-the-resources",children:"Apply the resources"}),"\n",(0,r.jsx)(n.p,{children:"Apply the resources to the cluster. Your workloads will block in the initialization phase until a\nmanifest is set at the Coordinator."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl apply -f resources/\n"})}),"\n",(0,r.jsx)(n.h2,{id:"connect-to-the-contrast-coordinator",children:"Connect to the Contrast Coordinator"}),"\n",(0,r.jsx)(n.p,{children:"For the next steps, we will need to connect to the Coordinator. The released Coordinator resource\nincludes a LoadBalancer definition we can use."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Port-forwarding of Confidential Containers",type:"info",children:[(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"kubectl port-forward"})," uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim.\nIf you can't use a public load balancer, you can deploy a ",(0,r.jsx)(n.a,{href:"https://github.com/edgelesssys/contrast/blob/ddc371b/deployments/emojivoto/portforwarder.yml",children:"port-forwarder"}),".\nThe port-forwarder relays traffic from a CoCo pod and can be accessed via ",(0,r.jsx)(n.code,{children:"kubectl port-forward"}),"."]}),(0,r.jsxs)(n.p,{children:["Upstream tracking issue: ",(0,r.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"https://github.com/kata-containers/kata-containers/issues/1693"}),"."]})]}),"\n",(0,r.jsx)(n.h2,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,r.jsx)(n.p,{children:"Attest the Coordinator and set the manifest:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" resources/\n'})}),"\n",(0,r.jsx)(n.p,{children:"After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container\nwill fetch a certificate for the workload and the workload is started."}),"\n",(0,r.jsx)(n.h2,{id:"verify-the-coordinator",children:"Verify the Coordinator"}),"\n",(0,r.jsxs)(n.p,{children:["An end user (data owner) can verify the Contrast deployment using the ",(0,r.jsx)(n.code,{children:"verify"})," command."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The CLI will attest the Coordinator using embedded reference values. The CLI will write the service mesh\nroot certificate and the history of manifests into the ",(0,r.jsx)(n.code,{children:"verify/"})," directory. In addition, the policies referenced\nin the manifest are also written to the directory."]}),"\n",(0,r.jsx)(n.h2,{id:"communicate-with-workloads",children:"Communicate with workloads"}),"\n",(0,r.jsxs)(n.p,{children:["You can securely connect to the workloads using the Coordinator's ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"})," as a trusted CA certificate.\nFirst, expose the service on a public IP address via a LoadBalancer service:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"kubectl patch svc ${MY_SERVICE} -p '{\"spec\": {\"type\": \"LoadBalancer\"}}'\nkubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}\nlbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $lbip\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Subject alternative names and LoadBalancer IP",type:"info",children:[(0,r.jsx)(n.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field.\nValidation fails since the certificate contains no IP entries as a subject alternative name (SAN).\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})})]}),"\n",(0,r.jsxs)(n.p,{children:["Using ",(0,r.jsx)(n.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,r.jsx)(n.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}function p(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var s=t(96540);const r={},i=s.createContext(r);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/dfd9c366.ac551a18.js b/pr-preview/pr-1071/assets/js/dfd9c366.ac551a18.js deleted file mode 100644 index 777942ddd5..0000000000 --- a/pr-preview/pr-1071/assets/js/dfd9c366.ac551a18.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2454],{29026:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","source":"@site/versioned_docs/version-0.6/basics/features.md","sourceDirName":"basics","slug":"/basics/features","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/features","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/basics/features.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits"},"next":{"title":"Getting started","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/"}}');var r=n(74848),i=n(28453);const o={},a="Product features",c={},l=[];function d(e){const t={a:"a",h1:"h1",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"product-features",children:"Product features"})}),"\n",(0,r.jsx)(t.p,{children:"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment."}),"\n",(0,r.jsxs)(t.p,{children:["From a security perspective, Contrast employs the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers",children:"Confidential Containers"})," concept and provides ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",children:"security benefits"})," that go beyond individual containers, shielding your entire deployment from the underlying infrastructure."]}),"\n",(0,r.jsx)(t.p,{children:"From an operational perspective, Contrast provides the following key features:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Managed Kubernetes compatibility"}),": Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Lightweight installation"}),": Contrast can be integrated as a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/deployment",children:"day-2 operation"})," within existing clusters, adding minimal ",(0,r.jsx)(t.a,{href:"../architecture",children:"components"})," to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Remote attestation"}),": Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation\u2019s validity."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Service mesh"}),": Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the ",(0,r.jsx)(t.a,{href:"https://www.envoyproxy.io/",children:"envoy proxy"})," to ensure secure communications within your Kubernetes cluster."]}),"\n"]}),"\n"]})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e1e441c9.cfbd7c08.js b/pr-preview/pr-1071/assets/js/e1e441c9.cfbd7c08.js deleted file mode 100644 index af4902db05..0000000000 --- a/pr-preview/pr-1071/assets/js/e1e441c9.cfbd7c08.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2623],{54794:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>l,frontMatter:()=>a,metadata:()=>i,toc:()=>h});const i=JSON.parse('{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","source":"@site/versioned_docs/version-0.6/architecture/attestation.md","sourceDirName":"architecture","slug":"/architecture/attestation","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/architecture/attestation.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Architecture","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates"}}');var r=n(74848),s=n(28453);const a={},o="Attestation in Contrast",c={},h=[{value:"Attestation architecture",id:"attestation-architecture",level:2},{value:"Components of Contrast's attestation",id:"components-of-contrasts-attestation",level:2},{value:"Attester: Application Pods",id:"attester-application-pods",level:3},{value:"Verifier: Coordinator and CLI",id:"verifier-coordinator-and-cli",level:3},{value:"Relying Party: Data owner",id:"relying-party-data-owner",level:3},{value:"Evidence generation and appraisal",id:"evidence-generation-and-appraisal",level:2},{value:"Evidence types and formats",id:"evidence-types-and-formats",level:3},{value:"Appraisal policies for evidence",id:"appraisal-policies-for-evidence",level:3},{value:"Frequently asked questions about attestation in Contrast",id:"frequently-asked-questions-about-attestation-in-contrast",level:2},{value:"What's the purpose of remote attestation in Contrast?",id:"whats-the-purpose-of-remote-attestation-in-contrast",level:3},{value:"How does Contrast ensure the security of the attestation process?",id:"how-does-contrast-ensure-the-security-of-the-attestation-process",level:3},{value:"What security benefits does attestation provide?",id:"what-security-benefits-does-attestation-provide",level:3},{value:"How can you verify the authenticity of attestation results?",id:"how-can-you-verify-the-authenticity-of-attestation-results",level:3},{value:"How are attestation results used by relying parties?",id:"how-are-attestation-results-used-by-relying-parties",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"attestation-in-contrast",children:"Attestation in Contrast"})}),"\n",(0,r.jsxs)(t.p,{children:["This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html",children:"RFC 9334"}),".\nThe following gives a detailed description of Contrast's attestation architecture.\nAt the end of this document, we included an ",(0,r.jsx)(t.a,{href:"#frequently-asked-questions-about-attestation-in-contrast",children:"FAQ"})," that answers the most common questions regarding attestation in hindsight of the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",children:"security benefits"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"attestation-architecture",children:"Attestation architecture"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including ",(0,r.jsx)(t.em,{children:"Attesters"}),", ",(0,r.jsx)(t.em,{children:"Verifiers"}),", and ",(0,r.jsx)(t.em,{children:"Relying Parties"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Conceptual attestation architecture",src:n(45890).A+"",width:"592",height:"377"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 1: Conceptual attestation architecture. Taken from ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-1",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Attester"}),": Assigned to entities that are responsible for creating ",(0,r.jsx)(t.em,{children:"Evidence"})," which is then sent to a ",(0,r.jsx)(t.em,{children:"Verifier"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Verifier"}),": These entities utilize the ",(0,r.jsx)(t.em,{children:"Evidence"}),", ",(0,r.jsx)(t.em,{children:"Reference Values"}),", and ",(0,r.jsx)(t.em,{children:"Endorsements"}),". They assess the trustworthiness of the ",(0,r.jsx)(t.em,{children:"Attester"})," by applying an ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"}),". Following this assessment, ",(0,r.jsx)(t.em,{children:"Verifiers"})," generate ",(0,r.jsx)(t.em,{children:"Attestation Results"})," for use by ",(0,r.jsx)(t.em,{children:"Relying Parties"}),". The ",(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Evidence"})," may be provided by the ",(0,r.jsx)(t.em,{children:"Verifier Owner"}),", programmed into the ",(0,r.jsx)(t.em,{children:"Verifier"}),", or acquired through other means."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Relying Party"}),": Assigned to entities that utilize ",(0,r.jsx)(t.em,{children:"Attestation Results"}),', applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The ',(0,r.jsx)(t.em,{children:"Appraisal Policy"})," for ",(0,r.jsx)(t.em,{children:"Attestation Results"})," might be sourced from the ",(0,r.jsx)(t.em,{children:"Relying Party Owner"}),", configured by the owner, embedded in the ",(0,r.jsx)(t.em,{children:"Relying Party"}),", or obtained through other protocols or mechanisms."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"components-of-contrasts-attestation",children:"Components of Contrast's attestation"}),"\n",(0,r.jsx)(t.p,{children:"The key components involved in the attestation process of Contrast are detailed below:"}),"\n",(0,r.jsx)(t.h3,{id:"attester-application-pods",children:"Attester: Application Pods"}),"\n",(0,r.jsxs)(t.p,{children:["This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state.\nTheir evidence is rooted in the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers",children:"hardware measurements"})," from the CPU and their ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:"confidential VM environment"}),".\nThe details of this evidence are given below in the section on ",(0,r.jsx)(t.a,{href:"#evidence-generation-and-appraisal",children:"evidence generation and appraisal"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Attestation flow of a confidential pod",src:n(83451).A+"",width:"608",height:"697"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-3",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Pods run in Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/runtime",children:"runtime environment"})," (B), effectively within a confidential VM.\nDuring launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence.\nThe image is in ",(0,r.jsx)(t.a,{href:"https://github.com/microsoft/igvm",children:"IGVM format"}),", encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline.\nThe kernel cmdline contains the root hash for ",(0,r.jsx)(t.a,{href:"https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",children:"dm-verity"})," that ensures the integrity of the root filesystem.\nThe root filesystem contains all components of the container's runtime environment including the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers#kata-containers",children:"guest agent"})," (C)."]}),"\n",(0,r.jsxs)(t.p,{children:["In the userland, the guest agent takes care of enforcing the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#runtime-policies",children:"runtime policy"})," of the pod.\nWhile the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements.\nDuring the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/deployment#generate-policy-annotations-and-manifest",children:"deployment"})," the policy is annotated to the Kubernetes Pod resources.\nOn AMD SEV-SNP the hash of the policy is then added to the attestation report via the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field by the hypervisor.\nWhen provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the ",(0,r.jsx)(t.code,{children:"HOSTDATA"})," field."]}),"\n",(0,r.jsx)(t.p,{children:"In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy."}),"\n",(0,r.jsx)(t.h3,{id:"verifier-coordinator-and-cli",children:"Verifier: Coordinator and CLI"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-coordinator",children:"Coordinator"})," acts as a verifier within the Contrast deployment, configured with a ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-manifest",children:"Manifest"})," that defines the reference values and serves as an appraisal policy for all pods in the deployment.\nIt also pulls endorsements from hardware vendors to verify the hardware claims.\nThe Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester.\nIn RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods.\nIt collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Deployment attestation as a composite device",src:n(54302).A+"",width:"576",height:"393"})}),"\n",(0,r.jsxs)(t.p,{children:["Figure 3: Contrast deployment as a composite device. Based on the composite device in ",(0,r.jsx)(t.a,{href:"https://www.rfc-editor.org/rfc/rfc9334.html#figure-4",children:"RFC 9334"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/components/#the-cli-command-line-interface",children:"CLI"})," serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors.\nThese reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds."]}),"\n",(0,r.jsx)(t.h3,{id:"relying-party-data-owner",children:"Relying Party: Data owner"}),"\n",(0,r.jsxs)(t.p,{children:["A relying party in the Contrast scenario could be, for example, the ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",children:"data owner"})," that interacts with the application.\nThe relying party can use the CLI to obtain the attestation results and Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates",children:"CA certificates"})," bound to these results.\nThe CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections."]}),"\n",(0,r.jsx)(t.h2,{id:"evidence-generation-and-appraisal",children:"Evidence generation and appraisal"}),"\n",(0,r.jsx)(t.h3,{id:"evidence-types-and-formats",children:"Evidence types and formats"}),"\n",(0,r.jsx)(t.p,{children:"In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The hardware attestation report"}),": This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The launch measurements"}),": Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The runtime policy hash"}),": Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"appraisal-policies-for-evidence",children:"Appraisal policies for evidence"}),"\n",(0,r.jsx)(t.p,{children:"The appraisal of this evidence in Contrast is governed by two main components:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The Manifest"}),": A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"The CLI's appraisal policy"}),": This policy encompasses expected values of the Coordinator\u2019s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference."]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"frequently-asked-questions-about-attestation-in-contrast",children:"Frequently asked questions about attestation in Contrast"}),"\n",(0,r.jsx)(t.h3,{id:"whats-the-purpose-of-remote-attestation-in-contrast",children:"What's the purpose of remote attestation in Contrast?"}),"\n",(0,r.jsx)(t.p,{children:"Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment.\nThis process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment.\nBy validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with."}),"\n",(0,r.jsx)(t.h3,{id:"how-does-contrast-ensure-the-security-of-the-attestation-process",children:"How does Contrast ensure the security of the attestation process?"}),"\n",(0,r.jsx)(t.p,{children:"Contrast leverages hardware-rooted security features such as AMD SEV-SNP to generate cryptographic evidence of a pod\u2019s current state and configuration.\nThis evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment."}),"\n",(0,r.jsx)(t.h3,{id:"what-security-benefits-does-attestation-provide",children:"What security benefits does attestation provide?"}),"\n",(0,r.jsxs)(t.p,{children:["Attestation confirms the integrity of the runtime environment and the identity of the workloads.\nIt plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime.\nThe attestation provides integrity and authenticity guarantees, enabling relying parties\u2014such as workload operators or data owners\u2014to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators.\nMore details on the specific security benefits can be found ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",children:"here"}),"."]}),"\n",(0,r.jsx)(t.h3,{id:"how-can-you-verify-the-authenticity-of-attestation-results",children:"How can you verify the authenticity of attestation results?"}),"\n",(0,r.jsx)(t.p,{children:"Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself.\nThese proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering.\nFor further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code."}),"\n",(0,r.jsx)(t.h3,{id:"how-are-attestation-results-used-by-relying-parties",children:"How are attestation results used by relying parties?"}),"\n",(0,r.jsxs)(t.p,{children:["Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity.\nThereafter, the use of Contrast's ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates",children:"CA certificates in TLS connections"})," provides a practical approach to communicate securely with the application."]}),"\n",(0,r.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,r.jsx)(t.p,{children:"In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy.\nThis comprehensive approach allows Contrast to provide a high level of security assurance to its users."})]})}function l(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},54302:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-composite-device-b91e917a07f0f2bb082989317a9b053f.svg"},83451:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-pod-af4fc34dd97b1fdc20f66ecfa4fdeb1a.svg"},45890:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/attestation-rats-architecture-1a05fc2165e5c75a171e7b7832186bc3.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var i=n(96540);const r={},s=i.createContext(r);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e277c26a.ea7b0cc6.js b/pr-preview/pr-1071/assets/js/e277c26a.ea7b0cc6.js deleted file mode 100644 index 5b49ce2107..0000000000 --- a/pr-preview/pr-1071/assets/js/e277c26a.ea7b0cc6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1632],{78335:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-0.7/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/architecture/certificates.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/attestation"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/observability"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(46241).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},46241:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e2b3b970.4d762215.js b/pr-preview/pr-1071/assets/js/e2b3b970.4d762215.js deleted file mode 100644 index 257739c55f..0000000000 --- a/pr-preview/pr-1071/assets/js/e2b3b970.4d762215.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2841],{6428:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","source":"@site/versioned_docs/version-0.7/features-limitations.md","sourceDirName":".","slug":"/features-limitations","permalink":"/contrast/pr-preview/pr-1071/0.7/features-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/features-limitations.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/0.7/architecture/observability"},"next":{"title":"About","permalink":"/contrast/pr-preview/pr-1071/0.7/about/"}}');var s=t(74848),r=t(28453);const o={},a="Planned features and limitations",l={},c=[{value:"Availability",id:"availability",level:2},{value:"Kubernetes features",id:"kubernetes-features",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"Tooling integration",id:"tooling-integration",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"planned-features-and-limitations",children:"Planned features and limitations"})}),"\n",(0,s.jsx)(n.p,{children:"This section lists planned features and current limitations of Contrast."}),"\n",(0,s.jsx)(n.h2,{id:"availability",children:"Availability"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Platform support"}),": At present, Contrast is exclusively available on Azure AKS, supported by the ",(0,s.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"Confidential Container preview for AKS"}),". Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Bare-metal support"}),": Support for running Contrast on bare-metal Kubernetes will be available soon for AMD SEV and Intel TDX."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"kubernetes-features",children:"Kubernetes features"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Persistent volumes"}),": Not currently supported within Confidential Containers."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Port forwarding"}),": This feature ",(0,s.jsx)(n.a,{href:"https://github.com/kata-containers/kata-containers/issues/1693",children:"isn't yet supported by Kata Containers"}),". You can ",(0,s.jsx)(n.a,{href:"https://docs.edgeless.systems/contrast/deployment#connect-to-the-contrast-coordinator",children:"deploy a port-forwarder"})," as a workaround."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Resource limits"}),": There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Coverage"}),": While the enforcement of workload policies generally functions well, ",(0,s.jsx)(n.a,{href:"https://github.com/microsoft/kata-containers/releases/tag/3.2.0.azl0.genpolicy",children:"there are scenarios not yet fully covered"}),". It's crucial to review deployments specifically for these edge cases."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Order of events"}),": The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh sidecar"})," container runs ",(0,s.jsx)(n.em,{children:"before"})," the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Absence of events"}),": Policies can't ensure certain events have happened. A container, such as the ",(0,s.jsx)(n.a,{href:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",children:"service mesh sidecar"}),", can be omitted entirely. Environment variables may be missing."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Volume integrity checks"}),": While persistent volumes aren't supported yet, integrity checks don't currently cover other objects such as ",(0,s.jsx)(n.code,{children:"ConfigMaps"})," and ",(0,s.jsx)(n.code,{children:"Secrets"}),"."]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container affects the service mesh implementation of Contrast. Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly."})}),"\n",(0,s.jsx)(n.h2,{id:"tooling-integration",children:"Tooling integration"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"CLI availability"}),": The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var i=t(96540);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e446d98f.4ef79517.js b/pr-preview/pr-1071/assets/js/e446d98f.4ef79517.js deleted file mode 100644 index 04ae8b908c..0000000000 --- a/pr-preview/pr-1071/assets/js/e446d98f.4ef79517.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[221],{43008:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>i,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>p});const o=JSON.parse('{"id":"architecture/components/coordinator","title":"coordinator","description":"","source":"@site/versioned_docs/version-0.5/architecture/components/coordinator.md","sourceDirName":"architecture/components","slug":"/architecture/components/coordinator","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/architecture/components/coordinator.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Components","permalink":"/contrast/pr-preview/pr-1071/0.5/category/components"},"next":{"title":"Init container","permalink":"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container"}}');var r=n(74848),c=n(28453);const s={},i=void 0,a={},p=[];function d(t){return(0,r.jsx)(r.Fragment,{})}function u(t={}){const{wrapper:e}={...(0,c.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d()}},28453:(t,e,n)=>{n.d(e,{R:()=>s,x:()=>i});var o=n(96540);const r={},c=o.createContext(r);function s(t){const e=o.useContext(c);return o.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:s(t.components),o.createElement(c.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e55aefba.ab15b078.js b/pr-preview/pr-1071/assets/js/e55aefba.ab15b078.js deleted file mode 100644 index 400b97ba27..0000000000 --- a/pr-preview/pr-1071/assets/js/e55aefba.ab15b078.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[4113],{69732:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","source":"@site/versioned_docs/version-0.9/basics/confidential-containers.md","sourceDirName":"basics","slug":"/basics/confidential-containers","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/basics/confidential-containers.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"What is Contrast?","permalink":"/contrast/pr-preview/pr-1071/0.9/"},"next":{"title":"Security benefits","permalink":"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits"}}');var i=t(74848),o=t(28453);const r={},a="Confidential Containers",c={},d=[{value:"Kubernetes RuntimeClass",id:"kubernetes-runtimeclass",level:2},{value:"Kata Containers",id:"kata-containers",level:2},{value:"AKS CoCo preview",id:"aks-coco-preview",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"confidential-containers",children:"Confidential Containers"})}),"\n",(0,i.jsxs)(n.p,{children:["Contrast uses some building blocks from ",(0,i.jsx)(n.a,{href:"https://confidentialcontainers.org",children:"Confidential Containers"})," (CoCo), a ",(0,i.jsx)(n.a,{href:"https://www.cncf.io/projects/confidential-containers/",children:"CNCF Sandbox project"})," that aims to standardize confidential computing at the pod level.\nThe project is under active development and many of the high-level features are still in flux.\nContrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime."]}),"\n",(0,i.jsx)(n.h2,{id:"kubernetes-runtimeclass",children:"Kubernetes RuntimeClass"}),"\n",(0,i.jsxs)(n.p,{children:["Kubernetes can be extended to use more than one container runtime with ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:(0,i.jsx)(n.code,{children:"RuntimeClass"})})," objects.\nThe ",(0,i.jsx)(n.a,{href:"https://kubernetes.io/docs/concepts/architecture/cri/",children:"Container Runtime Interface"})," (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate ",(0,i.jsx)(n.code,{children:"RuntimeClass"}),".\n",(0,i.jsx)(n.code,{children:"RuntimeClass"})," implementations are usually based on an ",(0,i.jsx)(n.a,{href:"https://github.com/opencontainers/runtime-spec",children:"OCI runtime"}),", such as ",(0,i.jsx)(n.code,{children:"runc"}),", ",(0,i.jsx)(n.code,{children:"runsc"})," or ",(0,i.jsx)(n.code,{children:"crun"}),".\nIn CoCo's case, the runtime is Kata Containers with added confidential computing capabilities."]}),"\n",(0,i.jsx)(n.h2,{id:"kata-containers",children:"Kata Containers"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://katacontainers.io/",children:"Kata Containers"})," is an OCI runtime that runs pods in VMs.\nThe pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host.\nThere are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs.\nUsing local VMs requires either bare-metal servers or VMs with support for nested virtualization.\nLocal VMs communicate with the host over a virtual socket.\nFor remote VMs, host-to-agent communication is tunnelled through the cloud provider's network."]}),"\n",(0,i.jsxs)(n.p,{children:["Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure.\nIn confidential mode, the guest agent is configured with an ",(0,i.jsx)(n.a,{href:"https://www.openpolicyagent.org/",children:"Open Policy Agent"})," (OPA) policy to authorize API calls from the host.\nThis policy also contains checksums for the expected container images.\nIt's derived from Kubernetes resource definitions and its checksum is included in the attestation report."]}),"\n",(0,i.jsx)(n.h2,{id:"aks-coco-preview",children:"AKS CoCo preview"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/",children:"Azure Kubernetes Service"})," (AKS) provides CoCo-enabled node pools as a ",(0,i.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/azure/aks/confidential-containers-overview",children:"preview offering"}),".\nThese node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed.\nContrast can be deployed directly into a CoCo-enabled AKS cluster."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var s=t(96540);const i={},o=s.createContext(i);function r(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e8480491.662dbe18.js b/pr-preview/pr-1071/assets/js/e8480491.662dbe18.js deleted file mode 100644 index 51ac8cf379..0000000000 --- a/pr-preview/pr-1071/assets/js/e8480491.662dbe18.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1362],{14920:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-1.0/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/architecture/certificates.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/secrets"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/observability"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(63063).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},63063:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e8dd02b6.d8be576b.js b/pr-preview/pr-1071/assets/js/e8dd02b6.d8be576b.js deleted file mode 100644 index 52efa2153c..0000000000 --- a/pr-preview/pr-1071/assets/js/e8dd02b6.d8be576b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6330],{58517:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"1.1","label":"1.1","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-1.1","isLast":false,"docsSidebars":{"docs":[{"type":"link","label":"What is Contrast?","href":"/contrast/pr-preview/pr-1071/1.1/","docId":"intro","unlisted":false},{"type":"category","label":"Basics","collapsed":false,"items":[{"type":"link","label":"Confidential Containers","href":"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers","docId":"basics/confidential-containers","unlisted":false},{"type":"link","label":"Security benefits","href":"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits","docId":"basics/security-benefits","unlisted":false},{"type":"link","label":"Features","href":"/contrast/pr-preview/pr-1071/1.1/basics/features","docId":"basics/features","unlisted":false}],"collapsible":true},{"type":"category","label":"Getting started","collapsed":false,"items":[{"type":"link","label":"Install","href":"/contrast/pr-preview/pr-1071/1.1/getting-started/install","docId":"getting-started/install","unlisted":false},{"type":"link","label":"Cluster setup","href":"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup","docId":"getting-started/cluster-setup","unlisted":false},{"type":"link","label":"Bare metal setup","href":"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal","docId":"getting-started/bare-metal","unlisted":false}],"collapsible":true},{"type":"category","label":"Examples","items":[{"type":"link","label":"Confidential emoji voting","href":"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto","docId":"examples/emojivoto","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Workload deployment","href":"/contrast/pr-preview/pr-1071/1.1/deployment","docId":"deployment","unlisted":false},{"type":"link","label":"Troubleshooting","href":"/contrast/pr-preview/pr-1071/1.1/troubleshooting","docId":"troubleshooting","unlisted":false},{"type":"category","label":"Components","items":[{"type":"link","label":"Overview","href":"/contrast/pr-preview/pr-1071/1.1/components/overview","docId":"components/overview","unlisted":false},{"type":"link","label":"Runtime","href":"/contrast/pr-preview/pr-1071/1.1/components/runtime","docId":"components/runtime","unlisted":false},{"type":"link","label":"Policies","href":"/contrast/pr-preview/pr-1071/1.1/components/policies","docId":"components/policies","unlisted":false},{"type":"link","label":"Service mesh","href":"/contrast/pr-preview/pr-1071/1.1/components/service-mesh","docId":"components/service-mesh","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Architecture","items":[{"type":"link","label":"Attestation","href":"/contrast/pr-preview/pr-1071/1.1/architecture/attestation","docId":"architecture/attestation","unlisted":false},{"type":"link","label":"Secrets & recovery","href":"/contrast/pr-preview/pr-1071/1.1/architecture/secrets","docId":"architecture/secrets","unlisted":false},{"type":"link","label":"Certificate authority","href":"/contrast/pr-preview/pr-1071/1.1/architecture/certificates","docId":"architecture/certificates","unlisted":false},{"type":"link","label":"Security considerations","href":"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations","docId":"architecture/security-considerations","unlisted":false},{"type":"link","label":"Observability","href":"/contrast/pr-preview/pr-1071/1.1/architecture/observability","docId":"architecture/observability","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Planned features and limitations","href":"/contrast/pr-preview/pr-1071/1.1/features-limitations","docId":"features-limitations","unlisted":false},{"type":"category","label":"About","items":[{"type":"link","label":"Telemetry","href":"/contrast/pr-preview/pr-1071/1.1/about/telemetry","docId":"about/telemetry","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"about/telemetry":{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","sidebar":"docs"},"architecture/attestation":{"id":"architecture/attestation","title":"Attestation in Contrast","description":"This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334.","sidebar":"docs"},"architecture/certificates":{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","sidebar":"docs"},"architecture/observability":{"id":"architecture/observability","title":"Observability","description":"The Contrast Coordinator can expose metrics in the","sidebar":"docs"},"architecture/secrets":{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","sidebar":"docs"},"architecture/security-considerations":{"id":"architecture/security-considerations","title":"Security Considerations","description":"Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits).","sidebar":"docs"},"basics/confidential-containers":{"id":"basics/confidential-containers","title":"Confidential Containers","description":"Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level.","sidebar":"docs"},"basics/features":{"id":"basics/features","title":"Product features","description":"Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.","sidebar":"docs"},"basics/security-benefits":{"id":"basics/security-benefits","title":"Contrast security overview","description":"This document outlines the security measures of Contrast and its capability to counter various threats.","sidebar":"docs"},"components/overview":{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","sidebar":"docs"},"components/policies":{"id":"components/policies","title":"Policies","description":"Kata runtime policies are an integral part of the Confidential Containers preview on AKS.","sidebar":"docs"},"components/runtime":{"id":"components/runtime","title":"Contrast Runtime","description":"The Contrast runtime is responsible for starting pods as confidential virtual machines.","sidebar":"docs"},"components/service-mesh":{"id":"components/service-mesh","title":"Service mesh","description":"The Contrast service mesh secures the communication of the workload by automatically","sidebar":"docs"},"deployment":{"id":"deployment","title":"Workload deployment","description":"The following instructions will guide you through the process of making an existing Kubernetes deployment","sidebar":"docs"},"examples/emojivoto":{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","sidebar":"docs"},"features-limitations":{"id":"features-limitations","title":"Planned features and limitations","description":"This section lists planned features and current limitations of Contrast.","sidebar":"docs"},"getting-started/bare-metal":{"id":"getting-started/bare-metal","title":"Prepare a bare-metal instance","description":"Hardware and firmware setup","sidebar":"docs"},"getting-started/cluster-setup":{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","sidebar":"docs"},"getting-started/install":{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","sidebar":"docs"},"intro":{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","sidebar":"docs"},"troubleshooting":{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/e9dbdd13.6065280b.js b/pr-preview/pr-1071/assets/js/e9dbdd13.6065280b.js deleted file mode 100644 index 7f3ddcdfd4..0000000000 --- a/pr-preview/pr-1071/assets/js/e9dbdd13.6065280b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1647],{35121:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>d});const o=JSON.parse('{"id":"troubleshooting","title":"Troubleshooting","description":"This section contains information on how to debug your Contrast deployment.","source":"@site/versioned_docs/version-1.1/troubleshooting.md","sourceDirName":".","slug":"/troubleshooting","permalink":"/contrast/pr-preview/pr-1071/1.1/troubleshooting","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/troubleshooting.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Workload deployment","permalink":"/contrast/pr-preview/pr-1071/1.1/deployment"},"next":{"title":"Overview","permalink":"/contrast/pr-preview/pr-1071/1.1/components/overview"}}');var i=t(74848),s=t(28453);const a={},r="Troubleshooting",c={},d=[{value:"Logging",id:"logging",level:2},{value:"CLI",id:"cli",level:3},{value:"Coordinator and Initializer",id:"coordinator-and-initializer",level:3},{value:"Pod fails to start",id:"pod-fails-to-start",level:2},{value:"Regenerating the policies",id:"regenerating-the-policies",level:3},{value:"Pin container images",id:"pin-container-images",level:3},{value:"Validate Contrast components match",id:"validate-contrast-components-match",level:3}];function l(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"troubleshooting",children:"Troubleshooting"})}),"\n",(0,i.jsx)(n.p,{children:"This section contains information on how to debug your Contrast deployment."}),"\n",(0,i.jsx)(n.h2,{id:"logging",children:"Logging"}),"\n",(0,i.jsx)(n.p,{children:"Collecting logs can be a good first step to identify problems in your\ndeployment. Both the CLI and the Contrast Coordinator as well as the Initializer\ncan be configured to emit additional logs."}),"\n",(0,i.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,i.jsxs)(n.p,{children:["The CLI logs can be configured with the ",(0,i.jsx)(n.code,{children:"--log-level"})," command-line flag, which\ncan be set to either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"})," or ",(0,i.jsx)(n.code,{children:"error"}),". The default is ",(0,i.jsx)(n.code,{children:"info"}),".\nSetting this to ",(0,i.jsx)(n.code,{children:"debug"})," can get more fine-grained information as to where the\nproblem lies."]}),"\n",(0,i.jsx)(n.h3,{id:"coordinator-and-initializer",children:"Coordinator and Initializer"}),"\n",(0,i.jsxs)(n.p,{children:["The logs from the Coordinator and the Initializer can be configured via the\nenvironment variables ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"}),", ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," and\n",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"}),"."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_LEVEL"})," can be set to one of either ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"info"}),", ",(0,i.jsx)(n.code,{children:"warn"}),", or\n",(0,i.jsx)(n.code,{children:"error"}),", similar to the CLI (defaults to ",(0,i.jsx)(n.code,{children:"info"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_FORMAT"})," can be set to ",(0,i.jsx)(n.code,{children:"text"})," or ",(0,i.jsx)(n.code,{children:"json"}),", determining the output\nformat (defaults to ",(0,i.jsx)(n.code,{children:"text"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," is a comma-seperated list of subsystems that should\nbe enabled for logging, which are disabled by default. Subsystems include:\n",(0,i.jsx)(n.code,{children:"kds-getter"}),", ",(0,i.jsx)(n.code,{children:"issuer"})," and ",(0,i.jsx)(n.code,{children:"validator"}),".\nTo enable all subsystems, use ",(0,i.jsx)(n.code,{children:"*"})," as the value for this environment variable.\nWarnings and error messages from subsystems get printed regardless of whether\nthe subsystem is listed in the ",(0,i.jsx)(n.code,{children:"CONTRAST_LOG_SUBSYSTEMS"})," environment variable."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"To configure debug logging with all subsystems for your Coordinator, add the\nfollowing variables to your container definition."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'spec: # v1.PodSpec\n containers:\n image: "ghcr.io/edgelesssys/contrast/coordinator:v1.1.1@sha256:272bf0910ad9ce8f0f0bd6865487dd062e53361cd2e3852c7d864a2018d2a461"\n name: coordinator\n env:\n - name: CONTRAST_LOG_LEVEL\n value: debug\n - name: CONTRAST_LOG_SUBSYSTEMS\n value: "*"\n # ...\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["While the Contrast Coordinator has a policy that allows certain configurations,\nthe Initializer and service mesh don't. When changing environment variables of other\nparts than the Coordinator, ensure to rerun ",(0,i.jsx)(n.code,{children:"contrast generate"})," to update the policy."]})}),"\n",(0,i.jsxs)(n.p,{children:["To access the logs generated by the Coordinator, you can use ",(0,i.jsx)(n.code,{children:"kubectl"})," with the\nfollowing command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl logs <coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.h2,{id:"pod-fails-to-start",children:"Pod fails to start"}),"\n",(0,i.jsxs)(n.p,{children:["If the Coordinator or a workload pod fails to even start, it can be helpful to\nlook at the events of the pod during the startup process using the ",(0,i.jsx)(n.code,{children:"describe"}),"\ncommand."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> events --for pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"Example output:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'LAST SEEN TYPE REASON OBJECT MESSAGE\n32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...\n'})}),"\n",(0,i.jsx)(n.p,{children:"A common error, as in this example, is that the container creation was blocked by the\npolicy. Potential reasons are a modification of the deployment YAML without updating\nthe policies afterward, or a version mismatch between Contrast components."}),"\n",(0,i.jsx)(n.h3,{id:"regenerating-the-policies",children:"Regenerating the policies"}),"\n",(0,i.jsx)(n.p,{children:"To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated\npolicies, rerun"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast generate\n"})}),"\n",(0,i.jsx)(n.p,{children:"on your deployment. If any of the policy annotations change, re-deploy with the updated policies."}),"\n",(0,i.jsx)(n.h3,{id:"pin-container-images",children:"Pin container images"}),"\n",(0,i.jsx)(n.p,{children:"When generating the policies, Contrast will download the images specified in your deployment\nYAML and include their cryptographic identity. If the image tag is moved to another\ncontainer image after the policy has been generated, the image downloaded at deploy time\nwill differ from the one at generation time, and the policy enforcement won't allow the\ncontainer to be started in the pod VM."}),"\n",(0,i.jsxs)(n.p,{children:["To ensure the correct image is always used, pin the container image to a fixed ",(0,i.jsx)(n.code,{children:"sha256"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This way, the same image will still be pulled when the container tag (",(0,i.jsx)(n.code,{children:"22.04"}),") is moved\nto another image."]}),"\n",(0,i.jsx)(n.h3,{id:"validate-contrast-components-match",children:"Validate Contrast components match"}),"\n",(0,i.jsx)(n.p,{children:"A version mismatch between Contrast components can cause policy validation or attestation\nto fail. Each Contrast runtime is identifiable based on its (shortened) measurement value\nused to name the runtime class version."}),"\n",(0,i.jsx)(n.p,{children:"First, analyze which runtime class is currently installed in your cluster by running"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl get runtimeclasses\n"})}),"\n",(0,i.jsx)(n.p,{children:"This should give you output similar to the following one."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"NAME HANDLER AGE\ncontrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h\nkata-cc-isolation kata-cc 45d\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided\nby the AKS CoCo preview, which isn't used by Contrast)."}),"\n",(0,i.jsx)(n.p,{children:"Next, check if the pod that won't start has the correct runtime class configured, and the\nCoordinator uses the exact same runtime:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>\nkubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>\n"})}),"\n",(0,i.jsx)(n.p,{children:"The output should list the runtime class the pod is using:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast-cc-aks-clh-snp-7173acb5\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Version information about the currently used CLI can be obtained via the ",(0,i.jsx)(n.code,{children:"version"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast --version\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-sh",children:"contrast version v0.X.0\n\n runtime handler: contrast-cc-aks-clh-snp-7173acb5\n launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35\n genpolicy version: 3.2.0.azl1.genpolicy0\n image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...\n ghcr.io/edgelesssys/contrast/initializer@sha256:...\n"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(96540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ecab07fd.a02478a9.js b/pr-preview/pr-1071/assets/js/ecab07fd.a02478a9.js deleted file mode 100644 index dc45058788..0000000000 --- a/pr-preview/pr-1071/assets/js/ecab07fd.a02478a9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3423],{34087:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-1.2/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.2/intro.md","tags":[],"version":"1.2","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"Contrast concept",src:n(96274).A+"",width:"1644",height:"764"})}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/getting-started/install",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},96274:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/concept-c1792eb1b8f3959308512d1e518b0176.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/edcfcef8.98b05483.js b/pr-preview/pr-1071/assets/js/edcfcef8.98b05483.js deleted file mode 100644 index 1b6f2d7cd9..0000000000 --- a/pr-preview/pr-1071/assets/js/edcfcef8.98b05483.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3133],{81779:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"components/overview","title":"Components","description":"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.","source":"@site/versioned_docs/version-1.1/components/overview.md","sourceDirName":"components","slug":"/components/overview","permalink":"/contrast/pr-preview/pr-1071/1.1/components/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/components/overview.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Troubleshooting","permalink":"/contrast/pr-preview/pr-1071/1.1/troubleshooting"},"next":{"title":"Runtime","permalink":"/contrast/pr-preview/pr-1071/1.1/components/runtime"}}');var o=n(74848),r=n(28453);const s={},a="Components",c={},l=[{value:"The CLI (Command Line Interface)",id:"the-cli-command-line-interface",level:2},{value:"The Coordinator",id:"the-coordinator",level:2},{value:"The Manifest",id:"the-manifest",level:2},{value:"Runtime policies",id:"runtime-policies",level:2},{value:"The Initializer",id:"the-initializer",level:2},{value:"The Contrast runtime",id:"the-contrast-runtime",level:2}];function d(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",ul:"ul",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"components",children:"Components"})}),"\n",(0,o.jsx)(t.p,{children:"Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments.\nThis page provides an overview of the core components essential for deploying and managing Contrast."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"components overview",src:n(51003).A+"",width:"3387",height:"1866"})}),"\n",(0,o.jsx)(t.h2,{id:"the-cli-command-line-interface",children:"The CLI (Command Line Interface)"}),"\n",(0,o.jsx)(t.p,{children:"The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster."}),"\n",(0,o.jsx)(t.li,{children:"Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest."}),"\n",(0,o.jsx)(t.li,{children:"Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest."}),"\n",(0,o.jsx)(t.li,{children:"Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation."}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"the-coordinator",children:"The Coordinator"}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator is the central remote attestation service of a Contrast deployment.\nIt runs inside a confidential container inside your cluster.\nThe Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained.\nThe Coordinator is configured with a ",(0,o.jsx)(t.em,{children:"manifest"}),", a configuration file containing the reference attestation values of your deployment.\nIt ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment.\nThe Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure.\nYour workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA.\nAs your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment."]}),"\n",(0,o.jsx)(t.p,{children:"To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment.\nA third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity."}),"\n",(0,o.jsx)(t.h2,{id:"the-manifest",children:"The Manifest"}),"\n",(0,o.jsx)(t.p,{children:"The manifest is the configuration file for the Coordinator, defining your confidential deployment.\nIt's automatically generated from your deployment by the Contrast CLI.\nIt currently consists of the following parts:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Policies"}),": The identities of your Pods, represented by the hashes of their respective runtime policies."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"Reference Values"}),": The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods."]}),"\n",(0,o.jsxs)(t.li,{children:[(0,o.jsx)(t.em,{children:"WorkloadOwnerKeyDigest"}),": The workload owner's public key digest. Used for authenticating subsequent manifest updates."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"runtime-policies",children:"Runtime policies"}),"\n",(0,o.jsx)(t.p,{children:"Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers.\nThey allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files.\nThe runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA.\nThe Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests.\nThe Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA."}),"\n",(0,o.jsx)(t.h2,{id:"the-initializer",children:"The Initializer"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast provides an Initializer that handles the remote attestation on the workload side transparently and\nfetches the workload certificate. The Initializer runs as an init container before your workload is started.\nIt provides the workload container and the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",children:"service mesh sidecar"})," with the workload certificates."]}),"\n",(0,o.jsx)(t.h2,{id:"the-contrast-runtime",children:"The Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a Kubernetes ",(0,o.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/containers/runtime-class/",children:"runtime class"}),", which is installed\nby the ",(0,o.jsx)(t.code,{children:"node-installer"})," DaemonSet.\nThis runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS).\nThe installer takes care of provisioning every node in the cluster so it provides this runtime class."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},51003:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/components-ea3fb9800d5718d6ab96607ee817c104.svg"},28453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>a});var i=n(96540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/ee8b52db.1127312e.js b/pr-preview/pr-1071/assets/js/ee8b52db.1127312e.js deleted file mode 100644 index 54ea566bcc..0000000000 --- a/pr-preview/pr-1071/assets/js/ee8b52db.1127312e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[5316],{51076:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>u});const n=JSON.parse('{"id":"basics/security-benefits","title":"security-benefits","description":"","source":"@site/versioned_docs/version-0.5/basics/security-benefits.md","sourceDirName":"basics","slug":"/basics/security-benefits","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/basics/security-benefits.md","tags":[],"version":"0.5","frontMatter":{},"sidebar":"docs","previous":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers"},"next":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/features"}}');var r=s(74848),i=s(28453);const o={},c=void 0,a={},u=[];function d(e){return(0,r.jsx)(r.Fragment,{})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d()}},28453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>c});var n=s(96540);const r={},i=n.createContext(r);function o(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/f2348f57.f3c0d472.js b/pr-preview/pr-1071/assets/js/f2348f57.f3c0d472.js deleted file mode 100644 index a7dc54bafa..0000000000 --- a/pr-preview/pr-1071/assets/js/f2348f57.f3c0d472.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8772],{74153:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","source":"@site/versioned_docs/version-1.1/architecture/secrets.md","sourceDirName":"architecture","slug":"/architecture/secrets","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/secrets","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.1/architecture/secrets.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/attestation"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/1.1/architecture/certificates"}}');var n=r(74848),i=r(28453);const o={},a="Secrets & recovery",d={},c=[{value:"Persistence",id:"persistence",level:2},{value:"Recovery",id:"recovery",level:2},{value:"Workload Secrets",id:"workload-secrets",level:2}];function h(e){const t={admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"secrets--recovery",children:"Secrets & recovery"})}),"\n",(0,n.jsx)(t.p,{children:"When the Coordinator is configured with the initial manifest, it generates a random secret seed.\nFrom this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history.\nThis derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state."}),"\n",(0,n.jsxs)(t.p,{children:["The secret seed is returned to the user on the first call to ",(0,n.jsx)(t.code,{children:"contrast set"}),", encrypted with the user's public seed share owner key.\nIf no seed share owner key is provided, a key is generated and stored in the working directory."]}),"\n",(0,n.jsx)(t.h2,{id:"persistence",children:"Persistence"}),"\n",(0,n.jsxs)(t.p,{children:["The Coordinator runs as a ",(0,n.jsx)(t.code,{children:"StatefulSet"})," with a dynamically provisioned persistent volume.\nThis volume stores the manifest history and the associated runtime policies.\nThe manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads.\nHowever, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users.\nThus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed."]}),"\n",(0,n.jsx)(t.h2,{id:"recovery",children:"Recovery"}),"\n",(0,n.jsxs)(t.p,{children:["When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests.\nIt needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures.\nThis procedure is called recovery and is initiated by the workload owner.\nThe CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the ",(0,n.jsx)(t.code,{children:"Recover"})," method.\nThe Coordinator recovers its key material and verifies the manifest history signature."]}),"\n",(0,n.jsx)(t.h2,{id:"workload-secrets",children:"Workload Secrets"}),"\n",(0,n.jsxs)(t.p,{children:["The Coordinator provides each workload a secret seed during attestation. This secret can be used by the workload to derive additional secrets for example to\nencrypt persistent data. Like the workload certificates it's mounted in the shared Kubernetes volume ",(0,n.jsx)(t.code,{children:"contrast-secrets"})," in the path ",(0,n.jsx)(t.code,{children:"<mountpoint>/secrets/workload-secret-seed"}),"."]}),"\n",(0,n.jsx)(t.admonition,{type:"warning",children:(0,n.jsx)(t.p,{children:"The workload owner can decrypt data encrypted with secrets derived from the workload secret.\nThe workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner.\nIf the data owner and the workload owner is the same entity, then they can safely use the workload secrets."})})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>a});var s=r(96540);const n={},i=s.createContext(n);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/f31967d8.78ed1777.js b/pr-preview/pr-1071/assets/js/f31967d8.78ed1777.js deleted file mode 100644 index 715b5df770..0000000000 --- a/pr-preview/pr-1071/assets/js/f31967d8.78ed1777.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6733],{89400:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"about/telemetry","title":"CLI telemetry","description":"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.","source":"@site/versioned_docs/version-0.7/about/telemetry.md","sourceDirName":"about","slug":"/about/telemetry","permalink":"/contrast/pr-preview/pr-1071/0.7/about/telemetry","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.7/about/telemetry.md","tags":[],"version":"0.7","frontMatter":{},"sidebar":"docs","previous":{"title":"About","permalink":"/contrast/pr-preview/pr-1071/0.7/about/"}}');var r=s(74848),o=s(28453);const i={},a="CLI telemetry",c={},d=[];function l(e){const t={a:"a",code:"code",em:"em",h1:"h1",header:"header",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"cli-telemetry",children:"CLI telemetry"})}),"\n",(0,r.jsx)(t.p,{children:"The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands.\nThis allows to understand how Contrast is used and to improve it."}),"\n",(0,r.jsx)(t.p,{children:"The CLI sends the following data:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"The CLI version"}),"\n",(0,r.jsx)(t.li,{children:"The CLI target OS and architecture (GOOS and GOARCH)"}),"\n",(0,r.jsx)(t.li,{children:"The command that was run"}),"\n",(0,r.jsx)(t.li,{children:"The kind of error that occurred (if any)"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The CLI ",(0,r.jsx)(t.em,{children:"doesn't"})," collect sensitive information.\nThe implementation is open-source and can be reviewed."]}),"\n",(0,r.jsx)(t.p,{children:"IP addresses may be processed or stored for security purposes."}),"\n",(0,r.jsxs)(t.p,{children:["The data that the CLI collects adheres to the Edgeless Systems ",(0,r.jsx)(t.a,{href:"https://www.edgeless.systems/privacy",children:"privacy policy"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can disable telemetry by setting the environment variable ",(0,r.jsx)(t.code,{children:"DO_NOT_TRACK=1"})," before running the CLI."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,s)=>{s.d(t,{R:()=>i,x:()=>a});var n=s(96540);const r={},o=n.createContext(r);function i(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/f36abd57.08938dac.js b/pr-preview/pr-1071/assets/js/f36abd57.08938dac.js deleted file mode 100644 index b937f551c1..0000000000 --- a/pr-preview/pr-1071/assets/js/f36abd57.08938dac.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6711],{8624:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>i});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-0.9/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/getting-started/cluster-setup.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.9/getting-started/install"},"next":{"title":"Confidential emoji voting","permalink":"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto"}}');var t=r(74848),a=r(28453);const o={},c="Create a cluster",l={},i=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.p,{children:["Install the latest version of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli",children:"Login to your account"}),", which needs\nto have the permissions to create an AKS cluster, by executing:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First, we need to create an AKS cluster. We can't directly create a CoCo-enabled cluster, so we'll need to create a\nnon-CoCo cluster first, and then add a CoCo node pool, optionally replacing the non-CoCo node pool."}),"\n",(0,t.jsx)(n.p,{children:"We'll first start by creating the non-CoCo cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.29 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"We then add a second node pool with CoCo support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool add \\\n --resource-group "${azResourceGroup:?}" \\\n --name nodepool2 \\\n --cluster-name "${azClusterName:?}" \\\n --node-count 1 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation\n'})}),"\n",(0,t.jsx)(n.p,{children:"Optionally, we can now remove the non-CoCo node pool:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool delete \\\n --resource-group "${azResourceGroup:?}" \\\n --cluster-name "${azClusterName:?}" \\\n --name nodepool1\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"For validation, list the available nodes using kubectl:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show two nodes:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\naks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>c});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/f47dd6e5.fd0db7db.js b/pr-preview/pr-1071/assets/js/f47dd6e5.fd0db7db.js deleted file mode 100644 index f79b02efc4..0000000000 --- a/pr-preview/pr-1071/assets/js/f47dd6e5.fd0db7db.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[6408],{99851:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-0.5/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/0.5/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.5/intro.md","tags":[],"version":"0.5","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.5/getting-started/",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/f593d43a.0672da79.js b/pr-preview/pr-1071/assets/js/f593d43a.0672da79.js deleted file mode 100644 index 470f224077..0000000000 --- a/pr-preview/pr-1071/assets/js/f593d43a.0672da79.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1956],{60558:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"intro","title":"Contrast","description":"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.","source":"@site/versioned_docs/version-0.6/intro.md","sourceDirName":".","slug":"/","permalink":"/contrast/pr-preview/pr-1071/0.6/","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/intro.md","tags":[],"version":"0.6","frontMatter":{"slug":"/","id":"intro"},"sidebar":"docs","next":{"title":"Confidential Containers","permalink":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers"}}');var r=n(74848),i=n(28453);const o={slug:"/",id:"intro"},a="Contrast",c={},d=[{value:"Goal",id:"goal",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"Next steps",id:"next-steps",level:2}];function l(e){const t={a:"a",admonition:"admonition",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"contrast",children:"Contrast"})}),"\n",(0,r.jsx)(t.p,{children:"Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale."}),"\n",(0,r.jsxs)(t.p,{children:["Contrast is based on the ",(0,r.jsx)(t.a,{href:"https://github.com/kata-containers/kata-containers",children:"Kata Containers"})," and\n",(0,r.jsx)(t.a,{href:"https://github.com/confidential-containers",children:"Confidential Containers"})," projects.\nConfidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment.\nThis works with unmodified containers in a lift-and-shift approach.\nContrast currently targets the ",(0,r.jsx)(t.a,{href:"https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-containers-on-aks-preview",children:"CoCo preview on AKS"}),"."]}),"\n",(0,r.jsx)(t.admonition,{type:"tip",children:(0,r.jsxs)(t.p,{children:["See the \ud83d\udcc4",(0,r.jsx)(t.a,{href:"https://content.edgeless.systems/hubfs/Confidential%20Computing%20Whitepaper.pdf",children:"whitepaper"})," for more information on confidential computing."]})}),"\n",(0,r.jsx)(t.h2,{id:"goal",children:"Goal"}),"\n",(0,r.jsx)(t.p,{children:"Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges."}),"\n",(0,r.jsx)(t.p,{children:"Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow."}),"\n",(0,r.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsxs)(t.p,{children:["Contrast provides unique security ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/features",children:"features"})," and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",children:"benefits"}),". The core use cases are:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Increasing the security of your containers"}),"\n",(0,r.jsx)(t.li,{children:"Moving sensitive workloads from on-prem to the cloud with Confidential Computing"}),"\n",(0,r.jsx)(t.li,{children:"Shielding the code and data even from the own cluster administrators"}),"\n",(0,r.jsx)(t.li,{children:"Increasing the trustworthiness of your SaaS offerings"}),"\n",(0,r.jsx)(t.li,{children:"Simplifying regulatory compliance"}),"\n",(0,r.jsx)(t.li,{children:"Multi-party computation for data collaboration"}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(t.p,{children:["You can learn more about the concept of ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers",children:"Confidential Containers"}),", ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/features",children:"features"}),", and ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",children:"security benefits"})," of Contrast in this section. To jump right into the action head to ",(0,r.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/0.6/getting-started/",children:(0,r.jsx)(t.em,{children:"Getting started"})}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(96540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/f65fea7a.8955c8e3.js b/pr-preview/pr-1071/assets/js/f65fea7a.8955c8e3.js deleted file mode 100644 index bdebde92f5..0000000000 --- a/pr-preview/pr-1071/assets/js/f65fea7a.8955c8e3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2472],{27115:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"examples/emojivoto","title":"Confidential emoji voting","description":"screenshot of the emojivoto UI","source":"@site/docs/examples/emojivoto.md","sourceDirName":"examples","slug":"/examples/emojivoto","permalink":"/contrast/pr-preview/pr-1071/next/examples/emojivoto","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/docs/examples/emojivoto.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Bare metal setup","permalink":"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal"},"next":{"title":"Encrypted volume mount","permalink":"/contrast/pr-preview/pr-1071/next/examples/mysql"}}');var o=n(74848),s=n(28453);const a={},r="Confidential emoji voting",l={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps to deploy emojivoto with Contrast",id:"steps-to-deploy-emojivoto-with-contrast",level:2},{value:"Download the deployment files",id:"download-the-deployment-files",level:3},{value:"Deploy the Contrast runtime",id:"deploy-the-contrast-runtime",level:3},{value:"Deploy the Contrast Coordinator",id:"deploy-the-contrast-coordinator",level:3},{value:"Generate policy annotations and manifest",id:"generate-policy-annotations-and-manifest",level:3},{value:"Set the manifest",id:"set-the-manifest",level:3},{value:"Deploy emojivoto",id:"deploy-emojivoto",level:3},{value:"Verifying the deployment as a user",id:"verifying-the-deployment-as-a-user",level:2},{value:"Verifying the Coordinator",id:"verifying-the-coordinator",level:3},{value:"Auditing the manifest history and artifacts",id:"auditing-the-manifest-history-and-artifacts",level:3},{value:"Connecting securely to the application",id:"connecting-securely-to-the-application",level:3},{value:"Updating the certificate SAN and the manifest (optional)",id:"updating-the-certificate-san-and-the-manifest-optional",level:2},{value:"Configuring the service SAN in the manifest",id:"configuring-the-service-san-in-the-manifest",level:3},{value:"Updating the manifest",id:"updating-the-manifest",level:3},{value:"Rolling out the update",id:"rolling-out-the-update",level:3}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components},{TabItem:i,Tabs:a}=t;return i||p("TabItem",!0),a||p("Tabs",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.header,{children:(0,o.jsx)(t.h1,{id:"confidential-emoji-voting",children:"Confidential emoji voting"})}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{alt:"screenshot of the emojivoto UI",src:n(72866).A+"",width:"1503",height:"732"})}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsxs)(t.strong,{children:["This tutorial guides you through deploying ",(0,o.jsx)(t.a,{href:"https://github.com/BuoyantIO/emojivoto",children:"emojivoto"})," as a\nconfidential Contrast deployment and validating the deployment from a voter's perspective."]})}),"\n",(0,o.jsxs)(t.p,{children:["Emojivoto is an example app allowing users to vote for different emojis and view votes\non a leader board. It has a microservice architecture consisting of a\nweb frontend (",(0,o.jsx)(t.code,{children:"web"}),"), a gRPC backend for listing available emojis (",(0,o.jsx)(t.code,{children:"emoji"}),"), and a backend for\nthe voting and leader board logic (",(0,o.jsx)(t.code,{children:"voting"}),"). The ",(0,o.jsx)(t.code,{children:"vote-bot"})," simulates user traffic by submitting\nvotes to the frontend."]}),"\n",(0,o.jsx)(t.p,{children:"Emojivoto can be seen as a lighthearted example of an app dealing with sensitive data.\nContrast protects emojivoto in two ways. First, it shields emojivoto as a whole from the infrastructure, for example, Azure.\nSecond, it can be configured to also prevent data access even from the administrator of the app. In the case of emojivoto, this gives assurance to users that their votes remain secret."}),"\n",(0,o.jsx)(t.p,{children:(0,o.jsx)(t.img,{src:"https://raw.githubusercontent.com/BuoyantIO/emojivoto/e490d5789086e75933a474b22f9723fbfa0b29ba/assets/emojivoto-topology.png",alt:"emojivoto components topology"})}),"\n",(0,o.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"Installed Contrast CLI"}),"\n",(0,o.jsxs)(t.li,{children:["A running Kubernetes cluster with support for confidential containers, either on ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup",children:"AKS"})," or on ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal",children:"bare metal"}),"."]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"steps-to-deploy-emojivoto-with-contrast",children:"Steps to deploy emojivoto with Contrast"}),"\n",(0,o.jsx)(t.h3,{id:"download-the-deployment-files",children:"Download the deployment files"}),"\n",(0,o.jsx)(t.p,{children:"The emojivoto deployment files are part of the Contrast release. You can download them by running:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"curl -fLO https://github.com/edgelesssys/contrast/releases/latest/download/emojivoto-demo.yml --create-dirs --output-dir deployment\n"})}),"\n",(0,o.jsx)(t.h3,{id:"deploy-the-contrast-runtime",children:"Deploy the Contrast runtime"}),"\n",(0,o.jsxs)(t.p,{children:["Contrast depends on a ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/runtime",children:"custom Kubernetes RuntimeClass"}),",\nwhich needs to be installed to the cluster initially.\nThis consists of a ",(0,o.jsx)(t.code,{children:"RuntimeClass"})," resource and a ",(0,o.jsx)(t.code,{children:"DaemonSet"})," that performs installation on worker nodes.\nThis step is only required once for each version of the runtime.\nIt can be shared between Contrast deployments."]}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-aks-clh-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-k3s-qemu-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,o.jsx)(t.h3,{id:"deploy-the-contrast-coordinator",children:"Deploy the Contrast Coordinator"}),"\n",(0,o.jsx)(t.p,{children:"Deploy the Contrast Coordinator, comprising a single replica deployment and a\nLoadBalancer service, into your cluster:"}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-aks-clh-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-k3s-qemu-snp.yml\n"})})}),(0,o.jsx)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-k3s-qemu-tdx.yml\n"})})})]}),"\n",(0,o.jsx)(t.h3,{id:"generate-policy-annotations-and-manifest",children:"Generate policy annotations and manifest"}),"\n",(0,o.jsxs)(t.p,{children:["Run the ",(0,o.jsx)(t.code,{children:"generate"})," command to generate the execution policies and add them as\nannotations to your deployment files. A ",(0,o.jsx)(t.code,{children:"manifest.json"})," file with the reference values\nof your deployment will be created:"]}),"\n",(0,o.jsxs)(a,{queryString:"platform",children:[(0,o.jsx)(i,{value:"aks-clh-snp",label:"AKS",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values aks-clh-snp deployment/\n"})})}),(0,o.jsxs)(i,{value:"k3s-qemu-snp",label:"Bare metal (SEV-SNP)",children:[(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-snp deployment/\n"})}),(0,o.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,o.jsxs)(t.p,{children:["On bare-metal SEV-SNP, ",(0,o.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,o.jsx)(t.code,{children:"MinimumTCB"})," values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,o.jsx)(t.code,{children:'{"BootloaderVersion":255,"TEEVersion":255,"SNPVersion":255,"MicrocodeVersion":255}'})," and observe the real values in the error messages in the following steps. This should only be done in a secure environment. Note that the values will differ between CPU models."]})})]}),(0,o.jsxs)(i,{value:"k3s-qemu-tdx",label:"Bare metal (TDX)",children:[(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"contrast generate --reference-values k3s-qemu-tdx deployment/\n"})}),(0,o.jsx)(t.admonition,{title:"Missing TCB values",type:"note",children:(0,o.jsxs)(t.p,{children:["On bare-metal TDX, ",(0,o.jsx)(t.code,{children:"contrast generate"})," is unable to fill in the ",(0,o.jsx)(t.code,{children:"MinimumTeeTcbSvn"})," and ",(0,o.jsx)(t.code,{children:"MrSeam"})," TCB values as they can vary between platforms.\nThey will have to be filled in manually.\nIf you don't know the correct values use ",(0,o.jsx)(t.code,{children:"ffffffffffffffffffffffffffffffff"})," and ",(0,o.jsx)(t.code,{children:"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"})," respectively and observe the real values in the error messages in the following steps. This should only be done in a secure environment."]})})]})]}),"\n",(0,o.jsxs)(t.admonition,{title:"Runtime class and Initializer",type:"note",children:[(0,o.jsxs)(t.p,{children:["The deployment YAML shipped for this demo is already configured to be used with Contrast.\nA ",(0,o.jsx)(t.a,{href:"../components/runtime",children:"runtime class"})," ",(0,o.jsx)(t.code,{children:"contrast-cc"}),"\nwas added to the pods to signal they should be run as Confidential Containers. During the generation process,\nthe Contrast ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/overview#the-initializer",children:"Initializer"})," will be added as an init container to these\nworkloads to facilitate the attestation and certificate pulling before the actual workload is started."]}),(0,o.jsxs)(t.p,{children:["Further, the deployment YAML is also configured with the Contrast ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/service-mesh",children:"service mesh"}),".\nThe configured service mesh proxy provides transparent protection for the communication between\nthe different components of emojivoto."]})]}),"\n",(0,o.jsx)(t.h3,{id:"set-the-manifest",children:"Set the manifest"}),"\n",(0,o.jsx)(t.p,{children:"Configure the coordinator with a manifest. It might take up to a few minutes\nfor the load balancer to be created and the Coordinator being available."}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'coordinator=$(kubectl get svc coordinator -o=jsonpath=\'{.status.loadBalancer.ingress[0].ip}\')\necho "The user API of your Contrast Coordinator is available at $coordinator:1313"\ncontrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,o.jsx)(t.p,{children:"The CLI will use the reference values from the manifest to attest the Coordinator deployment\nduring the TLS handshake. If the connection succeeds, it's ensured that the Coordinator\ndeployment hasn't been tampered with."}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"deploy-emojivoto",children:"Deploy emojivoto"}),"\n",(0,o.jsx)(t.p,{children:"Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload,\nwe can deploy the application:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl apply -f deployment/\n"})}),"\n",(0,o.jsx)(t.admonition,{title:"Inter-deployment communication",type:"note",children:(0,o.jsxs)(t.p,{children:["The Contrast Coordinator issues mesh certificates after successfully validating workloads.\nThese certificates can be used for secure inter-deployment communication. The Initializer\nsends an attestation report to the Coordinator, retrieves certificates and a private key in return\nand writes them to a ",(0,o.jsx)(t.code,{children:"volumeMount"}),". The service mesh sidecar is configured to use the credentials\nfrom the ",(0,o.jsx)(t.code,{children:"volumeMount"})," when communicating with other parts of the deployment over mTLS.\nThe public facing frontend for voting uses the mesh certificate without client authentication."]})}),"\n",(0,o.jsx)(t.h2,{id:"verifying-the-deployment-as-a-user",children:"Verifying the deployment as a user"}),"\n",(0,o.jsx)(t.p,{children:"In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before casting a vote.\nWith Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment.\nContrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future.\nSuccessful verification of the Coordinator means that the user can be sure that the given manifest will be enforced."}),"\n",(0,o.jsx)(t.h3,{id:"verifying-the-coordinator",children:"Verifying the Coordinator"}),"\n",(0,o.jsx)(t.p,{children:"A user can verify the Contrast deployment using the verify\ncommand:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'contrast verify -c "${coordinator}:1313" -m manifest.json\n'})}),"\n",(0,o.jsxs)(t.p,{children:["The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs\nto be communicated out of band to everyone wanting to verify the deployment, as the ",(0,o.jsx)(t.code,{children:"verify"})," command checks\nif the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds,\nthe Coordinator deployment was successfully verified to be running in the expected Confidential\nComputing environment with the expected code version. The Coordinator will then return its\nconfiguration over the established TLS channel. The CLI will store this information, namely the root\ncertificate of the mesh (",(0,o.jsx)(t.code,{children:"mesh-ca.pem"}),") and the history of manifests, into the ",(0,o.jsx)(t.code,{children:"verify/"})," directory.\nIn addition, the policies referenced in the manifest history are also written into the same directory."]}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"auditing-the-manifest-history-and-artifacts",children:"Auditing the manifest history and artifacts"}),"\n",(0,o.jsxs)(t.p,{children:["In the next step, the Coordinator configuration that was written by the ",(0,o.jsx)(t.code,{children:"verify"})," command needs to be audited.\nA potential voter should inspect the manifest and the referenced policies. They could delegate\nthis task to an entity they trust."]}),"\n",(0,o.jsx)(t.h3,{id:"connecting-securely-to-the-application",children:"Connecting securely to the application"}),"\n",(0,o.jsxs)(t.p,{children:["After ensuring the configuration of the Coordinator fits the expectation, the user can securely connect\nto the application using the Coordinator's ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"})," as a trusted CA certificate."]}),"\n",(0,o.jsx)(t.p,{children:"To access the web frontend, expose the service on a public IP address via a LoadBalancer service:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho \"Frontend is available at https://$frontendIP, you can visit it in your browser.\"\n"})}),"\n",(0,o.jsxs)(t.p,{children:["Using ",(0,o.jsx)(t.code,{children:"openssl"}),", the certificate of the service can be validated with the ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"}),":"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null\n"})}),"\n",(0,o.jsx)(t.h2,{id:"updating-the-certificate-san-and-the-manifest-optional",children:"Updating the certificate SAN and the manifest (optional)"}),"\n",(0,o.jsx)(t.p,{children:"By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed\nvia load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field.\nValidation fails since the certificate contains no IP entries as a SAN.\nFor example, a connection attempt using the curl and the mesh CA certificate with throw the following error:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"$ curl --cacert ./verify/mesh-ca.pem \"https://${frontendIP}:443\"\ncurl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'\n"})}),"\n",(0,o.jsx)(t.h3,{id:"configuring-the-service-san-in-the-manifest",children:"Configuring the service SAN in the manifest"}),"\n",(0,o.jsxs)(t.p,{children:["The ",(0,o.jsx)(t.code,{children:"Policies"})," section of the manifest maps policy hashes to a list of SANs. To enable certificate verification\nof the web frontend with tools like curl, edit the policy with your favorite editor and add the ",(0,o.jsx)(t.code,{children:"frontendIP"})," to\nthe list that already contains the ",(0,o.jsx)(t.code,{children:'"web"'})," DNS entry:"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-diff",children:' "Policies": {\n ...\n "99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {\n "SANs": [\n "web",\n- "*"\n+ "*",\n+ "203.0.113.34"\n ],\n "WorkloadSecretID": "web"\n },\n'})}),"\n",(0,o.jsx)(t.h3,{id:"updating-the-manifest",children:"Updating the manifest"}),"\n",(0,o.jsx)(t.p,{children:"Next, set the changed manifest at the coordinator with:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'contrast set -c "${coordinator}:1313" deployment/\n'})}),"\n",(0,o.jsxs)(t.p,{children:["The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued\nafter the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain\nwon't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures\nthat parts of the deployment that received a security update won't be infected by parts of the deployment at an older\npatch level that may have been compromised. The ",(0,o.jsx)(t.code,{children:"mesh-ca.pem"})," is updated with the new CA certificate chain."]}),"\n",(0,o.jsx)(t.admonition,{type:"warning",children:(0,o.jsxs)(t.p,{children:["On bare metal, the ",(0,o.jsx)(t.a,{href:"/contrast/pr-preview/pr-1071/next/components/policies#platform-differences",children:"coordinator policy hash"})," must be overwritten using ",(0,o.jsx)(t.code,{children:"--coordinator-policy-hash"}),"."]})}),"\n",(0,o.jsx)(t.h3,{id:"rolling-out-the-update",children:"Rolling out the update"}),"\n",(0,o.jsx)(t.p,{children:"The Coordinator has the new manifest set, but the different containers of the app are still\nusing the older certificate authority. The Contrast Initializer terminates after the initial attestation\nflow and won't pull new certificates on manifest updates."}),"\n",(0,o.jsx)(t.p,{children:"To roll out the update, use:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:"kubectl rollout restart deployment/emoji\nkubectl rollout restart deployment/vote-bot\nkubectl rollout restart deployment/voting\nkubectl rollout restart deployment/web\n"})}),"\n",(0,o.jsx)(t.p,{children:"After the update has been rolled out, connecting to the frontend using curl will successfully validate\nthe service certificate and return the HTML document of the voting site:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-sh",children:'curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"\n'})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}function p(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},72866:(e,t,n)=>{n.d(t,{A:()=>i});const i=n.p+"assets/images/emoijvoto-3fb48da575d6d4adf76cc90caa35d762.png"},28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var i=n(96540);const o={},s=i.createContext(o);function a(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/fbad2ec0.6f2e0862.js b/pr-preview/pr-1071/assets/js/fbad2ec0.6f2e0862.js deleted file mode 100644 index 80e6125be9..0000000000 --- a/pr-preview/pr-1071/assets/js/fbad2ec0.6f2e0862.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[1658],{6784:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>i,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"getting-started/cluster-setup","title":"Create a cluster","description":"Prerequisites","source":"@site/versioned_docs/version-0.6/getting-started/cluster-setup.md","sourceDirName":"getting-started","slug":"/getting-started/cluster-setup","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.6/getting-started/cluster-setup.md","tags":[],"version":"0.6","frontMatter":{},"sidebar":"docs","previous":{"title":"Install","permalink":"/contrast/pr-preview/pr-1071/0.6/getting-started/install"},"next":{"title":"Examples","permalink":"/contrast/pr-preview/pr-1071/0.6/examples/"}}');var t=r(74848),a=r(28453);const o={},c="Create a cluster",i={},l=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Prepare using the AKS preview",id:"prepare-using-the-aks-preview",level:2},{value:"Create resource group",id:"create-resource-group",level:2},{value:"Create AKS cluster",id:"create-aks-cluster",level:2},{value:"Cleanup",id:"cleanup",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"create-a-cluster",children:"Create a cluster"})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.p,{children:["Install the latest version of the ",(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/",children:"Azure CLI"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli",children:"Login to your account"}),", which needs\nto have the permissions to create an AKS cluster, by executing:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az login\n"})}),"\n",(0,t.jsx)(n.h2,{id:"prepare-using-the-aks-preview",children:"Prepare using the AKS preview"}),"\n",(0,t.jsxs)(n.p,{children:["CoCo on AKS is currently in preview. An extension for the ",(0,t.jsx)(n.code,{children:"az"})," CLI is needed to create such a cluster.\nAdd the extension with the following commands:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"az extension add \\\n --name aks-preview \\\n --allow-preview true\naz extension update \\\n --name aks-preview \\\n --allow-preview true\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then register the required feature flags in your subscription to allow access to the public preview:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az feature register \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The registration can take a few minutes. The status of the operation can be checked with the following\ncommand, which should show the registration state as ",(0,t.jsx)(n.code,{children:"Registered"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az feature show \\\n --namespace "Microsoft.ContainerService" \\\n --name "KataCcIsolationPreview" \\\n --output table\n'})}),"\n",(0,t.jsx)(n.p,{children:"Afterward, refresh the registration of the ContainerService provider:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az provider register \\\n --namespace "Microsoft.ContainerService"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-resource-group",children:"Create resource group"}),"\n",(0,t.jsx)(n.p,{children:"The AKS with CoCo preview is currently available in the following locations:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"CentralIndia\neastus\nEastUS2EUAP\nGermanyWestCentral\njapaneast\nnortheurope\nSwitzerlandNorth\nUAENorth\nwesteurope\nwestus\n"})}),"\n",(0,t.jsx)(n.p,{children:"Set the name of the resource group you want to use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azResourceGroup="ContrastDemo"\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can either use an existing one or create a new resource group with the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'azLocation="westus" # Select a location from the list above\n\naz group create \\\n --name "${azResourceGroup:?}" \\\n --location "${azLocation:?}"\n'})}),"\n",(0,t.jsx)(n.h2,{id:"create-aks-cluster",children:"Create AKS cluster"}),"\n",(0,t.jsx)(n.p,{children:"First create an AKS cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Select the name for your AKS cluster\nazClusterName="ContrastDemo"\n\naz aks create \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}" \\\n --kubernetes-version 1.29 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --node-count 1 \\\n --generate-ssh-keys\n'})}),"\n",(0,t.jsx)(n.p,{children:"We then add a second node pool with CoCo support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks nodepool add \\\n --resource-group "${azResourceGroup:?}" \\\n --name nodepool2 \\\n --cluster-name "${azClusterName:?}" \\\n --node-count 1 \\\n --os-sku AzureLinux \\\n --node-vm-size Standard_DC4as_cc_v5 \\\n --workload-runtime KataCcIsolation\n'})}),"\n",(0,t.jsx)(n.p,{children:"Finally, update your kubeconfig with the credentials to access the cluster:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'az aks get-credentials \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"For validation, list the available nodes using kubectl:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"kubectl get nodes\n"})}),"\n",(0,t.jsx)(n.p,{children:"It should show two nodes:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"NAME STATUS ROLES AGE VERSION\naks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0\naks-nodepool2-32238657-vmss000000 Ready <none> 45s v1.29.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"cleanup",children:"Cleanup"}),"\n",(0,t.jsx)(n.p,{children:"After trying out Contrast, you might want to clean up the cloud resources created in this step.\nIn case you've created a new resource group, you can just delete that group with"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az group delete \\\n --name "${azResourceGroup:?}"\n'})}),"\n",(0,t.jsx)(n.p,{children:"Deleting the resource group will also delete the cluster and all other related resources."}),"\n",(0,t.jsx)(n.p,{children:"To only cleanup the AKS cluster and node pools, run"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'az aks delete \\\n --resource-group "${azResourceGroup:?}" \\\n --name "${azClusterName:?}"\n'})})]})}function d(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>c});var s=r(96540);const t={},a=s.createContext(t);function o(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/fbad79f4.c7fad30b.js b/pr-preview/pr-1071/assets/js/fbad79f4.c7fad30b.js deleted file mode 100644 index b6602858b1..0000000000 --- a/pr-preview/pr-1071/assets/js/fbad79f4.c7fad30b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[2590],{98707:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"getting-started/install","title":"Installation","description":"Download the Contrast CLI from the latest release:","source":"@site/versioned_docs/version-1.0/getting-started/install.md","sourceDirName":"getting-started","slug":"/getting-started/install","permalink":"/contrast/pr-preview/pr-1071/1.0/getting-started/install","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/getting-started/install.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Features","permalink":"/contrast/pr-preview/pr-1071/1.0/basics/features"},"next":{"title":"Cluster setup","permalink":"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup"}}');var r=s(74848),a=s(28453);const o={},i="Installation",l={},c=[];function d(t){const e={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,a.R)(),...t.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(e.header,{children:(0,r.jsx)(e.h1,{id:"installation",children:"Installation"})}),"\n",(0,r.jsx)(e.p,{children:"Download the Contrast CLI from the latest release:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v1.0.0/contrast\n"})}),"\n",(0,r.jsx)(e.p,{children:"After that, install the Contrast CLI in your PATH, e.g.:"}),"\n",(0,r.jsx)(e.pre,{children:(0,r.jsx)(e.code,{className:"language-bash",children:"sudo install contrast /usr/local/bin/contrast\n"})})]})}function p(t={}){const{wrapper:e}={...(0,a.R)(),...t.components};return e?(0,r.jsx)(e,{...t,children:(0,r.jsx)(d,{...t})}):d(t)}},28453:(t,e,s)=>{s.d(e,{R:()=>o,x:()=>i});var n=s(96540);const r={},a=n.createContext(r);function o(t){const e=n.useContext(a);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function i(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),n.createElement(a.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/fbcf0d59.4fb6163a.js b/pr-preview/pr-1071/assets/js/fbcf0d59.4fb6163a.js deleted file mode 100644 index a30f742de5..0000000000 --- a/pr-preview/pr-1071/assets/js/fbcf0d59.4fb6163a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[3970],{18012:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>f,frontMatter:()=>s,metadata:()=>r,toc:()=>h});const r=JSON.parse('{"id":"architecture/certificates","title":"Certificate authority","description":"The Coordinator acts as a certificate authority (CA) for the workloads","source":"@site/versioned_docs/version-0.9/architecture/certificates.md","sourceDirName":"architecture","slug":"/architecture/certificates","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/certificates","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-0.9/architecture/certificates.md","tags":[],"version":"0.9","frontMatter":{},"sidebar":"docs","previous":{"title":"Secrets & recovery","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/secrets"},"next":{"title":"Observability","permalink":"/contrast/pr-preview/pr-1071/0.9/architecture/observability"}}');var n=i(74848),a=i(28453);const s={},o="Certificate authority",c={},h=[{value:"Public key infrastructure",id:"public-key-infrastructure",level:2},{value:"Certificate rotation",id:"certificate-rotation",level:2},{value:"Usage of the different certificates",id:"usage-of-the-different-certificates",level:2}];function d(e){const t={em:"em",h1:"h1",h2:"h2",header:"header",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"certificate-authority",children:"Certificate authority"})}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator acts as a certificate authority (CA) for the workloads\ndefined in the manifest.\nAfter a workload pod's attestation has been verified by the Coordinator,\nit receives a mesh certificate and the mesh CA certificate.\nThe mesh certificate can be used for example in a TLS connection as the server or\nclient certificate to proof to the other party that the workload has been\nverified by the Coordinator. The other party can verify the mesh certificate\nwith the mesh CA certificate. While the certificates can be used by the workload\ndeveloper in different ways, they're automatically used in Contrast's service\nmesh to establish mTLS connections between workloads in the same deployment."}),"\n",(0,n.jsx)(t.h2,{id:"public-key-infrastructure",children:"Public key infrastructure"}),"\n",(0,n.jsx)(t.p,{children:"The Coordinator establishes a public key infrastructure (PKI) for all workloads\ncontained in the manifest. The Coordinator holds three certificates: the root CA\ncertificate, the intermediate CA certificate, and the mesh CA certificate.\nThe root CA certificate is a long-lasting certificate and its private key signs\nthe intermediate CA certificate. The intermediate CA certificate and the mesh CA\ncertificate share the same private key. This intermediate private key is used\nto sign the mesh certificates. Moreover, the intermediate private key and\ntherefore the intermediate CA certificate and the mesh CA certificate are\nrotated when setting a new manifest."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"PKI certificate chain",src:i(19979).A+""})}),"\n",(0,n.jsx)(t.h2,{id:"certificate-rotation",children:"Certificate rotation"}),"\n",(0,n.jsx)(t.p,{children:"Depending on the configuration of the first manifest, it allows the workload\nowner to update the manifest and, therefore, the deployment.\nWorkload owners and data owners can be mutually untrusted parties.\nTo protect against the workload owner silently introducing malicious containers,\nthe Coordinator rotates the intermediate private key every time the manifest is\nupdated and, therefore, the\nintermediate CA certificate and mesh CA certificate. If the user doesn't\ntrust the workload owner, they use the mesh CA certificate obtained when they\nverified the Coordinator and the manifest. This ensures that the user only\nconnects to workloads defined in the manifest they verified since only those\nworkloads' certificates are signed with this intermediate private key."}),"\n",(0,n.jsx)(t.p,{children:"Similarly, the service mesh also uses the mesh CA certificate obtained when the\nworkload was started, so the workload only trusts endpoints that have been\nverified by the Coordinator based on the same manifest. Consequently, a\nmanifest update requires a fresh rollout of the services in the service mesh."}),"\n",(0,n.jsx)(t.h2,{id:"usage-of-the-different-certificates",children:"Usage of the different certificates"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"root CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis should only be used if the data owner trusts all future updates to the\nmanifest and workloads. This is, for instance, the case when the workload owner is\nthe same entity as the data owner."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh CA certificate"})," is returned when verifying the Coordinator.\nThe data owner can use it to verify the mesh certificates of the workloads.\nThis certificate is bound to the manifest set when the Coordinator is verified.\nIf the manifest is updated, the mesh CA certificate changes.\nNew workloads will receive mesh certificates signed by the ",(0,n.jsx)(t.em,{children:"new"})," mesh CA certificate.\nThe Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate.\nThe service mesh also uses the mesh CA certificate to verify the mesh certificates."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"intermediate CA certificate"})," links the root CA certificate to the\nmesh certificate so that the mesh certificate can be verified with the root CA\ncertificate. It's part of the certificate chain handed out by\nendpoints in the service mesh."]}),"\n",(0,n.jsxs)(t.li,{children:["The ",(0,n.jsx)(t.strong,{children:"mesh certificate"})," is part of the certificate chain handed out by\nendpoints in the service mesh. During the startup of a pod, the Initializer\nrequests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully\nverifies the workload. The mesh certificate\ncontains X.509 extensions with information from the workloads attestation\ndocument."]}),"\n"]})]})}function f(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},19979:(e,t,i)=>{i.d(t,{A:()=>r});const r=i.p+"assets/images/contrast_pki.drawio-a2442a1eeb081612c5ad587a58589ad4.svg"},28453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>o});var r=i(96540);const n={},a=r.createContext(n);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/fda633d9.061ed873.js b/pr-preview/pr-1071/assets/js/fda633d9.061ed873.js deleted file mode 100644 index 9d909cbe9d..0000000000 --- a/pr-preview/pr-1071/assets/js/fda633d9.061ed873.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[827],{29598:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"architecture/secrets","title":"Secrets & recovery","description":"When the Coordinator is configured with the initial manifest, it generates a random secret seed.","source":"@site/versioned_docs/version-1.0/architecture/secrets.md","sourceDirName":"architecture","slug":"/architecture/secrets","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/secrets","draft":false,"unlisted":false,"editUrl":"https://github.com/edgelesssys/contrast/edit/main/docs/versioned_docs/version-1.0/architecture/secrets.md","tags":[],"version":"1.0","frontMatter":{},"sidebar":"docs","previous":{"title":"Attestation","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/attestation"},"next":{"title":"Certificate authority","permalink":"/contrast/pr-preview/pr-1071/1.0/architecture/certificates"}}');var n=r(74848),i=r(28453);const o={},a="Secrets & recovery",d={},c=[{value:"Persistence",id:"persistence",level:2},{value:"Recovery",id:"recovery",level:2},{value:"Workload Secrets",id:"workload-secrets",level:2}];function h(e){const t={admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"secrets--recovery",children:"Secrets & recovery"})}),"\n",(0,n.jsx)(t.p,{children:"When the Coordinator is configured with the initial manifest, it generates a random secret seed.\nFrom this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history.\nThis derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state."}),"\n",(0,n.jsxs)(t.p,{children:["The secret seed is returned to the user on the first call to ",(0,n.jsx)(t.code,{children:"contrast set"}),", encrypted with the user's public seed share owner key.\nIf no seed share owner key is provided, a key is generated and stored in the working directory."]}),"\n",(0,n.jsx)(t.h2,{id:"persistence",children:"Persistence"}),"\n",(0,n.jsxs)(t.p,{children:["The Coordinator runs as a ",(0,n.jsx)(t.code,{children:"StatefulSet"})," with a dynamically provisioned persistent volume.\nThis volume stores the manifest history and the associated runtime policies.\nThe manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads.\nHowever, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users.\nThus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed."]}),"\n",(0,n.jsx)(t.h2,{id:"recovery",children:"Recovery"}),"\n",(0,n.jsxs)(t.p,{children:["When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests.\nIt needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures.\nThis procedure is called recovery and is initiated by the workload owner.\nThe CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the ",(0,n.jsx)(t.code,{children:"Recover"})," method.\nThe Coordinator recovers its key material and verifies the manifest history signature."]}),"\n",(0,n.jsx)(t.h2,{id:"workload-secrets",children:"Workload Secrets"}),"\n",(0,n.jsxs)(t.p,{children:["The Coordinator provides each workload a secret seed during attestation. This secret can be used by the workload to derive additional secrets for example to\nencrypt persistent data. Like the workload certificates it's mounted in the shared Kubernetes volume ",(0,n.jsx)(t.code,{children:"contrast-secrets"})," in the path ",(0,n.jsx)(t.code,{children:"<mountpoint>/secrets/workload-secret-seed"}),"."]}),"\n",(0,n.jsx)(t.admonition,{type:"warning",children:(0,n.jsx)(t.p,{children:"The workload owner can decrypt data encrypted with secrets derived from the workload secret.\nThe workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner.\nIf the data owner and the workload owner is the same entity, then they can safely use the workload secrets."})})]})}function l(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},28453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>a});var s=r(96540);const n={},i=s.createContext(n);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/main.be0c3a62.js b/pr-preview/pr-1071/assets/js/main.be0c3a62.js deleted file mode 100644 index 602b4c6881..0000000000 --- a/pr-preview/pr-1071/assets/js/main.be0c3a62.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.be0c3a62.js.LICENSE.txt */ -(self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[]).push([[8792],{92413:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});n(96540);var r=n(53259),o=n.n(r),a=n(84054);const i={"014daffb":[()=>n.e(1955).then(n.bind(n,89204)),"@site/docs/architecture/secrets.md",89204],"018595b3":[()=>Promise.all([n.e(1869),n.e(3876)]).then(n.bind(n,59763)),"@site/versioned_docs/version-0.5/examples/index.md",59763],"04102e85":[()=>n.e(1158).then(n.bind(n,30612)),"@site/versioned_docs/version-0.5/architecture/attestation/hardware.md",30612],"046575a6":[()=>n.e(2285).then(n.bind(n,30182)),"@site/versioned_docs/version-1.2/about/telemetry.md",30182],"06354bbe":[()=>n.e(8204).then(n.bind(n,18733)),"@site/versioned_docs/version-0.9/components/overview.md",18733],"06eada7a":[()=>n.e(6470).then(n.bind(n,28601)),"@site/versioned_docs/version-0.7/components/policies.md",28601],"078f57bf":[()=>n.e(1690).then(n.bind(n,30569)),"@site/versioned_docs/version-0.9/architecture/observability.md",30569],"098bf236":[()=>n.e(8259).then(n.bind(n,32284)),"@site/versioned_docs/version-0.8/intro.md",32284],"0a09f1f2":[()=>n.e(7e3).then(n.bind(n,35787)),"@site/versioned_docs/version-1.1/deployment.md",35787],"0a7a212e":[()=>n.e(3702).then(n.bind(n,4949)),"@site/versioned_docs/version-0.8/basics/confidential-containers.md",4949],"0b1c872d":[()=>n.e(3188).then(n.bind(n,25776)),"@site/versioned_docs/version-1.1/components/policies.md",25776],"0ba7602a":[()=>n.e(7368).then(n.bind(n,37154)),"@site/versioned_docs/version-0.9/features-limitations.md",37154],"0c24bc66":[()=>n.e(6739).then(n.bind(n,73521)),"@site/versioned_docs/version-0.6/basics/security-benefits.md",73521],"0e384e19":[()=>n.e(3976).then(n.bind(n,73700)),"@site/docs/intro.md",73700],"10257d90":[()=>n.e(3477).then(n.bind(n,45013)),"@site/versioned_docs/version-1.1/basics/security-benefits.md",45013],"1057c3b3":[()=>n.e(5811).then(n.bind(n,26033)),"@site/versioned_docs/version-1.1/basics/confidential-containers.md",26033],"14a9ce33":[()=>n.e(7924).then(n.bind(n,50499)),"@site/versioned_docs/version-0.8/architecture/attestation.md",50499],"14eb3368":[()=>Promise.all([n.e(1869),n.e(6969)]).then(n.bind(n,97449)),"@theme/DocCategoryGeneratedIndexPage",97449],"15b9bf06":[()=>n.e(5388).then(n.bind(n,12988)),"@site/versioned_docs/version-0.5/architecture/confidential-containers.md",12988],"16cd20a9":[()=>n.e(2007).then(n.bind(n,7254)),"@site/versioned_docs/version-1.2/components/policies.md",7254],"173fd1a8":[()=>n.e(1514).then(n.bind(n,71144)),"@site/versioned_docs/version-0.7/basics/features.md",71144],17896441:[()=>Promise.all([n.e(1869),n.e(3764),n.e(8401)]).then(n.bind(n,86829)),"@theme/DocItem",86829],"197c7105":[()=>n.e(7742).then(n.bind(n,82557)),"@site/versioned_docs/version-1.2/deployment.md",82557],"1ab97833":[()=>n.e(985).then(n.bind(n,29083)),"@site/versioned_docs/version-1.0/components/overview.md",29083],"1c9b88ee":[()=>n.e(1560).then(n.bind(n,62538)),"@site/versioned_docs/version-0.6/getting-started/install.md",62538],"1de90583":[()=>n.e(6200).then(n.t.bind(n,64920,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-8-a24.json",64920],"1e7c9753":[()=>n.e(3391).then(n.bind(n,99028)),"@site/versioned_docs/version-1.1/basics/features.md",99028],"1fefe6de":[()=>n.e(6463).then(n.bind(n,71758)),"@site/versioned_docs/version-1.2/troubleshooting.md",71758],"200ecf61":[()=>n.e(8904).then(n.t.bind(n,79880,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-5-category-network-encryption-e0a.json",79880],"20382dd7":[()=>n.e(3357).then(n.bind(n,33961)),"@site/versioned_docs/version-0.5/architecture/attestation/runtime-policies.md",33961],"207bb774":[()=>Promise.all([n.e(1869),n.e(430)]).then(n.bind(n,50880)),"@site/versioned_docs/version-0.6/about/index.md",50880],"20e0cfa9":[()=>n.e(8403).then(n.bind(n,69107)),"@site/versioned_docs/version-0.7/basics/confidential-containers.md",69107],"21893f51":[()=>n.e(5016).then(n.t.bind(n,25337,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-next-648.json",25337],"21d7c4d4":[()=>n.e(5390).then(n.bind(n,50728)),"@site/versioned_docs/version-0.6/examples/emojivoto.md",50728],"2496d21b":[()=>n.e(995).then(n.bind(n,83495)),"@site/docs/about/telemetry.md",83495],"250ffcdd":[()=>n.e(2343).then(n.bind(n,30106)),"@site/versioned_docs/version-0.8/troubleshooting.md",30106],"26742c3b":[()=>n.e(3108).then(n.bind(n,45694)),"@site/versioned_docs/version-0.9/architecture/secrets.md",45694],"27004ef7":[()=>n.e(2154).then(n.bind(n,23003)),"@site/versioned_docs/version-1.1/features-limitations.md",23003],"270470f6":[()=>n.e(8671).then(n.bind(n,67669)),"@site/versioned_docs/version-1.0/components/service-mesh.md",67669],"27a940ba":[()=>n.e(5279).then(n.bind(n,85360)),"@site/versioned_docs/version-1.0/components/runtime.md",85360],"27d05faa":[()=>n.e(7697).then(n.bind(n,12346)),"@site/versioned_docs/version-0.6/about/telemetry.md",12346],"2a2a0c40":[()=>n.e(7292).then(n.bind(n,48672)),"@site/docs/getting-started/install.md",48672],"2cdf8d95":[()=>n.e(4118).then(n.t.bind(n,14175,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-5-category-components-2b5.json",14175],"2d1295a3":[()=>n.e(5374).then(n.t.bind(n,74413,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-5-c33.json",74413],"2dbe31cc":[()=>n.e(2700).then(n.bind(n,18856)),"@site/versioned_docs/version-0.7/components/service-mesh.md",18856],"2df6ad32":[()=>n.e(1597).then(n.bind(n,92258)),"@site/versioned_docs/version-1.0/deployment.md",92258],"2e82b444":[()=>n.e(6232).then(n.bind(n,91313)),"@site/versioned_docs/version-0.9/architecture/attestation.md",91313],"327db732":[()=>n.e(1751).then(n.bind(n,59414)),"@site/versioned_docs/version-0.5/getting-started/first-steps.md",59414],"327e592d":[()=>n.e(388).then(n.bind(n,17160)),"@site/versioned_docs/version-0.9/basics/security-benefits.md",17160],"35dd9928":[()=>n.e(95).then(n.bind(n,90087)),"@site/docs/features-limitations.md",90087],"3683601e":[()=>n.e(2987).then(n.bind(n,85863)),"@site/versioned_docs/version-0.9/deployment.md",85863],"368b3075":[()=>n.e(5919).then(n.t.bind(n,97447,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-042.json",97447],"39db4684":[()=>Promise.all([n.e(1869),n.e(3459)]).then(n.bind(n,56860)),"@site/versioned_docs/version-0.7/about/index.md",56860],"3a77bb3e":[()=>n.e(1889).then(n.bind(n,34690)),"@site/versioned_docs/version-0.5/getting-started/cluster-setup.md",34690],"3b29aa35":[()=>n.e(3641).then(n.bind(n,97607)),"@site/versioned_docs/version-1.2/getting-started/bare-metal.md",97607],"3d96af17":[()=>n.e(4506).then(n.bind(n,78016)),"@site/versioned_docs/version-1.1/getting-started/cluster-setup.md",78016],"3d9be0cc":[()=>n.e(5310).then(n.bind(n,51550)),"@site/versioned_docs/version-0.5/examples/emojivoto.md",51550],"3e02a241":[()=>n.e(8117).then(n.bind(n,28072)),"@site/versioned_docs/version-0.5/architecture/certificates-and-identities/pki.md",28072],"41b31679":[()=>n.e(4714).then(n.bind(n,65324)),"@site/versioned_docs/version-0.9/troubleshooting.md",65324],"44b49990":[()=>n.e(9652).then(n.bind(n,40820)),"@site/versioned_docs/version-0.9/intro.md",40820],"44f8de13":[()=>n.e(8976).then(n.bind(n,65878)),"@site/versioned_docs/version-1.2/examples/emojivoto.md",65878],"45c98560":[()=>n.e(9361).then(n.bind(n,70687)),"@site/versioned_docs/version-0.6/components/index.md",70687],46157656:[()=>n.e(2857).then(n.t.bind(n,35749,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-1-0-896.json",35749],"46d228a0":[()=>n.e(3246).then(n.bind(n,78137)),"@site/versioned_docs/version-1.2/components/service-mesh.md",78137],"48f2f8ef":[()=>n.e(2020).then(n.bind(n,80401)),"@site/versioned_docs/version-1.1/architecture/attestation.md",80401],"4ce6baab":[()=>n.e(455).then(n.bind(n,57718)),"@site/versioned_docs/version-1.0/about/telemetry.md",57718],"4cf3063f":[()=>n.e(8364).then(n.bind(n,53881)),"@site/versioned_docs/version-1.0/basics/features.md",53881],"4eec459c":[()=>n.e(2639).then(n.bind(n,13204)),"@site/versioned_docs/version-1.1/components/runtime.md",13204],"4f453872":[()=>n.e(8170).then(n.bind(n,80786)),"@site/versioned_docs/version-0.5/architecture/attestation/pod-vm.md",80786],"4fb24623":[()=>n.e(2550).then(n.bind(n,17364)),"@site/docs/architecture/certificates.md",17364],"50474e10":[()=>n.e(7061).then(n.bind(n,63297)),"@site/versioned_docs/version-0.6/basics/confidential-containers.md",63297],"51513a8d":[()=>n.e(3859).then(n.bind(n,12241)),"@site/versioned_docs/version-1.0/architecture/observability.md",12241],"54c6367b":[()=>n.e(5999).then(n.bind(n,84608)),"@site/versioned_docs/version-0.6/components/service-mesh.md",84608],"567e04ee":[()=>n.e(6440).then(n.bind(n,71871)),"@site/versioned_docs/version-0.6/components/policies.md",71871],"5c6fa5d3":[()=>n.e(722).then(n.bind(n,30014)),"@site/versioned_docs/version-1.1/examples/emojivoto.md",30014],"5e95c892":[()=>n.e(9647).then(n.bind(n,83124)),"@theme/DocsRoot",83124],"5eab7755":[()=>Promise.all([n.e(1869),n.e(2772)]).then(n.bind(n,80601)),"@site/versioned_docs/version-0.7/getting-started/index.md",80601],"5ecc20d3":[()=>n.e(1954).then(n.bind(n,71417)),"@site/versioned_docs/version-1.1/architecture/certificates.md",71417],"5f62f97d":[()=>n.e(2756).then(n.t.bind(n,59528,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-5-category-certificates-and-identities-47d.json",59528],"5f998a2f":[()=>n.e(941).then(n.bind(n,67785)),"@site/versioned_docs/version-1.1/intro.md",67785],"6009a9aa":[()=>n.e(8212).then(n.bind(n,80621)),"@site/versioned_docs/version-0.9/components/runtime.md",80621],"6100b425":[()=>n.e(3129).then(n.bind(n,11768)),"@site/versioned_docs/version-0.9/basics/features.md",11768],"616c9a0e":[()=>n.e(9562).then(n.bind(n,5354)),"@site/versioned_docs/version-1.2/components/overview.md",5354],"640cb024":[()=>n.e(7682).then(n.bind(n,8381)),"@site/docs/basics/security-benefits.md",8381],"642ed902":[()=>n.e(5541).then(n.bind(n,48162)),"@site/docs/architecture/attestation.md",48162],"6478b99f":[()=>n.e(3506).then(n.bind(n,56468)),"@site/versioned_docs/version-0.6/known-limitations.md",56468],"64d58a39":[()=>n.e(2005).then(n.bind(n,4463)),"@site/versioned_docs/version-0.5/architecture/attestation/coordinator.md",4463],"6507182a":[()=>n.e(9079).then(n.bind(n,90915)),"@site/versioned_docs/version-1.1/architecture/security-considerations.md",90915],"68be920e":[()=>n.e(7294).then(n.bind(n,11080)),"@site/versioned_docs/version-1.1/architecture/observability.md",11080],"6903d0da":[()=>n.e(594).then(n.bind(n,43980)),"@site/versioned_docs/version-0.5/basics/features.md",43980],"69ec948c":[()=>n.e(3712).then(n.bind(n,75778)),"@site/versioned_docs/version-0.5/deployment.md",75778],"6a46f748":[()=>n.e(6240).then(n.bind(n,42508)),"@site/versioned_docs/version-0.8/architecture/observability.md",42508],"6fc50b39":[()=>n.e(4213).then(n.bind(n,3669)),"@site/versioned_docs/version-0.8/getting-started/install.md",3669],"75100f0d":[()=>Promise.all([n.e(1869),n.e(7882)]).then(n.bind(n,82094)),"@site/versioned_docs/version-0.6/architecture/index.md",82094],"75d659e1":[()=>n.e(8597).then(n.bind(n,5004)),"@site/versioned_docs/version-0.6/deployment.md",5004],"7680d80e":[()=>n.e(9025).then(n.bind(n,88205)),"@site/versioned_docs/version-0.7/examples/emojivoto.md",88205],"790f17e8":[()=>n.e(5242).then(n.bind(n,27808)),"@site/versioned_docs/version-0.8/components/service-mesh.md",27808],"7bd8db71":[()=>n.e(1606).then(n.bind(n,57378)),"@site/versioned_docs/version-1.0/intro.md",57378],"7bdde4a4":[()=>n.e(3752).then(n.bind(n,79218)),"@site/docs/examples/mysql.md",79218],"7d1602ac":[()=>n.e(6069).then(n.bind(n,55238)),"@site/versioned_docs/version-0.8/basics/features.md",55238],"7edb0f0d":[()=>n.e(5231).then(n.bind(n,32716)),"@site/versioned_docs/version-0.7/architecture/observability.md",32716],"7f3f1ff7":[()=>n.e(6623).then(n.bind(n,86696)),"@site/versioned_docs/version-0.9/about/telemetry.md",86696],"808ec8ef":[()=>n.e(6118).then(n.bind(n,20528)),"@site/versioned_docs/version-1.2/architecture/secrets.md",20528],"8132774f":[()=>n.e(1841).then(n.bind(n,58879)),"@site/versioned_docs/version-0.7/getting-started/cluster-setup.md",58879],"84cf2b87":[()=>n.e(4411).then(n.t.bind(n,91892,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-7-3ee.json",91892],89486910:[()=>n.e(7086).then(n.bind(n,41805)),"@site/docs/components/overview.md",41805],"896da145":[()=>Promise.all([n.e(1869),n.e(1739)]).then(n.bind(n,57204)),"@site/versioned_docs/version-0.7/examples/index.md",57204],"89a4f0ca":[()=>n.e(4687).then(n.bind(n,78700)),"@site/docs/basics/features.md",78700],"8bfc695a":[()=>n.e(7261).then(n.bind(n,52261)),"@site/versioned_docs/version-1.2/getting-started/install.md",52261],"8c9a8791":[()=>n.e(5335).then(n.bind(n,20016)),"@site/versioned_docs/version-0.7/components/runtime.md",20016],"8dca39c2":[()=>n.e(3116).then(n.bind(n,82489)),"@site/versioned_docs/version-0.5/basics/confidential-containers.md",82489],"8ec58f4b":[()=>n.e(2506).then(n.bind(n,37802)),"@site/versioned_docs/version-1.2/features-limitations.md",37802],"9040bbc8":[()=>n.e(2453).then(n.bind(n,98935)),"@site/versioned_docs/version-1.0/examples/emojivoto.md",98935],"90af0d0d":[()=>n.e(8921).then(n.bind(n,17170)),"@site/versioned_docs/version-0.6/components/runtime.md",17170],"91456bd6":[()=>n.e(9366).then(n.bind(n,93287)),"@site/versioned_docs/version-1.2/basics/features.md",93287],"9230b32a":[()=>n.e(5829).then(n.t.bind(n,39428,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-9-0bd.json",39428],"927cf76e":[()=>n.e(1226).then(n.bind(n,9902)),"@site/docs/architecture/observability.md",9902],"9397123b":[()=>n.e(2941).then(n.bind(n,99845)),"@site/versioned_docs/version-0.5/architecture/attestation/manifest.md",99845],"9620adf5":[()=>n.e(912).then(n.bind(n,81469)),"@site/versioned_docs/version-1.0/basics/security-benefits.md",81469],"966b9f47":[()=>n.e(1112).then(n.bind(n,98525)),"@site/versioned_docs/version-0.5/architecture/components/cli.md",98525],"969019ea":[()=>n.e(485).then(n.bind(n,31424)),"@site/versioned_docs/version-1.1/components/service-mesh.md",31424],"98367cce":[()=>n.e(133).then(n.bind(n,71663)),"@site/versioned_docs/version-0.8/basics/security-benefits.md",71663],"989c6d03":[()=>n.e(782).then(n.bind(n,91122)),"@site/docs/components/policies.md",91122],"9a06ae3d":[()=>n.e(2912).then(n.bind(n,56704)),"@site/docs/getting-started/cluster-setup.md",56704],"9a28f5c4":[()=>n.e(3505).then(n.bind(n,99764)),"@site/versioned_docs/version-0.9/examples/emojivoto.md",99764],"9a99019d":[()=>n.e(801).then(n.bind(n,89293)),"@site/versioned_docs/version-0.7/intro.md",89293],"9c6eeb97":[()=>n.e(9377).then(n.t.bind(n,97063,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-5-category-attestation-9dd.json",97063],"9ccb1fc6":[()=>n.e(9874).then(n.bind(n,65339)),"@site/versioned_docs/version-0.8/components/runtime.md",65339],"9ce1fd56":[()=>n.e(426).then(n.bind(n,42809)),"@site/versioned_docs/version-0.8/components/overview.md",42809],"9d9e06f4":[()=>Promise.all([n.e(1869),n.e(4670)]).then(n.bind(n,12325)),"@site/versioned_docs/version-0.5/architecture/index.md",12325],"9d9f8394":[()=>n.e(9013).then(n.bind(n,42245)),"@site/docs/troubleshooting.md",42245],a0a1fd3b:[()=>n.e(6755).then(n.bind(n,92395)),"@site/versioned_docs/version-1.1/getting-started/install.md",92395],a0a4ec6e:[()=>n.e(4980).then(n.bind(n,48542)),"@site/versioned_docs/version-0.8/examples/emojivoto.md",48542],a161c24f:[()=>n.e(1575).then(n.bind(n,82560)),"@site/versioned_docs/version-0.5/getting-started/install.md",82560],a2899f6e:[()=>n.e(1861).then(n.bind(n,51866)),"@site/versioned_docs/version-1.0/getting-started/cluster-setup.md",51866],a3713279:[()=>n.e(9588).then(n.bind(n,33745)),"@site/docs/deployment.md",33745],a66d714b:[()=>n.e(9974).then(n.bind(n,91304)),"@site/versioned_docs/version-0.8/deployment.md",91304],a71cbd8f:[()=>n.e(5003).then(n.bind(n,91238)),"@site/versioned_docs/version-0.8/architecture/secrets.md",91238],a7bd4aaa:[()=>n.e(7098).then(n.bind(n,22881)),"@theme/DocVersionRoot",22881],a86a94ce:[()=>n.e(212).then(n.bind(n,55850)),"@site/versioned_docs/version-1.1/about/telemetry.md",55850],a92f10fb:[()=>n.e(5806).then(n.bind(n,94203)),"@site/versioned_docs/version-1.2/basics/confidential-containers.md",94203],a94703ab:[()=>Promise.all([n.e(1869),n.e(9048)]).then(n.bind(n,88001)),"@theme/DocRoot",88001],aa0f7abf:[()=>Promise.all([n.e(1869),n.e(8295)]).then(n.bind(n,40593)),"@site/versioned_docs/version-0.7/architecture/index.md",40593],aaa7edc4:[()=>n.e(315).then(n.bind(n,16796)),"@site/versioned_docs/version-1.2/architecture/attestation.md",16796],aaec90ae:[()=>n.e(4304).then(n.bind(n,19947)),"@site/versioned_docs/version-1.0/features-limitations.md",19947],aafa6b90:[()=>n.e(6645).then(n.bind(n,55633)),"@site/versioned_docs/version-0.8/architecture/certificates.md",55633],ab09c42c:[()=>n.e(8683).then(n.bind(n,99437)),"@site/versioned_docs/version-0.7/architecture/attestation.md",99437],aba21aa0:[()=>n.e(5742).then(n.t.bind(n,27093,19)),"@generated/docusaurus-plugin-content-docs/default/__plugin.json",27093],abfbdc79:[()=>n.e(2045).then(n.bind(n,71925)),"@site/versioned_docs/version-0.7/components/index.md",71925],ac3e6feb:[()=>n.e(3074).then(n.bind(n,25315)),"@site/versioned_docs/version-0.8/about/telemetry.md",25315],ae6c0c68:[()=>n.e(2729).then(n.bind(n,32113)),"@site/versioned_docs/version-0.8/components/policies.md",32113],b0cb3eb4:[()=>n.e(2132).then(n.bind(n,81850)),"@site/docs/architecture/security-considerations.md",81850],b27c3275:[()=>n.e(3690).then(n.bind(n,40497)),"@site/docs/basics/confidential-containers.md",40497],b3916dd3:[()=>n.e(89).then(n.bind(n,34806)),"@site/versioned_docs/version-0.5/architecture/network-encryption/sidecar.md",34806],b451d7c3:[()=>n.e(234).then(n.bind(n,90961)),"@site/versioned_docs/version-1.1/getting-started/bare-metal.md",90961],ba2406d8:[()=>n.e(2476).then(n.bind(n,56218)),"@site/versioned_docs/version-0.8/getting-started/cluster-setup.md",56218],baef5027:[()=>Promise.all([n.e(1869),n.e(9103)]).then(n.bind(n,51760)),"@site/versioned_docs/version-0.5/getting-started/index.md",51760],bced0f3c:[()=>n.e(8001).then(n.bind(n,33221)),"@site/versioned_docs/version-0.7/basics/security-benefits.md",33221],bd029836:[()=>n.e(1047).then(n.bind(n,74283)),"@site/versioned_docs/version-1.0/components/policies.md",74283],bd625abb:[()=>n.e(4415).then(n.bind(n,89939)),"@site/versioned_docs/version-1.0/architecture/attestation.md",89939],bedb5cc1:[()=>n.e(3098).then(n.bind(n,64922)),"@site/versioned_docs/version-1.2/architecture/observability.md",64922],bf823012:[()=>n.e(5225).then(n.bind(n,32615)),"@site/versioned_docs/version-0.7/getting-started/install.md",32615],bfdb605f:[()=>n.e(3610).then(n.bind(n,52055)),"@site/versioned_docs/version-1.2/examples/mysql.md",52055],c09e49b9:[()=>n.e(390).then(n.bind(n,82693)),"@site/versioned_docs/version-0.6/architecture/certificates.md",82693],c1fac065:[()=>Promise.all([n.e(1869),n.e(4206)]).then(n.bind(n,69006)),"@site/versioned_docs/version-0.6/getting-started/index.md",69006],c2ce05d5:[()=>n.e(8024).then(n.bind(n,94003)),"@site/versioned_docs/version-1.0/troubleshooting.md",94003],c3a9f66a:[()=>n.e(7832).then(n.bind(n,8032)),"@site/versioned_docs/version-0.9/components/service-mesh.md",8032],c3f66d9e:[()=>n.e(13).then(n.t.bind(n,1570,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-0-6-13c.json",1570],c4b4ced0:[()=>n.e(2564).then(n.bind(n,58505)),"@site/docs/components/runtime.md",58505],c7462af2:[()=>n.e(2540).then(n.bind(n,56473)),"@site/versioned_docs/version-0.9/components/policies.md",56473],ca5b6702:[()=>n.e(5945).then(n.bind(n,95477)),"@site/docs/components/service-mesh.md",95477],cc4abb91:[()=>n.e(7234).then(n.bind(n,92898)),"@site/versioned_docs/version-1.2/getting-started/cluster-setup.md",92898],ccad6777:[()=>n.e(9033).then(n.bind(n,38028)),"@site/versioned_docs/version-1.2/architecture/certificates.md",38028],cdb2b1a5:[()=>Promise.all([n.e(1869),n.e(9119)]).then(n.bind(n,78496)),"@site/versioned_docs/version-0.6/examples/index.md",78496],cf49aa2b:[()=>n.e(4703).then(n.bind(n,18803)),"@site/docs/getting-started/bare-metal.md",18803],d18a22d8:[()=>n.e(447).then(n.bind(n,7939)),"@site/versioned_docs/version-1.2/components/runtime.md",7939],d1a11e04:[()=>n.e(8902).then(n.bind(n,97232)),"@site/versioned_docs/version-0.8/features-limitations.md",97232],d2630e76:[()=>n.e(9634).then(n.bind(n,22846)),"@site/versioned_docs/version-0.5/architecture/network-encryption/protocols-and-keys.md",22846],d28f01c4:[()=>n.e(2759).then(n.bind(n,55045)),"@site/versioned_docs/version-1.2/architecture/security-considerations.md",55045],d43358e1:[()=>n.e(3024).then(n.bind(n,61156)),"@site/versioned_docs/version-1.2/basics/security-benefits.md",61156],d580a1fd:[()=>n.e(1734).then(n.bind(n,42533)),"@site/versioned_docs/version-0.5/architecture/components/init-container.md",42533],d77304ba:[()=>n.e(4233).then(n.bind(n,15796)),"@site/versioned_docs/version-1.0/basics/confidential-containers.md",15796],dacf14a0:[()=>n.e(101).then(n.bind(n,48763)),"@site/versioned_docs/version-0.9/getting-started/install.md",48763],de615ffd:[()=>n.e(1321).then(n.bind(n,85230)),"@site/versioned_docs/version-0.7/deployment.md",85230],dfd9c366:[()=>n.e(2454).then(n.bind(n,29026)),"@site/versioned_docs/version-0.6/basics/features.md",29026],e1e441c9:[()=>n.e(2623).then(n.bind(n,54794)),"@site/versioned_docs/version-0.6/architecture/attestation.md",54794],e277c26a:[()=>n.e(1632).then(n.bind(n,78335)),"@site/versioned_docs/version-0.7/architecture/certificates.md",78335],e2b3b970:[()=>n.e(2841).then(n.bind(n,6428)),"@site/versioned_docs/version-0.7/features-limitations.md",6428],e446d98f:[()=>n.e(221).then(n.bind(n,43008)),"@site/versioned_docs/version-0.5/architecture/components/coordinator.md",43008],e55aefba:[()=>n.e(4113).then(n.bind(n,69732)),"@site/versioned_docs/version-0.9/basics/confidential-containers.md",69732],e8480491:[()=>n.e(1362).then(n.bind(n,14920)),"@site/versioned_docs/version-1.0/architecture/certificates.md",14920],e8dd02b6:[()=>n.e(6330).then(n.t.bind(n,58517,19)),"@generated/docusaurus-plugin-content-docs/default/p/contrast-pr-preview-pr-1071-1-1-754.json",58517],e9dbdd13:[()=>n.e(1647).then(n.bind(n,35121)),"@site/versioned_docs/version-1.1/troubleshooting.md",35121],ecab07fd:[()=>n.e(3423).then(n.bind(n,34087)),"@site/versioned_docs/version-1.2/intro.md",34087],edcfcef8:[()=>n.e(3133).then(n.bind(n,81779)),"@site/versioned_docs/version-1.1/components/overview.md",81779],ee8b52db:[()=>n.e(5316).then(n.bind(n,51076)),"@site/versioned_docs/version-0.5/basics/security-benefits.md",51076],f2348f57:[()=>n.e(8772).then(n.bind(n,74153)),"@site/versioned_docs/version-1.1/architecture/secrets.md",74153],f31967d8:[()=>n.e(6733).then(n.bind(n,89400)),"@site/versioned_docs/version-0.7/about/telemetry.md",89400],f36abd57:[()=>n.e(6711).then(n.bind(n,8624)),"@site/versioned_docs/version-0.9/getting-started/cluster-setup.md",8624],f47dd6e5:[()=>n.e(6408).then(n.bind(n,99851)),"@site/versioned_docs/version-0.5/intro.md",99851],f593d43a:[()=>n.e(1956).then(n.bind(n,60558)),"@site/versioned_docs/version-0.6/intro.md",60558],f65fea7a:[()=>n.e(2472).then(n.bind(n,27115)),"@site/docs/examples/emojivoto.md",27115],fbad2ec0:[()=>n.e(1658).then(n.bind(n,6784)),"@site/versioned_docs/version-0.6/getting-started/cluster-setup.md",6784],fbad79f4:[()=>n.e(2590).then(n.bind(n,98707)),"@site/versioned_docs/version-1.0/getting-started/install.md",98707],fbcf0d59:[()=>n.e(3970).then(n.bind(n,18012)),"@site/versioned_docs/version-0.9/architecture/certificates.md",18012],fda633d9:[()=>n.e(827).then(n.bind(n,29598)),"@site/versioned_docs/version-1.0/architecture/secrets.md",29598]};var s=n(74848);function c(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,s.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,s.jsx)("p",{children:String(t)}),(0,s.jsx)("div",{children:(0,s.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,s.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,s.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,s.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,s.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,s.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,s.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,s.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,s.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,s.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,s.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var l=n(81604),u=n(23363);function p(e,t){if("*"===e)return o()({loading:c,loader:()=>n.e(2560).then(n.bind(n,72560)),modules:["@theme/NotFound"],webpack:()=>[72560],render(e,t){const n=e.default;return(0,s.jsx)(u.W,{value:{plugin:{name:"native",id:"default"}},children:(0,s.jsx)(n,{...t})})}});const r=a[`${e}-${t}`],p={},d=[],f=[],m=(0,l.A)(r);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=i[n];r&&(p[t]=r[0],d.push(r[1]),f.push(r[2]))})),o().Map({loading:c,loader:p,modules:d,webpack:()=>f,render(t,n){const o=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let i=o;const s=n.split(".");s.slice(0,-1).forEach((e=>{i=i[e]})),i[s[s.length-1]]=a}));const a=o.__comp;delete o.__comp;const i=o.__context;delete o.__context;const c=o.__props;return delete o.__props,(0,s.jsx)(u.W,{value:i,children:(0,s.jsx)(a,{...o,...c,...n})})}})}const d=[{path:"/contrast/pr-preview/pr-1071/",component:p("/contrast/pr-preview/pr-1071/","b32"),routes:[{path:"/contrast/pr-preview/pr-1071/0.5",component:p("/contrast/pr-preview/pr-1071/0.5","207"),routes:[{path:"/contrast/pr-preview/pr-1071/0.5",component:p("/contrast/pr-preview/pr-1071/0.5","b4d"),routes:[{path:"/contrast/pr-preview/pr-1071/0.5",component:p("/contrast/pr-preview/pr-1071/0.5","f85"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture",component:p("/contrast/pr-preview/pr-1071/0.5/architecture","921"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator","f7c"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware","eda"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest","0e1"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm","705"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies","2e5"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki","471"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/components/cli","7b3"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator","9a4"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container","f12"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers","43c"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys","1bc"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar",component:p("/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar","cab"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers","747"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/basics/features",component:p("/contrast/pr-preview/pr-1071/0.5/basics/features","b08"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/0.5/basics/security-benefits","a41"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/category/attestation",component:p("/contrast/pr-preview/pr-1071/0.5/category/attestation","aba"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities",component:p("/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities","1a6"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/category/components",component:p("/contrast/pr-preview/pr-1071/0.5/category/components","4d0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/category/network-encryption",component:p("/contrast/pr-preview/pr-1071/0.5/category/network-encryption","166"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/deployment",component:p("/contrast/pr-preview/pr-1071/0.5/deployment","fbd"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/examples",component:p("/contrast/pr-preview/pr-1071/0.5/examples","98d"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/0.5/examples/emojivoto","ed2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/getting-started",component:p("/contrast/pr-preview/pr-1071/0.5/getting-started","5bc"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup","16e"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps",component:p("/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps","989"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.5/getting-started/install",component:p("/contrast/pr-preview/pr-1071/0.5/getting-started/install","6d3"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/0.6",component:p("/contrast/pr-preview/pr-1071/0.6","576"),routes:[{path:"/contrast/pr-preview/pr-1071/0.6",component:p("/contrast/pr-preview/pr-1071/0.6","f94"),routes:[{path:"/contrast/pr-preview/pr-1071/0.6",component:p("/contrast/pr-preview/pr-1071/0.6","84d"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/about",component:p("/contrast/pr-preview/pr-1071/0.6/about","6f7"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/about/telemetry",component:p("/contrast/pr-preview/pr-1071/0.6/about/telemetry","e96"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/architecture",component:p("/contrast/pr-preview/pr-1071/0.6/architecture","75a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/0.6/architecture/attestation","b31"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/0.6/architecture/certificates","fb2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers","71e"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/basics/features",component:p("/contrast/pr-preview/pr-1071/0.6/basics/features","360"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/0.6/basics/security-benefits","044"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/components",component:p("/contrast/pr-preview/pr-1071/0.6/components","d3d"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/components/policies",component:p("/contrast/pr-preview/pr-1071/0.6/components/policies","0f5"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/components/runtime",component:p("/contrast/pr-preview/pr-1071/0.6/components/runtime","6ac"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/0.6/components/service-mesh","831"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/deployment",component:p("/contrast/pr-preview/pr-1071/0.6/deployment","9df"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/examples",component:p("/contrast/pr-preview/pr-1071/0.6/examples","694"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/0.6/examples/emojivoto","b43"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/getting-started",component:p("/contrast/pr-preview/pr-1071/0.6/getting-started","745"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup","e61"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/getting-started/install",component:p("/contrast/pr-preview/pr-1071/0.6/getting-started/install","57e"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.6/known-limitations",component:p("/contrast/pr-preview/pr-1071/0.6/known-limitations","bc4"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/0.7",component:p("/contrast/pr-preview/pr-1071/0.7","6ea"),routes:[{path:"/contrast/pr-preview/pr-1071/0.7",component:p("/contrast/pr-preview/pr-1071/0.7","5f7"),routes:[{path:"/contrast/pr-preview/pr-1071/0.7",component:p("/contrast/pr-preview/pr-1071/0.7","1e7"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/about",component:p("/contrast/pr-preview/pr-1071/0.7/about","c2b"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/about/telemetry",component:p("/contrast/pr-preview/pr-1071/0.7/about/telemetry","cb9"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/architecture",component:p("/contrast/pr-preview/pr-1071/0.7/architecture","439"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/0.7/architecture/attestation","f94"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/0.7/architecture/certificates","f88"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/architecture/observability",component:p("/contrast/pr-preview/pr-1071/0.7/architecture/observability","329"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers","7b6"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/basics/features",component:p("/contrast/pr-preview/pr-1071/0.7/basics/features","de3"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/0.7/basics/security-benefits","dd3"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/components",component:p("/contrast/pr-preview/pr-1071/0.7/components","2e0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/components/policies",component:p("/contrast/pr-preview/pr-1071/0.7/components/policies","bcf"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/components/runtime",component:p("/contrast/pr-preview/pr-1071/0.7/components/runtime","dff"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/0.7/components/service-mesh","3b8"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/deployment",component:p("/contrast/pr-preview/pr-1071/0.7/deployment","3f6"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/examples",component:p("/contrast/pr-preview/pr-1071/0.7/examples","69d"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/0.7/examples/emojivoto","f59"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/features-limitations",component:p("/contrast/pr-preview/pr-1071/0.7/features-limitations","56e"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/getting-started",component:p("/contrast/pr-preview/pr-1071/0.7/getting-started","25a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup","437"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.7/getting-started/install",component:p("/contrast/pr-preview/pr-1071/0.7/getting-started/install","308"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/0.8",component:p("/contrast/pr-preview/pr-1071/0.8","763"),routes:[{path:"/contrast/pr-preview/pr-1071/0.8",component:p("/contrast/pr-preview/pr-1071/0.8","f5d"),routes:[{path:"/contrast/pr-preview/pr-1071/0.8",component:p("/contrast/pr-preview/pr-1071/0.8","c01"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/about/telemetry",component:p("/contrast/pr-preview/pr-1071/0.8/about/telemetry","273"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/0.8/architecture/attestation","e5c"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/0.8/architecture/certificates","5be"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/architecture/observability",component:p("/contrast/pr-preview/pr-1071/0.8/architecture/observability","e76"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/architecture/secrets",component:p("/contrast/pr-preview/pr-1071/0.8/architecture/secrets","00c"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers","7ad"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/basics/features",component:p("/contrast/pr-preview/pr-1071/0.8/basics/features","bd0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/0.8/basics/security-benefits","3e5"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/components/overview",component:p("/contrast/pr-preview/pr-1071/0.8/components/overview","087"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/components/policies",component:p("/contrast/pr-preview/pr-1071/0.8/components/policies","798"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/components/runtime",component:p("/contrast/pr-preview/pr-1071/0.8/components/runtime","a8e"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/0.8/components/service-mesh","225"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/deployment",component:p("/contrast/pr-preview/pr-1071/0.8/deployment","c4d"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/0.8/examples/emojivoto","141"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/features-limitations",component:p("/contrast/pr-preview/pr-1071/0.8/features-limitations","355"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup","cd2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/getting-started/install",component:p("/contrast/pr-preview/pr-1071/0.8/getting-started/install","7bf"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.8/troubleshooting",component:p("/contrast/pr-preview/pr-1071/0.8/troubleshooting","094"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/0.9",component:p("/contrast/pr-preview/pr-1071/0.9","a1e"),routes:[{path:"/contrast/pr-preview/pr-1071/0.9",component:p("/contrast/pr-preview/pr-1071/0.9","4d3"),routes:[{path:"/contrast/pr-preview/pr-1071/0.9",component:p("/contrast/pr-preview/pr-1071/0.9","172"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/about/telemetry",component:p("/contrast/pr-preview/pr-1071/0.9/about/telemetry","bee"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/0.9/architecture/attestation","3df"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/0.9/architecture/certificates","b26"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/architecture/observability",component:p("/contrast/pr-preview/pr-1071/0.9/architecture/observability","6b0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/architecture/secrets",component:p("/contrast/pr-preview/pr-1071/0.9/architecture/secrets","7ca"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers","5b0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/basics/features",component:p("/contrast/pr-preview/pr-1071/0.9/basics/features","345"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/0.9/basics/security-benefits","f8f"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/components/overview",component:p("/contrast/pr-preview/pr-1071/0.9/components/overview","e5b"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/components/policies",component:p("/contrast/pr-preview/pr-1071/0.9/components/policies","630"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/components/runtime",component:p("/contrast/pr-preview/pr-1071/0.9/components/runtime","242"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/0.9/components/service-mesh","02e"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/deployment",component:p("/contrast/pr-preview/pr-1071/0.9/deployment","002"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/0.9/examples/emojivoto","103"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/features-limitations",component:p("/contrast/pr-preview/pr-1071/0.9/features-limitations","896"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup","011"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/getting-started/install",component:p("/contrast/pr-preview/pr-1071/0.9/getting-started/install","e1a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/0.9/troubleshooting",component:p("/contrast/pr-preview/pr-1071/0.9/troubleshooting","537"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/1.0",component:p("/contrast/pr-preview/pr-1071/1.0","2d1"),routes:[{path:"/contrast/pr-preview/pr-1071/1.0",component:p("/contrast/pr-preview/pr-1071/1.0","d58"),routes:[{path:"/contrast/pr-preview/pr-1071/1.0",component:p("/contrast/pr-preview/pr-1071/1.0","186"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/about/telemetry",component:p("/contrast/pr-preview/pr-1071/1.0/about/telemetry","99b"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/1.0/architecture/attestation","a02"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/1.0/architecture/certificates","81a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/architecture/observability",component:p("/contrast/pr-preview/pr-1071/1.0/architecture/observability","732"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/architecture/secrets",component:p("/contrast/pr-preview/pr-1071/1.0/architecture/secrets","df7"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers","9f0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/basics/features",component:p("/contrast/pr-preview/pr-1071/1.0/basics/features","4f9"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/1.0/basics/security-benefits","1f5"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/components/overview",component:p("/contrast/pr-preview/pr-1071/1.0/components/overview","bc2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/components/policies",component:p("/contrast/pr-preview/pr-1071/1.0/components/policies","13a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/components/runtime",component:p("/contrast/pr-preview/pr-1071/1.0/components/runtime","6c4"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/1.0/components/service-mesh","7ba"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/deployment",component:p("/contrast/pr-preview/pr-1071/1.0/deployment","97f"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/1.0/examples/emojivoto","4ea"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/features-limitations",component:p("/contrast/pr-preview/pr-1071/1.0/features-limitations","e94"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup","4d1"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/getting-started/install",component:p("/contrast/pr-preview/pr-1071/1.0/getting-started/install","2b0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.0/troubleshooting",component:p("/contrast/pr-preview/pr-1071/1.0/troubleshooting","249"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/1.1",component:p("/contrast/pr-preview/pr-1071/1.1","5db"),routes:[{path:"/contrast/pr-preview/pr-1071/1.1",component:p("/contrast/pr-preview/pr-1071/1.1","24c"),routes:[{path:"/contrast/pr-preview/pr-1071/1.1",component:p("/contrast/pr-preview/pr-1071/1.1","ac4"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/about/telemetry",component:p("/contrast/pr-preview/pr-1071/1.1/about/telemetry","237"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/1.1/architecture/attestation","af4"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/1.1/architecture/certificates","6e2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/architecture/observability",component:p("/contrast/pr-preview/pr-1071/1.1/architecture/observability","220"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/architecture/secrets",component:p("/contrast/pr-preview/pr-1071/1.1/architecture/secrets","dac"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations",component:p("/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations","354"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers","fdd"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/basics/features",component:p("/contrast/pr-preview/pr-1071/1.1/basics/features","8ff"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/1.1/basics/security-benefits","5f9"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/components/overview",component:p("/contrast/pr-preview/pr-1071/1.1/components/overview","08b"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/components/policies",component:p("/contrast/pr-preview/pr-1071/1.1/components/policies","1fe"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/components/runtime",component:p("/contrast/pr-preview/pr-1071/1.1/components/runtime","179"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/1.1/components/service-mesh","aac"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/deployment",component:p("/contrast/pr-preview/pr-1071/1.1/deployment","1f2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/1.1/examples/emojivoto","ec4"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/features-limitations",component:p("/contrast/pr-preview/pr-1071/1.1/features-limitations","c73"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal",component:p("/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal","6ec"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup","211"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/getting-started/install",component:p("/contrast/pr-preview/pr-1071/1.1/getting-started/install","897"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/1.1/troubleshooting",component:p("/contrast/pr-preview/pr-1071/1.1/troubleshooting","a8a"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/next",component:p("/contrast/pr-preview/pr-1071/next","a49"),routes:[{path:"/contrast/pr-preview/pr-1071/next",component:p("/contrast/pr-preview/pr-1071/next","d49"),routes:[{path:"/contrast/pr-preview/pr-1071/next",component:p("/contrast/pr-preview/pr-1071/next","223"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/about/telemetry",component:p("/contrast/pr-preview/pr-1071/next/about/telemetry","4d2"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/next/architecture/attestation","876"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/next/architecture/certificates","898"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/architecture/observability",component:p("/contrast/pr-preview/pr-1071/next/architecture/observability","47a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/architecture/secrets",component:p("/contrast/pr-preview/pr-1071/next/architecture/secrets","991"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/architecture/security-considerations",component:p("/contrast/pr-preview/pr-1071/next/architecture/security-considerations","72c"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/next/basics/confidential-containers","bc0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/basics/features",component:p("/contrast/pr-preview/pr-1071/next/basics/features","81d"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/next/basics/security-benefits","952"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/components/overview",component:p("/contrast/pr-preview/pr-1071/next/components/overview","19b"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/components/policies",component:p("/contrast/pr-preview/pr-1071/next/components/policies","2b1"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/components/runtime",component:p("/contrast/pr-preview/pr-1071/next/components/runtime","d46"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/next/components/service-mesh","701"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/deployment",component:p("/contrast/pr-preview/pr-1071/next/deployment","9ee"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/next/examples/emojivoto","a56"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/examples/mysql",component:p("/contrast/pr-preview/pr-1071/next/examples/mysql","d38"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/features-limitations",component:p("/contrast/pr-preview/pr-1071/next/features-limitations","f30"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal",component:p("/contrast/pr-preview/pr-1071/next/getting-started/bare-metal","ae6"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup","4f0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/getting-started/install",component:p("/contrast/pr-preview/pr-1071/next/getting-started/install","fc0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/next/troubleshooting",component:p("/contrast/pr-preview/pr-1071/next/troubleshooting","3ab"),exact:!0,sidebar:"docs"}]}]},{path:"/contrast/pr-preview/pr-1071/",component:p("/contrast/pr-preview/pr-1071/","fe3"),routes:[{path:"/contrast/pr-preview/pr-1071/",component:p("/contrast/pr-preview/pr-1071/","f4c"),routes:[{path:"/contrast/pr-preview/pr-1071/about/telemetry",component:p("/contrast/pr-preview/pr-1071/about/telemetry","ce3"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/architecture/attestation",component:p("/contrast/pr-preview/pr-1071/architecture/attestation","7cd"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/architecture/certificates",component:p("/contrast/pr-preview/pr-1071/architecture/certificates","d75"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/architecture/observability",component:p("/contrast/pr-preview/pr-1071/architecture/observability","9f1"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/architecture/secrets",component:p("/contrast/pr-preview/pr-1071/architecture/secrets","4ce"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/architecture/security-considerations",component:p("/contrast/pr-preview/pr-1071/architecture/security-considerations","c81"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/basics/confidential-containers",component:p("/contrast/pr-preview/pr-1071/basics/confidential-containers","703"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/basics/features",component:p("/contrast/pr-preview/pr-1071/basics/features","046"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/basics/security-benefits",component:p("/contrast/pr-preview/pr-1071/basics/security-benefits","43f"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/components/overview",component:p("/contrast/pr-preview/pr-1071/components/overview","9ba"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/components/policies",component:p("/contrast/pr-preview/pr-1071/components/policies","447"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/components/runtime",component:p("/contrast/pr-preview/pr-1071/components/runtime","c8a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/components/service-mesh",component:p("/contrast/pr-preview/pr-1071/components/service-mesh","8d0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/deployment",component:p("/contrast/pr-preview/pr-1071/deployment","dcc"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/examples/emojivoto",component:p("/contrast/pr-preview/pr-1071/examples/emojivoto","a53"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/examples/mysql",component:p("/contrast/pr-preview/pr-1071/examples/mysql","646"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/features-limitations",component:p("/contrast/pr-preview/pr-1071/features-limitations","914"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/getting-started/bare-metal",component:p("/contrast/pr-preview/pr-1071/getting-started/bare-metal","78b"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/getting-started/cluster-setup",component:p("/contrast/pr-preview/pr-1071/getting-started/cluster-setup","4b6"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/getting-started/install",component:p("/contrast/pr-preview/pr-1071/getting-started/install","17a"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/troubleshooting",component:p("/contrast/pr-preview/pr-1071/troubleshooting","ad0"),exact:!0,sidebar:"docs"},{path:"/contrast/pr-preview/pr-1071/",component:p("/contrast/pr-preview/pr-1071/","d63"),exact:!0,sidebar:"docs"}]}]}]},{path:"*",component:p("*")}]},60774:(e,t,n)=>{var r,o;!function(){var a,i,s,c,l,u,p,d,f,m,h,v,g,b,y,w,_,x,S,k,E,O,j,P,C,A,T,I,N,L,R=function(e){var t=new R.Builder;return t.pipeline.add(R.trimmer,R.stopWordFilter,R.stemmer),t.searchPipeline.add(R.stemmer),e.call(t,t),t.build()};R.version="2.3.9",R.utils={},R.utils.warn=(a=this,function(e){a.console&&console.warn&&console.warn(e)}),R.utils.asString=function(e){return null==e?"":e.toString()},R.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),n=Object.keys(e),r=0;r<n.length;r++){var o=n[r],a=e[o];if(Array.isArray(a))t[o]=a.slice();else{if("string"!=typeof a&&"number"!=typeof a&&"boolean"!=typeof a)throw new TypeError("clone is not deep and does not support nested objects");t[o]=a}}return t},R.FieldRef=function(e,t,n){this.docRef=e,this.fieldName=t,this._stringValue=n},R.FieldRef.joiner="/",R.FieldRef.fromString=function(e){var t=e.indexOf(R.FieldRef.joiner);if(-1===t)throw"malformed field ref string";var n=e.slice(0,t),r=e.slice(t+1);return new R.FieldRef(r,n,e)},R.FieldRef.prototype.toString=function(){return null==this._stringValue&&(this._stringValue=this.fieldName+R.FieldRef.joiner+this.docRef),this._stringValue},R.Set=function(e){if(this.elements=Object.create(null),e){this.length=e.length;for(var t=0;t<this.length;t++)this.elements[e[t]]=!0}else this.length=0},R.Set.complete={intersect:function(e){return e},union:function(){return this},contains:function(){return!0}},R.Set.empty={intersect:function(){return this},union:function(e){return e},contains:function(){return!1}},R.Set.prototype.contains=function(e){return!!this.elements[e]},R.Set.prototype.intersect=function(e){var t,n,r,o=[];if(e===R.Set.complete)return this;if(e===R.Set.empty)return e;this.length<e.length?(t=this,n=e):(t=e,n=this),r=Object.keys(t.elements);for(var a=0;a<r.length;a++){var i=r[a];i in n.elements&&o.push(i)}return new R.Set(o)},R.Set.prototype.union=function(e){return e===R.Set.complete?R.Set.complete:e===R.Set.empty?this:new R.Set(Object.keys(this.elements).concat(Object.keys(e.elements)))},R.idf=function(e,t){var n=0;for(var r in e)"_index"!=r&&(n+=Object.keys(e[r]).length);var o=(t-n+.5)/(n+.5);return Math.log(1+Math.abs(o))},R.Token=function(e,t){this.str=e||"",this.metadata=t||{}},R.Token.prototype.toString=function(){return this.str},R.Token.prototype.update=function(e){return this.str=e(this.str,this.metadata),this},R.Token.prototype.clone=function(e){return e=e||function(e){return e},new R.Token(e(this.str,this.metadata),this.metadata)},R.tokenizer=function(e,t){if(null==e||null==e)return[];if(Array.isArray(e))return e.map((function(e){return new R.Token(R.utils.asString(e).toLowerCase(),R.utils.clone(t))}));for(var n=e.toString().toLowerCase(),r=n.length,o=[],a=0,i=0;a<=r;a++){var s=a-i;if(n.charAt(a).match(R.tokenizer.separator)||a==r){if(s>0){var c=R.utils.clone(t)||{};c.position=[i,s],c.index=o.length,o.push(new R.Token(n.slice(i,a),c))}i=a+1}}return o},R.tokenizer.separator=/[\s\-]+/,R.Pipeline=function(){this._stack=[]},R.Pipeline.registeredFunctions=Object.create(null),R.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&R.utils.warn("Overwriting existing registered function: "+t),e.label=t,R.Pipeline.registeredFunctions[e.label]=e},R.Pipeline.warnIfFunctionNotRegistered=function(e){e.label&&e.label in this.registeredFunctions||R.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},R.Pipeline.load=function(e){var t=new R.Pipeline;return e.forEach((function(e){var n=R.Pipeline.registeredFunctions[e];if(!n)throw new Error("Cannot load unregistered function: "+e);t.add(n)})),t},R.Pipeline.prototype.add=function(){Array.prototype.slice.call(arguments).forEach((function(e){R.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)}),this)},R.Pipeline.prototype.after=function(e,t){R.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");n+=1,this._stack.splice(n,0,t)},R.Pipeline.prototype.before=function(e,t){R.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");this._stack.splice(n,0,t)},R.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);-1!=t&&this._stack.splice(t,1)},R.Pipeline.prototype.run=function(e){for(var t=this._stack.length,n=0;n<t;n++){for(var r=this._stack[n],o=[],a=0;a<e.length;a++){var i=r(e[a],a,e);if(null!=i&&""!==i)if(Array.isArray(i))for(var s=0;s<i.length;s++)o.push(i[s]);else o.push(i)}e=o}return e},R.Pipeline.prototype.runString=function(e,t){var n=new R.Token(e,t);return this.run([n]).map((function(e){return e.toString()}))},R.Pipeline.prototype.reset=function(){this._stack=[]},R.Pipeline.prototype.toJSON=function(){return this._stack.map((function(e){return R.Pipeline.warnIfFunctionNotRegistered(e),e.label}))},R.Vector=function(e){this._magnitude=0,this.elements=e||[]},R.Vector.prototype.positionForIndex=function(e){if(0==this.elements.length)return 0;for(var t=0,n=this.elements.length/2,r=n-t,o=Math.floor(r/2),a=this.elements[2*o];r>1&&(a<e&&(t=o),a>e&&(n=o),a!=e);)r=n-t,o=t+Math.floor(r/2),a=this.elements[2*o];return a==e||a>e?2*o:a<e?2*(o+1):void 0},R.Vector.prototype.insert=function(e,t){this.upsert(e,t,(function(){throw"duplicate index"}))},R.Vector.prototype.upsert=function(e,t,n){this._magnitude=0;var r=this.positionForIndex(e);this.elements[r]==e?this.elements[r+1]=n(this.elements[r+1],t):this.elements.splice(r,0,e,t)},R.Vector.prototype.magnitude=function(){if(this._magnitude)return this._magnitude;for(var e=0,t=this.elements.length,n=1;n<t;n+=2){var r=this.elements[n];e+=r*r}return this._magnitude=Math.sqrt(e)},R.Vector.prototype.dot=function(e){for(var t=0,n=this.elements,r=e.elements,o=n.length,a=r.length,i=0,s=0,c=0,l=0;c<o&&l<a;)(i=n[c])<(s=r[l])?c+=2:i>s?l+=2:i==s&&(t+=n[c+1]*r[l+1],c+=2,l+=2);return t},R.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},R.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,n=0;t<this.elements.length;t+=2,n++)e[n]=this.elements[t];return e},R.Vector.prototype.toJSON=function(){return this.elements},R.stemmer=(i={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"},s={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},p="^("+(l="[^aeiou][^aeiouy]*")+")?"+(u=(c="[aeiouy]")+"[aeiou]*")+l+"("+u+")?$",d="^("+l+")?"+u+l+u+l,f="^("+l+")?"+c,m=new RegExp("^("+l+")?"+u+l),h=new RegExp(d),v=new RegExp(p),g=new RegExp(f),b=/^(.+?)(ss|i)es$/,y=/^(.+?)([^s])s$/,w=/^(.+?)eed$/,_=/^(.+?)(ed|ing)$/,x=/.$/,S=/(at|bl|iz)$/,k=new RegExp("([^aeiouylsz])\\1$"),E=new RegExp("^"+l+c+"[^aeiouwxy]$"),O=/^(.+?[^aeiou])y$/,j=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,P=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,C=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,A=/^(.+?)(s|t)(ion)$/,T=/^(.+?)e$/,I=/ll$/,N=new RegExp("^"+l+c+"[^aeiouwxy]$"),L=function(e){var t,n,r,o,a,c,l;if(e.length<3)return e;if("y"==(r=e.substr(0,1))&&(e=r.toUpperCase()+e.substr(1)),a=y,(o=b).test(e)?e=e.replace(o,"$1$2"):a.test(e)&&(e=e.replace(a,"$1$2")),a=_,(o=w).test(e)){var u=o.exec(e);(o=m).test(u[1])&&(o=x,e=e.replace(o,""))}else a.test(e)&&(t=(u=a.exec(e))[1],(a=g).test(t)&&(c=k,l=E,(a=S).test(e=t)?e+="e":c.test(e)?(o=x,e=e.replace(o,"")):l.test(e)&&(e+="e")));return(o=O).test(e)&&(e=(t=(u=o.exec(e))[1])+"i"),(o=j).test(e)&&(t=(u=o.exec(e))[1],n=u[2],(o=m).test(t)&&(e=t+i[n])),(o=P).test(e)&&(t=(u=o.exec(e))[1],n=u[2],(o=m).test(t)&&(e=t+s[n])),a=A,(o=C).test(e)?(t=(u=o.exec(e))[1],(o=h).test(t)&&(e=t)):a.test(e)&&(t=(u=a.exec(e))[1]+u[2],(a=h).test(t)&&(e=t)),(o=T).test(e)&&(t=(u=o.exec(e))[1],a=v,c=N,((o=h).test(t)||a.test(t)&&!c.test(t))&&(e=t)),a=h,(o=I).test(e)&&a.test(e)&&(o=x,e=e.replace(o,"")),"y"==r&&(e=r.toLowerCase()+e.substr(1)),e},function(e){return e.update(L)}),R.Pipeline.registerFunction(R.stemmer,"stemmer"),R.generateStopWordFilter=function(e){var t=e.reduce((function(e,t){return e[t]=t,e}),{});return function(e){if(e&&t[e.toString()]!==e.toString())return e}},R.stopWordFilter=R.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),R.Pipeline.registerFunction(R.stopWordFilter,"stopWordFilter"),R.trimmer=function(e){return e.update((function(e){return e.replace(/^\W+/,"").replace(/\W+$/,"")}))},R.Pipeline.registerFunction(R.trimmer,"trimmer"),R.TokenSet=function(){this.final=!1,this.edges={},this.id=R.TokenSet._nextId,R.TokenSet._nextId+=1},R.TokenSet._nextId=1,R.TokenSet.fromArray=function(e){for(var t=new R.TokenSet.Builder,n=0,r=e.length;n<r;n++)t.insert(e[n]);return t.finish(),t.root},R.TokenSet.fromClause=function(e){return"editDistance"in e?R.TokenSet.fromFuzzyString(e.term,e.editDistance):R.TokenSet.fromString(e.term)},R.TokenSet.fromFuzzyString=function(e,t){for(var n=new R.TokenSet,r=[{node:n,editsRemaining:t,str:e}];r.length;){var o=r.pop();if(o.str.length>0){var a,i=o.str.charAt(0);i in o.node.edges?a=o.node.edges[i]:(a=new R.TokenSet,o.node.edges[i]=a),1==o.str.length&&(a.final=!0),r.push({node:a,editsRemaining:o.editsRemaining,str:o.str.slice(1)})}if(0!=o.editsRemaining){if("*"in o.node.edges)var s=o.node.edges["*"];else{s=new R.TokenSet;o.node.edges["*"]=s}if(0==o.str.length&&(s.final=!0),r.push({node:s,editsRemaining:o.editsRemaining-1,str:o.str}),o.str.length>1&&r.push({node:o.node,editsRemaining:o.editsRemaining-1,str:o.str.slice(1)}),1==o.str.length&&(o.node.final=!0),o.str.length>=1){if("*"in o.node.edges)var c=o.node.edges["*"];else{c=new R.TokenSet;o.node.edges["*"]=c}1==o.str.length&&(c.final=!0),r.push({node:c,editsRemaining:o.editsRemaining-1,str:o.str.slice(1)})}if(o.str.length>1){var l,u=o.str.charAt(0),p=o.str.charAt(1);p in o.node.edges?l=o.node.edges[p]:(l=new R.TokenSet,o.node.edges[p]=l),1==o.str.length&&(l.final=!0),r.push({node:l,editsRemaining:o.editsRemaining-1,str:u+o.str.slice(2)})}}}return n},R.TokenSet.fromString=function(e){for(var t=new R.TokenSet,n=t,r=0,o=e.length;r<o;r++){var a=e[r],i=r==o-1;if("*"==a)t.edges[a]=t,t.final=i;else{var s=new R.TokenSet;s.final=i,t.edges[a]=s,t=s}}return n},R.TokenSet.prototype.toArray=function(){for(var e=[],t=[{prefix:"",node:this}];t.length;){var n=t.pop(),r=Object.keys(n.node.edges),o=r.length;n.node.final&&(n.prefix.charAt(0),e.push(n.prefix));for(var a=0;a<o;a++){var i=r[a];t.push({prefix:n.prefix.concat(i),node:n.node.edges[i]})}}return e},R.TokenSet.prototype.toString=function(){if(this._str)return this._str;for(var e=this.final?"1":"0",t=Object.keys(this.edges).sort(),n=t.length,r=0;r<n;r++){var o=t[r];e=e+o+this.edges[o].id}return e},R.TokenSet.prototype.intersect=function(e){for(var t=new R.TokenSet,n=void 0,r=[{qNode:e,output:t,node:this}];r.length;){n=r.pop();for(var o=Object.keys(n.qNode.edges),a=o.length,i=Object.keys(n.node.edges),s=i.length,c=0;c<a;c++)for(var l=o[c],u=0;u<s;u++){var p=i[u];if(p==l||"*"==l){var d=n.node.edges[p],f=n.qNode.edges[l],m=d.final&&f.final,h=void 0;p in n.output.edges?(h=n.output.edges[p]).final=h.final||m:((h=new R.TokenSet).final=m,n.output.edges[p]=h),r.push({qNode:f,output:h,node:d})}}}return t},R.TokenSet.Builder=function(){this.previousWord="",this.root=new R.TokenSet,this.uncheckedNodes=[],this.minimizedNodes={}},R.TokenSet.Builder.prototype.insert=function(e){var t,n=0;if(e<this.previousWord)throw new Error("Out of order word insertion");for(var r=0;r<e.length&&r<this.previousWord.length&&e[r]==this.previousWord[r];r++)n++;this.minimize(n),t=0==this.uncheckedNodes.length?this.root:this.uncheckedNodes[this.uncheckedNodes.length-1].child;for(r=n;r<e.length;r++){var o=new R.TokenSet,a=e[r];t.edges[a]=o,this.uncheckedNodes.push({parent:t,char:a,child:o}),t=o}t.final=!0,this.previousWord=e},R.TokenSet.Builder.prototype.finish=function(){this.minimize(0)},R.TokenSet.Builder.prototype.minimize=function(e){for(var t=this.uncheckedNodes.length-1;t>=e;t--){var n=this.uncheckedNodes[t],r=n.child.toString();r in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[r]:(n.child._str=r,this.minimizedNodes[r]=n.child),this.uncheckedNodes.pop()}},R.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},R.Index.prototype.search=function(e){return this.query((function(t){new R.QueryParser(e,t).parse()}))},R.Index.prototype.query=function(e){for(var t=new R.Query(this.fields),n=Object.create(null),r=Object.create(null),o=Object.create(null),a=Object.create(null),i=Object.create(null),s=0;s<this.fields.length;s++)r[this.fields[s]]=new R.Vector;e.call(t,t);for(s=0;s<t.clauses.length;s++){var c=t.clauses[s],l=null,u=R.Set.empty;l=c.usePipeline?this.pipeline.runString(c.term,{fields:c.fields}):[c.term];for(var p=0;p<l.length;p++){var d=l[p];c.term=d;var f=R.TokenSet.fromClause(c),m=this.tokenSet.intersect(f).toArray();if(0===m.length&&c.presence===R.Query.presence.REQUIRED){for(var h=0;h<c.fields.length;h++){a[T=c.fields[h]]=R.Set.empty}break}for(var v=0;v<m.length;v++){var g=m[v],b=this.invertedIndex[g],y=b._index;for(h=0;h<c.fields.length;h++){var w=b[T=c.fields[h]],_=Object.keys(w),x=g+"/"+T,S=new R.Set(_);if(c.presence==R.Query.presence.REQUIRED&&(u=u.union(S),void 0===a[T]&&(a[T]=R.Set.complete)),c.presence!=R.Query.presence.PROHIBITED){if(r[T].upsert(y,c.boost,(function(e,t){return e+t})),!o[x]){for(var k=0;k<_.length;k++){var E,O=_[k],j=new R.FieldRef(O,T),P=w[O];void 0===(E=n[j])?n[j]=new R.MatchData(g,T,P):E.add(g,T,P)}o[x]=!0}}else void 0===i[T]&&(i[T]=R.Set.empty),i[T]=i[T].union(S)}}}if(c.presence===R.Query.presence.REQUIRED)for(h=0;h<c.fields.length;h++){a[T=c.fields[h]]=a[T].intersect(u)}}var C=R.Set.complete,A=R.Set.empty;for(s=0;s<this.fields.length;s++){var T;a[T=this.fields[s]]&&(C=C.intersect(a[T])),i[T]&&(A=A.union(i[T]))}var I=Object.keys(n),N=[],L=Object.create(null);if(t.isNegated()){I=Object.keys(this.fieldVectors);for(s=0;s<I.length;s++){j=I[s];var D=R.FieldRef.fromString(j);n[j]=new R.MatchData}}for(s=0;s<I.length;s++){var F=(D=R.FieldRef.fromString(I[s])).docRef;if(C.contains(F)&&!A.contains(F)){var M,B=this.fieldVectors[D],z=r[D.fieldName].similarity(B);if(void 0!==(M=L[F]))M.score+=z,M.matchData.combine(n[D]);else{var $={ref:F,score:z,matchData:n[D]};L[F]=$,N.push($)}}}return N.sort((function(e,t){return t.score-e.score}))},R.Index.prototype.toJSON=function(){var e=Object.keys(this.invertedIndex).sort().map((function(e){return[e,this.invertedIndex[e]]}),this),t=Object.keys(this.fieldVectors).map((function(e){return[e,this.fieldVectors[e].toJSON()]}),this);return{version:R.version,fields:this.fields,fieldVectors:t,invertedIndex:e,pipeline:this.pipeline.toJSON()}},R.Index.load=function(e){var t={},n={},r=e.fieldVectors,o=Object.create(null),a=e.invertedIndex,i=new R.TokenSet.Builder,s=R.Pipeline.load(e.pipeline);e.version!=R.version&&R.utils.warn("Version mismatch when loading serialised index. Current version of lunr '"+R.version+"' does not match serialized index '"+e.version+"'");for(var c=0;c<r.length;c++){var l=(p=r[c])[0],u=p[1];n[l]=new R.Vector(u)}for(c=0;c<a.length;c++){var p,d=(p=a[c])[0],f=p[1];i.insert(d),o[d]=f}return i.finish(),t.fields=e.fields,t.fieldVectors=n,t.invertedIndex=o,t.tokenSet=i.root,t.pipeline=s,new R.Index(t)},R.Builder=function(){this._ref="id",this._fields=Object.create(null),this._documents=Object.create(null),this.invertedIndex=Object.create(null),this.fieldTermFrequencies={},this.fieldLengths={},this.tokenizer=R.tokenizer,this.pipeline=new R.Pipeline,this.searchPipeline=new R.Pipeline,this.documentCount=0,this._b=.75,this._k1=1.2,this.termIndex=0,this.metadataWhitelist=[]},R.Builder.prototype.ref=function(e){this._ref=e},R.Builder.prototype.field=function(e,t){if(/\//.test(e))throw new RangeError("Field '"+e+"' contains illegal character '/'");this._fields[e]=t||{}},R.Builder.prototype.b=function(e){this._b=e<0?0:e>1?1:e},R.Builder.prototype.k1=function(e){this._k1=e},R.Builder.prototype.add=function(e,t){var n=e[this._ref],r=Object.keys(this._fields);this._documents[n]=t||{},this.documentCount+=1;for(var o=0;o<r.length;o++){var a=r[o],i=this._fields[a].extractor,s=this._fields[a].isLiteral??!1,c=i?i(e):e[a],l=s?[c]:this.tokenizer(c,{fields:[a]}),u=s?l:this.pipeline.run(l),p=new R.FieldRef(n,a),d=Object.create(null);this.fieldTermFrequencies[p]=d,this.fieldLengths[p]=0,this.fieldLengths[p]+=u.length;for(var f=0;f<u.length;f++){var m=u[f];if(null==d[m]&&(d[m]=0),d[m]+=1,null==this.invertedIndex[m]){var h=Object.create(null);h._index=this.termIndex,this.termIndex+=1;for(var v=0;v<r.length;v++)h[r[v]]=Object.create(null);this.invertedIndex[m]=h}null==this.invertedIndex[m][a][n]&&(this.invertedIndex[m][a][n]=Object.create(null));for(var g=0;g<this.metadataWhitelist.length;g++){var b=this.metadataWhitelist[g],y=m.metadata[b];null==this.invertedIndex[m][a][n][b]&&(this.invertedIndex[m][a][n][b]=[]),this.invertedIndex[m][a][n][b].push(y)}}}},R.Builder.prototype.calculateAverageFieldLengths=function(){for(var e=Object.keys(this.fieldLengths),t=e.length,n={},r={},o=0;o<t;o++){var a=R.FieldRef.fromString(e[o]),i=a.fieldName;r[i]||(r[i]=0),r[i]+=1,n[i]||(n[i]=0),n[i]+=this.fieldLengths[a]}var s=Object.keys(this._fields);for(o=0;o<s.length;o++){var c=s[o];n[c]=n[c]/r[c]}this.averageFieldLength=n},R.Builder.prototype.createFieldVectors=function(){for(var e={},t=Object.keys(this.fieldTermFrequencies),n=t.length,r=Object.create(null),o=0;o<n;o++){for(var a=R.FieldRef.fromString(t[o]),i=a.fieldName,s=this.fieldLengths[a],c=new R.Vector,l=this.fieldTermFrequencies[a],u=Object.keys(l),p=u.length,d=this._fields[i].boost||1,f=this._documents[a.docRef].boost||1,m=0;m<p;m++){var h,v,g,b=u[m],y=l[b],w=this.invertedIndex[b]._index;void 0===r[b]?(h=R.idf(this.invertedIndex[b],this.documentCount),r[b]=h):h=r[b],v=h*((this._k1+1)*y)/(this._k1*(1-this._b+this._b*(s/this.averageFieldLength[i]))+y),v*=d,v*=f,g=Math.round(1e3*v)/1e3,c.insert(w,g)}e[a]=c}this.fieldVectors=e},R.Builder.prototype.createTokenSet=function(){this.tokenSet=R.TokenSet.fromArray(Object.keys(this.invertedIndex).sort())},R.Builder.prototype.build=function(){return this.calculateAverageFieldLengths(),this.createFieldVectors(),this.createTokenSet(),new R.Index({invertedIndex:this.invertedIndex,fieldVectors:this.fieldVectors,tokenSet:this.tokenSet,fields:Object.keys(this._fields),pipeline:this.searchPipeline})},R.Builder.prototype.use=function(e){var t=Array.prototype.slice.call(arguments,1);t.unshift(this),e.apply(this,t)},R.MatchData=function(e,t,n){for(var r=Object.create(null),o=Object.keys(n||{}),a=0;a<o.length;a++){var i=o[a];r[i]=n[i].slice()}this.metadata=Object.create(null),void 0!==e&&(this.metadata[e]=Object.create(null),this.metadata[e][t]=r)},R.MatchData.prototype.combine=function(e){for(var t=Object.keys(e.metadata),n=0;n<t.length;n++){var r=t[n],o=Object.keys(e.metadata[r]);null==this.metadata[r]&&(this.metadata[r]=Object.create(null));for(var a=0;a<o.length;a++){var i=o[a],s=Object.keys(e.metadata[r][i]);null==this.metadata[r][i]&&(this.metadata[r][i]=Object.create(null));for(var c=0;c<s.length;c++){var l=s[c];null==this.metadata[r][i][l]?this.metadata[r][i][l]=e.metadata[r][i][l]:this.metadata[r][i][l]=this.metadata[r][i][l].concat(e.metadata[r][i][l])}}}},R.MatchData.prototype.add=function(e,t,n){if(!(e in this.metadata))return this.metadata[e]=Object.create(null),void(this.metadata[e][t]=n);if(t in this.metadata[e])for(var r=Object.keys(n),o=0;o<r.length;o++){var a=r[o];a in this.metadata[e][t]?this.metadata[e][t][a]=this.metadata[e][t][a].concat(n[a]):this.metadata[e][t][a]=n[a]}else this.metadata[e][t]=n},R.Query=function(e){this.clauses=[],this.allFields=e},R.Query.wildcard=new String("*"),R.Query.wildcard.NONE=0,R.Query.wildcard.LEADING=1,R.Query.wildcard.TRAILING=2,R.Query.presence={OPTIONAL:1,REQUIRED:2,PROHIBITED:3},R.Query.prototype.clause=function(e){return"fields"in e||(e.fields=this.allFields),"boost"in e||(e.boost=1),"usePipeline"in e||(e.usePipeline=!0),"wildcard"in e||(e.wildcard=R.Query.wildcard.NONE),e.wildcard&R.Query.wildcard.LEADING&&e.term.charAt(0)!=R.Query.wildcard&&(e.term="*"+e.term),e.wildcard&R.Query.wildcard.TRAILING&&e.term.slice(-1)!=R.Query.wildcard&&(e.term=e.term+"*"),"presence"in e||(e.presence=R.Query.presence.OPTIONAL),this.clauses.push(e),this},R.Query.prototype.isNegated=function(){for(var e=0;e<this.clauses.length;e++)if(this.clauses[e].presence!=R.Query.presence.PROHIBITED)return!1;return!0},R.Query.prototype.term=function(e,t){if(Array.isArray(e))return e.forEach((function(e){this.term(e,R.utils.clone(t))}),this),this;var n=t||{};return n.term=e.toString(),this.clause(n),this},R.QueryParseError=function(e,t,n){this.name="QueryParseError",this.message=e,this.start=t,this.end=n},R.QueryParseError.prototype=new Error,R.QueryLexer=function(e){this.lexemes=[],this.str=e,this.length=e.length,this.pos=0,this.start=0,this.escapeCharPositions=[]},R.QueryLexer.prototype.run=function(){for(var e=R.QueryLexer.lexText;e;)e=e(this)},R.QueryLexer.prototype.sliceString=function(){for(var e=[],t=this.start,n=this.pos,r=0;r<this.escapeCharPositions.length;r++)n=this.escapeCharPositions[r],e.push(this.str.slice(t,n)),t=n+1;return e.push(this.str.slice(t,this.pos)),this.escapeCharPositions.length=0,e.join("")},R.QueryLexer.prototype.emit=function(e){this.lexemes.push({type:e,str:this.sliceString(),start:this.start,end:this.pos}),this.start=this.pos},R.QueryLexer.prototype.escapeCharacter=function(){this.escapeCharPositions.push(this.pos-1),this.pos+=1},R.QueryLexer.prototype.next=function(){if(this.pos>=this.length)return R.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},R.QueryLexer.prototype.width=function(){return this.pos-this.start},R.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},R.QueryLexer.prototype.backup=function(){this.pos-=1},R.QueryLexer.prototype.acceptDigitRun=function(){var e,t;do{t=(e=this.next()).charCodeAt(0)}while(t>47&&t<58);e!=R.QueryLexer.EOS&&this.backup()},R.QueryLexer.prototype.more=function(){return this.pos<this.length},R.QueryLexer.EOS="EOS",R.QueryLexer.FIELD="FIELD",R.QueryLexer.TERM="TERM",R.QueryLexer.EDIT_DISTANCE="EDIT_DISTANCE",R.QueryLexer.BOOST="BOOST",R.QueryLexer.PRESENCE="PRESENCE",R.QueryLexer.lexField=function(e){return e.backup(),e.emit(R.QueryLexer.FIELD),e.ignore(),R.QueryLexer.lexText},R.QueryLexer.lexTerm=function(e){if(e.width()>1&&(e.backup(),e.emit(R.QueryLexer.TERM)),e.ignore(),e.more())return R.QueryLexer.lexText},R.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(R.QueryLexer.EDIT_DISTANCE),R.QueryLexer.lexText},R.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(R.QueryLexer.BOOST),R.QueryLexer.lexText},R.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(R.QueryLexer.TERM)},R.QueryLexer.termSeparator=R.tokenizer.separator,R.QueryLexer.lexText=function(e){for(;;){var t=e.next();if(t==R.QueryLexer.EOS)return R.QueryLexer.lexEOS;if(92!=t.charCodeAt(0)){if(":"==t)return R.QueryLexer.lexField;if("~"==t)return e.backup(),e.width()>0&&e.emit(R.QueryLexer.TERM),R.QueryLexer.lexEditDistance;if("^"==t)return e.backup(),e.width()>0&&e.emit(R.QueryLexer.TERM),R.QueryLexer.lexBoost;if("+"==t&&1===e.width())return e.emit(R.QueryLexer.PRESENCE),R.QueryLexer.lexText;if("-"==t&&1===e.width())return e.emit(R.QueryLexer.PRESENCE),R.QueryLexer.lexText;if(t.match(R.QueryLexer.termSeparator))return R.QueryLexer.lexTerm}else e.escapeCharacter()}},R.QueryParser=function(e,t){this.lexer=new R.QueryLexer(e),this.query=t,this.currentClause={},this.lexemeIdx=0},R.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=R.QueryParser.parseClause;e;)e=e(this);return this.query},R.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},R.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},R.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},R.QueryParser.parseClause=function(e){var t=e.peekLexeme();if(null!=t)switch(t.type){case R.QueryLexer.PRESENCE:return R.QueryParser.parsePresence;case R.QueryLexer.FIELD:return R.QueryParser.parseField;case R.QueryLexer.TERM:return R.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+t.type;throw t.str.length>=1&&(n+=" with value '"+t.str+"'"),new R.QueryParseError(n,t.start,t.end)}},R.QueryParser.parsePresence=function(e){var t=e.consumeLexeme();if(null!=t){switch(t.str){case"-":e.currentClause.presence=R.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=R.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+t.str+"'";throw new R.QueryParseError(n,t.start,t.end)}var r=e.peekLexeme();if(null==r){n="expecting term or field, found nothing";throw new R.QueryParseError(n,t.start,t.end)}switch(r.type){case R.QueryLexer.FIELD:return R.QueryParser.parseField;case R.QueryLexer.TERM:return R.QueryParser.parseTerm;default:n="expecting term or field, found '"+r.type+"'";throw new R.QueryParseError(n,r.start,r.end)}}},R.QueryParser.parseField=function(e){var t=e.consumeLexeme();if(null!=t){if(-1==e.query.allFields.indexOf(t.str)){var n=e.query.allFields.map((function(e){return"'"+e+"'"})).join(", "),r="unrecognised field '"+t.str+"', possible fields: "+n;throw new R.QueryParseError(r,t.start,t.end)}e.currentClause.fields=[t.str];var o=e.peekLexeme();if(null==o){r="expecting term, found nothing";throw new R.QueryParseError(r,t.start,t.end)}if(o.type===R.QueryLexer.TERM)return R.QueryParser.parseTerm;r="expecting term, found '"+o.type+"'";throw new R.QueryParseError(r,o.start,o.end)}},R.QueryParser.parseTerm=function(e){var t=e.consumeLexeme();if(null!=t){e.currentClause.term=t.str.toLowerCase(),-1!=t.str.indexOf("*")&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(null!=n)switch(n.type){case R.QueryLexer.TERM:return e.nextClause(),R.QueryParser.parseTerm;case R.QueryLexer.FIELD:return e.nextClause(),R.QueryParser.parseField;case R.QueryLexer.EDIT_DISTANCE:return R.QueryParser.parseEditDistance;case R.QueryLexer.BOOST:return R.QueryParser.parseBoost;case R.QueryLexer.PRESENCE:return e.nextClause(),R.QueryParser.parsePresence;default:var r="Unexpected lexeme type '"+n.type+"'";throw new R.QueryParseError(r,n.start,n.end)}else e.nextClause()}},R.QueryParser.parseEditDistance=function(e){var t=e.consumeLexeme();if(null!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="edit distance must be numeric";throw new R.QueryParseError(r,t.start,t.end)}e.currentClause.editDistance=n;var o=e.peekLexeme();if(null!=o)switch(o.type){case R.QueryLexer.TERM:return e.nextClause(),R.QueryParser.parseTerm;case R.QueryLexer.FIELD:return e.nextClause(),R.QueryParser.parseField;case R.QueryLexer.EDIT_DISTANCE:return R.QueryParser.parseEditDistance;case R.QueryLexer.BOOST:return R.QueryParser.parseBoost;case R.QueryLexer.PRESENCE:return e.nextClause(),R.QueryParser.parsePresence;default:r="Unexpected lexeme type '"+o.type+"'";throw new R.QueryParseError(r,o.start,o.end)}else e.nextClause()}},R.QueryParser.parseBoost=function(e){var t=e.consumeLexeme();if(null!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="boost must be numeric";throw new R.QueryParseError(r,t.start,t.end)}e.currentClause.boost=n;var o=e.peekLexeme();if(null!=o)switch(o.type){case R.QueryLexer.TERM:return e.nextClause(),R.QueryParser.parseTerm;case R.QueryLexer.FIELD:return e.nextClause(),R.QueryParser.parseField;case R.QueryLexer.EDIT_DISTANCE:return R.QueryParser.parseEditDistance;case R.QueryLexer.BOOST:return R.QueryParser.parseBoost;case R.QueryLexer.PRESENCE:return e.nextClause(),R.QueryParser.parsePresence;default:r="Unexpected lexeme type '"+o.type+"'";throw new R.QueryParseError(r,o.start,o.end)}else e.nextClause()}},void 0===(o="function"==typeof(r=function(){return R})?r.call(t,n,t,e):r)||(e.exports=o)}()},48848:(e,t,n)=>{"use strict";n.d(t,{o:()=>a,x:()=>i});var r=n(96540),o=n(74848);const a=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),(0,o.jsx)(a.Provider,{value:n,children:t})}},45022:(e,t,n)=>{"use strict";var r=n(96540),o=n(5338),a=n(80545),i=n(54625),s=n(4784),c=n(31712);const l=[n(85300),n(74753),n(75729),n(58252)];var u=n(92413),p=n(56347),d=n(22831),f=n(74848);function m(e){let{children:t}=e;return(0,f.jsx)(f.Fragment,{children:t})}var h=n(21141),v=n(97639),g=n(98180),b=n(86957),y=n(69817),w=n(2098),_=n(19503),x=n(61482),S=n(64609),k=n(51210);function E(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,v.A)(),r=(0,w.o)(),o=n[e].htmlLang,a=e=>e.replace("-","_");return(0,f.jsxs)(h.A,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,f.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,f.jsx)("meta",{property:"og:locale",content:a(o)}),Object.values(n).filter((e=>o!==e.htmlLang)).map((e=>(0,f.jsx)("meta",{property:"og:locale:alternate",content:a(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function O(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,v.A)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,v.A)(),{pathname:r}=(0,p.zy)();return e+(0,S.Ks)((0,g.Ay)(r),{trailingSlash:n,baseUrl:t})}(),o=t?`${n}${t}`:r;return(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{property:"og:url",content:o}),(0,f.jsx)("link",{rel:"canonical",href:o})]})}function j(){const{i18n:{currentLocale:e}}=(0,v.A)(),{metadata:t,image:n}=(0,b.p)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,f.jsx)("body",{className:_.w})]}),n&&(0,f.jsx)(y.be,{image:n}),(0,f.jsx)(O,{}),(0,f.jsx)(E,{}),(0,f.jsx)(k.A,{tag:x.C,locale:e}),(0,f.jsx)(h.A,{children:t.map(((e,t)=>(0,f.jsx)("meta",{...e},t)))})]})}const P=new Map;var C=n(48848),A=n(53366),T=n(36494);function I(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const o=l.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>o.forEach((e=>e?.()))}const N=function(e){let{children:t,location:n,previousLocation:r}=e;return(0,T.A)((()=>{r!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,o=t.hash===n.hash,a=t.search===n.search;if(r&&o&&!a)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:r}),I("onRouteDidUpdate",{previousLocation:r,location:n}))}),[r,n]),t};function L(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.u)(u.A,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class R extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=c.A.canUseDOM?I("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=I("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),L(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return(0,f.jsx)(N,{previousLocation:this.previousLocation,location:t,children:(0,f.jsx)(p.qh,{location:t,render:()=>e})})}}const D=R,F="__docusaurus-base-url-issue-banner-suggestion-container";function M(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '__docusaurus-base-url-issue-banner-container';\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="__docusaurus-base-url-issue-banner" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${F}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n document.body.prepend(bannerContainer);\n var suggestionContainer = document.getElementById('${F}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function B(){const{siteConfig:{baseUrl:e}}=(0,v.A)();return(0,f.jsx)(f.Fragment,{children:!c.A.canUseDOM&&(0,f.jsx)(h.A,{children:(0,f.jsx)("script",{children:M(e)})})})}function z(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,v.A)(),{pathname:n}=(0,p.zy)();return t&&n===e?(0,f.jsx)(B,{}):null}function $(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:r,localeConfigs:o}}=(0,v.A)(),a=(0,g.Ay)(e),{htmlLang:i,direction:s}=o[r];return(0,f.jsxs)(h.A,{children:[(0,f.jsx)("html",{lang:i,dir:s}),(0,f.jsx)("title",{children:t}),(0,f.jsx)("meta",{property:"og:title",content:t}),(0,f.jsx)("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&(0,f.jsx)("meta",{name:"robots",content:"noindex, nofollow"}),e&&(0,f.jsx)("link",{rel:"icon",href:a})]})}var U=n(33832),H=n(11062);function V(){const e=(0,H.A)();return(0,f.jsx)(h.A,{children:(0,f.jsx)("html",{"data-has-hydrated":e})})}const W=(0,d.v)(u.A);function Q(){const e=function(e){if(P.has(e.pathname))return{...e,pathname:P.get(e.pathname)};if((0,d.u)(u.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return P.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return P.set(e.pathname,t),{...e,pathname:t}}((0,p.zy)());return(0,f.jsx)(D,{location:e,children:W})}function q(){return(0,f.jsx)(U.A,{children:(0,f.jsx)(A.l,{children:(0,f.jsxs)(C.x,{children:[(0,f.jsxs)(m,{children:[(0,f.jsx)($,{}),(0,f.jsx)(j,{}),(0,f.jsx)(z,{}),(0,f.jsx)(Q,{})]}),(0,f.jsx)(V,{})]})})})}var G=n(84054);const K=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const o=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;o?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var Y=n(81604);const Z=new Set,X=new Set,J=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,ee={prefetch:e=>{if(!(e=>!J()&&!X.has(e)&&!Z.has(e))(e))return!1;Z.add(e);const t=(0,d.u)(u.A,e).flatMap((e=>{return t=e.route.path,Object.entries(G).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,Y.A)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?K(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!J()&&!X.has(e))(e)&&(X.add(e),L(e))},te=Object.freeze(ee);function ne(e){let{children:t}=e;return"hash"===s.A.future.experimental_router?(0,f.jsx)(i.I9,{children:t}):(0,f.jsx)(i.Kd,{children:t})}const re=Boolean(!0);if(c.A.canUseDOM){window.docusaurus=te;const e=document.getElementById("__docusaurus"),t=(0,f.jsx)(a.vd,{children:(0,f.jsx)(ne,{children:(0,f.jsx)(q,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},i=()=>{if(window.docusaurusRoot)window.docusaurusRoot.render(t);else if(re)window.docusaurusRoot=o.hydrateRoot(e,t,{onRecoverableError:n});else{const r=o.createRoot(e,{onRecoverableError:n});r.render(t),window.docusaurusRoot=r}};L(window.location.pathname).then((()=>{(0,r.startTransition)(i)}))}},53366:(e,t,n)=>{"use strict";n.d(t,{o:()=>p,l:()=>d});var r=n(96540),o=n(4784);const a=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/contrast/pr-preview/pr-1071/","versions":[{"name":"current","label":"Next","isLast":false,"path":"/contrast/pr-preview/pr-1071/next","mainDocId":"intro","docs":[{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/next/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/next/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/next/architecture/certificates","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/next/architecture/observability","sidebar":"docs"},{"id":"architecture/secrets","path":"/contrast/pr-preview/pr-1071/next/architecture/secrets","sidebar":"docs"},{"id":"architecture/security-considerations","path":"/contrast/pr-preview/pr-1071/next/architecture/security-considerations","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/next/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/next/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/next/basics/security-benefits","sidebar":"docs"},{"id":"components/overview","path":"/contrast/pr-preview/pr-1071/next/components/overview","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/next/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/next/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/next/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/next/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/next/examples/emojivoto","sidebar":"docs"},{"id":"examples/mysql","path":"/contrast/pr-preview/pr-1071/next/examples/mysql","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/next/features-limitations","sidebar":"docs"},{"id":"getting-started/bare-metal","path":"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/next/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/next/","sidebar":"docs"},{"id":"troubleshooting","path":"/contrast/pr-preview/pr-1071/next/troubleshooting","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/next/","label":"What is Contrast?"}}}},{"name":"1.2","label":"1.2","isLast":true,"path":"/contrast/pr-preview/pr-1071/","mainDocId":"intro","docs":[{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/architecture/certificates","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/architecture/observability","sidebar":"docs"},{"id":"architecture/secrets","path":"/contrast/pr-preview/pr-1071/architecture/secrets","sidebar":"docs"},{"id":"architecture/security-considerations","path":"/contrast/pr-preview/pr-1071/architecture/security-considerations","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/basics/security-benefits","sidebar":"docs"},{"id":"components/overview","path":"/contrast/pr-preview/pr-1071/components/overview","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/examples/emojivoto","sidebar":"docs"},{"id":"examples/mysql","path":"/contrast/pr-preview/pr-1071/examples/mysql","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/features-limitations","sidebar":"docs"},{"id":"getting-started/bare-metal","path":"/contrast/pr-preview/pr-1071/getting-started/bare-metal","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/","sidebar":"docs"},{"id":"troubleshooting","path":"/contrast/pr-preview/pr-1071/troubleshooting","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/","label":"What is Contrast?"}}}},{"name":"1.1","label":"1.1","isLast":false,"path":"/contrast/pr-preview/pr-1071/1.1","mainDocId":"intro","docs":[{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/1.1/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/1.1/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/1.1/architecture/certificates","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/1.1/architecture/observability","sidebar":"docs"},{"id":"architecture/secrets","path":"/contrast/pr-preview/pr-1071/1.1/architecture/secrets","sidebar":"docs"},{"id":"architecture/security-considerations","path":"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/1.1/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits","sidebar":"docs"},{"id":"components/overview","path":"/contrast/pr-preview/pr-1071/1.1/components/overview","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/1.1/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/1.1/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/1.1/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/1.1/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/1.1/features-limitations","sidebar":"docs"},{"id":"getting-started/bare-metal","path":"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/1.1/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/1.1/","sidebar":"docs"},{"id":"troubleshooting","path":"/contrast/pr-preview/pr-1071/1.1/troubleshooting","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/1.1/","label":"What is Contrast?"}}}},{"name":"1.0","label":"1.0","isLast":false,"path":"/contrast/pr-preview/pr-1071/1.0","mainDocId":"intro","docs":[{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/1.0/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/1.0/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/1.0/architecture/certificates","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/1.0/architecture/observability","sidebar":"docs"},{"id":"architecture/secrets","path":"/contrast/pr-preview/pr-1071/1.0/architecture/secrets","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/1.0/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits","sidebar":"docs"},{"id":"components/overview","path":"/contrast/pr-preview/pr-1071/1.0/components/overview","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/1.0/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/1.0/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/1.0/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/1.0/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/1.0/features-limitations","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/1.0/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/1.0/","sidebar":"docs"},{"id":"troubleshooting","path":"/contrast/pr-preview/pr-1071/1.0/troubleshooting","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/1.0/","label":"What is Contrast?"}}}},{"name":"0.9","label":"0.9","isLast":false,"path":"/contrast/pr-preview/pr-1071/0.9","mainDocId":"intro","docs":[{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/0.9/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/0.9/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/0.9/architecture/certificates","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/0.9/architecture/observability","sidebar":"docs"},{"id":"architecture/secrets","path":"/contrast/pr-preview/pr-1071/0.9/architecture/secrets","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/0.9/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits","sidebar":"docs"},{"id":"components/overview","path":"/contrast/pr-preview/pr-1071/0.9/components/overview","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/0.9/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/0.9/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/0.9/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/0.9/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/0.9/features-limitations","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/0.9/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/0.9/","sidebar":"docs"},{"id":"troubleshooting","path":"/contrast/pr-preview/pr-1071/0.9/troubleshooting","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/0.9/","label":"What is Contrast?"}}}},{"name":"0.8","label":"0.8","isLast":false,"path":"/contrast/pr-preview/pr-1071/0.8","mainDocId":"intro","docs":[{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/0.8/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/0.8/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/0.8/architecture/certificates","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/0.8/architecture/observability","sidebar":"docs"},{"id":"architecture/secrets","path":"/contrast/pr-preview/pr-1071/0.8/architecture/secrets","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/0.8/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits","sidebar":"docs"},{"id":"components/overview","path":"/contrast/pr-preview/pr-1071/0.8/components/overview","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/0.8/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/0.8/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/0.8/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/0.8/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/0.8/features-limitations","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/0.8/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/0.8/","sidebar":"docs"},{"id":"troubleshooting","path":"/contrast/pr-preview/pr-1071/0.8/troubleshooting","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/0.8/","label":"What is Contrast?"}}}},{"name":"0.7","label":"0.7","isLast":false,"path":"/contrast/pr-preview/pr-1071/0.7","mainDocId":"intro","docs":[{"id":"about/index","path":"/contrast/pr-preview/pr-1071/0.7/about/","sidebar":"docs"},{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/0.7/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/0.7/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/0.7/architecture/certificates","sidebar":"docs"},{"id":"architecture/index","path":"/contrast/pr-preview/pr-1071/0.7/architecture/","sidebar":"docs"},{"id":"architecture/observability","path":"/contrast/pr-preview/pr-1071/0.7/architecture/observability","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/0.7/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits","sidebar":"docs"},{"id":"components/index","path":"/contrast/pr-preview/pr-1071/0.7/components/","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/0.7/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/0.7/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/0.7/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/0.7/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto","sidebar":"docs"},{"id":"examples/index","path":"/contrast/pr-preview/pr-1071/0.7/examples/","sidebar":"docs"},{"id":"features-limitations","path":"/contrast/pr-preview/pr-1071/0.7/features-limitations","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/index","path":"/contrast/pr-preview/pr-1071/0.7/getting-started/","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/0.7/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/0.7/","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/0.7/","label":"What is Contrast?"}}}},{"name":"0.6","label":"0.6","isLast":false,"path":"/contrast/pr-preview/pr-1071/0.6","mainDocId":"intro","docs":[{"id":"about/index","path":"/contrast/pr-preview/pr-1071/0.6/about/","sidebar":"docs"},{"id":"about/telemetry","path":"/contrast/pr-preview/pr-1071/0.6/about/telemetry","sidebar":"docs"},{"id":"architecture/attestation","path":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation","sidebar":"docs"},{"id":"architecture/certificates","path":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates","sidebar":"docs"},{"id":"architecture/index","path":"/contrast/pr-preview/pr-1071/0.6/architecture/","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/0.6/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits","sidebar":"docs"},{"id":"components/index","path":"/contrast/pr-preview/pr-1071/0.6/components/","sidebar":"docs"},{"id":"components/policies","path":"/contrast/pr-preview/pr-1071/0.6/components/policies","sidebar":"docs"},{"id":"components/runtime","path":"/contrast/pr-preview/pr-1071/0.6/components/runtime","sidebar":"docs"},{"id":"components/service-mesh","path":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/0.6/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto","sidebar":"docs"},{"id":"examples/index","path":"/contrast/pr-preview/pr-1071/0.6/examples/","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/index","path":"/contrast/pr-preview/pr-1071/0.6/getting-started/","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/0.6/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/0.6/","sidebar":"docs"},{"id":"known-limitations","path":"/contrast/pr-preview/pr-1071/0.6/known-limitations","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/0.6/","label":"What is Contrast?"}}}},{"name":"0.5","label":"0.5","isLast":false,"path":"/contrast/pr-preview/pr-1071/0.5","mainDocId":"intro","docs":[{"id":"architecture/attestation/coordinator","path":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator","sidebar":"docs"},{"id":"architecture/attestation/hardware","path":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware","sidebar":"docs"},{"id":"architecture/attestation/manifest","path":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest","sidebar":"docs"},{"id":"architecture/attestation/pod-vm","path":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm","sidebar":"docs"},{"id":"architecture/attestation/runtime-policies","path":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies","sidebar":"docs"},{"id":"architecture/certificates-and-identities/pki","path":"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki","sidebar":"docs"},{"id":"architecture/components/cli","path":"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli","sidebar":"docs"},{"id":"architecture/components/coordinator","path":"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator","sidebar":"docs"},{"id":"architecture/components/init-container","path":"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container","sidebar":"docs"},{"id":"architecture/confidential-containers","path":"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers","sidebar":"docs"},{"id":"architecture/index","path":"/contrast/pr-preview/pr-1071/0.5/architecture/","sidebar":"docs"},{"id":"architecture/network-encryption/protocols-and-keys","path":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys","sidebar":"docs"},{"id":"architecture/network-encryption/sidecar","path":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar","sidebar":"docs"},{"id":"basics/confidential-containers","path":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers","sidebar":"docs"},{"id":"basics/features","path":"/contrast/pr-preview/pr-1071/0.5/basics/features","sidebar":"docs"},{"id":"basics/security-benefits","path":"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits","sidebar":"docs"},{"id":"deployment","path":"/contrast/pr-preview/pr-1071/0.5/deployment","sidebar":"docs"},{"id":"examples/emojivoto","path":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto","sidebar":"docs"},{"id":"examples/index","path":"/contrast/pr-preview/pr-1071/0.5/examples/","sidebar":"docs"},{"id":"getting-started/cluster-setup","path":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup","sidebar":"docs"},{"id":"getting-started/first-steps","path":"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps","sidebar":"docs"},{"id":"getting-started/index","path":"/contrast/pr-preview/pr-1071/0.5/getting-started/","sidebar":"docs"},{"id":"getting-started/install","path":"/contrast/pr-preview/pr-1071/0.5/getting-started/install","sidebar":"docs"},{"id":"intro","path":"/contrast/pr-preview/pr-1071/0.5/","sidebar":"docs"},{"id":"/category/components","path":"/contrast/pr-preview/pr-1071/0.5/category/components","sidebar":"docs"},{"id":"/category/attestation","path":"/contrast/pr-preview/pr-1071/0.5/category/attestation","sidebar":"docs"},{"id":"/category/certificates-and-identities","path":"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities","sidebar":"docs"},{"id":"/category/network-encryption","path":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/contrast/pr-preview/pr-1071/0.5/","label":"What is Contrast?"}}}}],"breadcrumbs":true}},"@cmfcmf/docusaurus-search-local":{"default":{"titleBoost":5,"contentBoost":1,"tagsBoost":3,"parentCategoriesBoost":2,"indexDocSidebarParentCategories":0,"maxSearchResults":8}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var s=n(22654);const c=JSON.parse('{"docusaurusVersion":"3.6.3","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"3.6.3"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.6.3"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.6.3"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.6.3"},"@cmfcmf/docusaurus-search-local":{"type":"package","name":"@cmfcmf/docusaurus-search-local","version":"1.2.0"},"docusaurus-theme-mermaid":{"type":"package","name":"@docusaurus/theme-mermaid","version":"3.6.3"}}}');var l=n(74848);const u={siteConfig:o.A,siteMetadata:c,globalData:a,i18n:i,codeTranslations:s},p=r.createContext(u);function d(e){let{children:t}=e;return(0,l.jsx)(p.Provider,{value:u,children:t})}},33832:(e,t,n)=>{"use strict";n.d(t,{A:()=>h});var r=n(96540),o=n(31712),a=n(21141),i=n(64609),s=n(53022),c=n(23363),l=n(74848);function u(e){let{error:t,tryAgain:n}=e;return(0,l.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,l.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,l.jsx)("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,l.jsx)(p,{error:t})]})}function p(e){let{error:t}=e;const n=(0,i.rA)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,l.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:n})}function d(e){let{children:t}=e;return(0,l.jsx)(c.W,{value:{plugin:{name:"docusaurus-core-error-boundary",id:"default"}},children:t})}function f(e){let{error:t,tryAgain:n}=e;return(0,l.jsx)(d,{children:(0,l.jsxs)(h,{fallback:()=>(0,l.jsx)(u,{error:t,tryAgain:n}),children:[(0,l.jsx)(a.A,{children:(0,l.jsx)("title",{children:"Page Error"})}),(0,l.jsx)(s.A,{children:(0,l.jsx)(u,{error:t,tryAgain:n})})]})})}const m=e=>(0,l.jsx)(f,{...e});class h extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){o.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??m)(e)}return e??null}}},31712:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,o={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},21141:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(96540);var r=n(80545),o=n(74848);function a(e){return(0,o.jsx)(r.mg,{...e})}},14783:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});var r=n(96540),o=n(54625),a=n(64609),i=n(97639),s=n(40877),c=n(31712),l=n(37344),u=n(98180),p=n(74848);function d(e,t){let{isNavLink:n,to:d,href:f,activeClassName:m,isActive:h,"data-noBrokenLinkCheck":v,autoAddBaseUrl:g=!0,...b}=e;const{siteConfig:y}=(0,i.A)(),{trailingSlash:w,baseUrl:_}=y,x=y.future.experimental_router,{withBaseUrl:S}=(0,u.hH)(),k=(0,l.A)(),E=(0,r.useRef)(null);(0,r.useImperativeHandle)(t,(()=>E.current));const O=d||f;const j=(0,s.A)(O),P=O?.replace("pathname://","");let C=void 0!==P?(A=P,g&&(e=>e.startsWith("/"))(A)?S(A):A):void 0;var A;"hash"===x&&C?.startsWith("./")&&(C=C?.slice(1)),C&&j&&(C=(0,a.Ks)(C,{trailingSlash:w,baseUrl:_}));const T=(0,r.useRef)(!1),I=n?o.k2:o.N_,N=c.A.canUseIntersectionObserver,L=(0,r.useRef)(),R=()=>{T.current||null==C||(window.docusaurus.preload(C),T.current=!0)};(0,r.useEffect)((()=>(!N&&j&&c.A.canUseDOM&&null!=C&&window.docusaurus.prefetch(C),()=>{N&&L.current&&L.current.disconnect()})),[L,C,N,j]);const D=C?.startsWith("#")??!1,F=!b.target||"_self"===b.target,M=!C||!j||!F||D&&"hash"!==x;v||!D&&M||k.collectLink(C),b.id&&k.collectAnchor(b.id);const B={};return M?(0,p.jsx)("a",{ref:E,href:C,...O&&!j&&{target:"_blank",rel:"noopener noreferrer"},...b,...B}):(0,p.jsx)(I,{...b,onMouseEnter:R,onTouchStart:R,innerRef:e=>{E.current=e,N&&e&&j&&(L.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(L.current.unobserve(e),L.current.disconnect(),null!=C&&window.docusaurus.prefetch(C))}))})),L.current.observe(e))},to:C,...n&&{isActive:h,activeClassName:m},...B})}const f=r.forwardRef(d)},23230:(e,t,n)=>{"use strict";n.d(t,{A:()=>l,T:()=>c});var r=n(96540),o=n(74848);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(22654);function s(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function c(e,t){let{message:n,id:r}=e;return a(s({message:n,id:r}),t)}function l(e){let{children:t,id:n,values:r}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const i=s({message:t,id:n});return(0,o.jsx)(o.Fragment,{children:a(i,r)})}},44598:(e,t,n)=>{"use strict";n.d(t,{W:()=>r});const r="default"},40877:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function o(e){return void 0!==e&&!r(e)}n.d(t,{A:()=>o,z:()=>r})},98180:(e,t,n)=>{"use strict";n.d(t,{Ay:()=>s,hH:()=>i});var r=n(96540),o=n(97639),a=n(40877);function i(){const{siteConfig:e}=(0,o.A)(),{baseUrl:t,url:n}=e,i=e.future.experimental_router,s=(0,r.useCallback)(((e,r)=>function(e){let{siteUrl:t,baseUrl:n,url:r,options:{forcePrependBaseUrl:o=!1,absolute:i=!1}={},router:s}=e;if(!r||r.startsWith("#")||(0,a.z)(r))return r;if("hash"===s)return r.startsWith("/")?`.${r}`:`./${r}`;if(o)return n+r.replace(/^\//,"");if(r===n.replace(/\/$/,""))return n;const c=r.startsWith(n)?r:n+r.replace(/^\//,"");return i?t+c:c}({siteUrl:n,baseUrl:t,url:e,options:r,router:i})),[n,t,i]);return{withBaseUrl:s}}function s(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},37344:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(96540);n(74848);const o=r.createContext({collectAnchor:()=>{},collectLink:()=>{}}),a=()=>(0,r.useContext)(o);function i(){return a()}},97639:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(96540),o=n(53366);function a(){return(0,r.useContext)(o.o)}},26503:(e,t,n)=>{"use strict";n.d(t,{P_:()=>i,kh:()=>a});var r=n(97639),o=n(44598);function a(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,r.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}function i(e,t,n){void 0===t&&(t=o.W),void 0===n&&(n={});const r=a(e),i=r?.[t];if(!i&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return i}},11062:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(96540),o=n(48848);function a(){return(0,r.useContext)(o.o)}},36494:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=n(96540);const o=n(31712).A.canUseDOM?r.useLayoutEffect:r.useEffect},81604:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function o(e){const t={};return function e(n,o){Object.entries(n).forEach((n=>{let[a,i]=n;const s=o?`${o}.${a}`:a;r(i)?e(i,s):t[s]=i}))}(e),t}},23363:(e,t,n)=>{"use strict";n.d(t,{W:()=>i,o:()=>a});var r=n(96540),o=n(74848);const a=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(a),s=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return(0,o.jsx)(a.Provider,{value:s,children:t})}},86457:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>v,XK:()=>y,g1:()=>b});var r=n(96540),o=n(19802),a=n(44598),i=n(86957),s=n(69900),c=n(4799),l=n(74848);const u=e=>`docs-preferred-version-${e}`,p={save:(e,t,n)=>{(0,s.Wf)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,s.Wf)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,s.Wf)(u(e),{persistence:t}).del()}},d=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const f=r.createContext(null);function m(){const e=(0,o.Gy)(),t=(0,i.p)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[a,s]=(0,r.useState)((()=>d(n)));(0,r.useEffect)((()=>{s(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function o(e){const t=p.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(p.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,o(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[a,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){p.save(e,t,n),s((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function h(e){let{children:t}=e;const n=m();return(0,l.jsx)(f.Provider,{value:n,children:t})}function v(e){let{children:t}=e;return(0,l.jsx)(h,{children:t})}function g(){const e=(0,r.useContext)(f);if(!e)throw new c.dV("DocsPreferredVersionContextProvider");return e}function b(e){void 0===e&&(e=a.W);const t=(0,o.ht)(e),[n,i]=g(),{preferredVersionName:s}=n[e];return{preferredVersion:t.versions.find((e=>e.name===s))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}function y(){const e=(0,o.Gy)(),[t]=g();function n(n){const r=e[n],{preferredVersionName:o}=t[n];return r.versions.find((e=>e.name===o))??null}const r=Object.keys(e);return Object.fromEntries(r.map((e=>[e,n(e)])))}},73718:(e,t,n)=>{"use strict";n.d(t,{k:()=>a,v:()=>i});var r=n(19802),o=n(86457);function a(e,t){return`docs-${e}-${t}`}function i(){const e=(0,r.Gy)(),t=(0,r.gk)(),n=(0,o.XK)();return[...Object.keys(e).map((function(r){const o=t?.activePlugin.pluginId===r?t.activeVersion:void 0,i=n[r],s=e[r].versions.find((e=>e.isLast));return a(r,(o??i??s).name)}))]}},20040:(e,t,n)=>{"use strict";n.d(t,{V:()=>c,t:()=>l});var r=n(96540),o=n(4799),a=n(74848);const i=Symbol("EmptyContext"),s=r.createContext(i);function c(e){let{children:t,name:n,items:o}=e;const i=(0,r.useMemo)((()=>n&&o?{name:n,items:o}:null),[n,o]);return(0,a.jsx)(s.Provider,{value:i,children:t})}function l(){const e=(0,r.useContext)(s);if(e===i)throw new o.dV("DocsSidebarProvider");return e}},45357:(e,t,n)=>{"use strict";n.d(t,{$S:()=>m,B5:()=>E,Nr:()=>f,OF:()=>_,QB:()=>k,Vd:()=>x,Y:()=>y,cC:()=>d,d1:()=>O,fW:()=>S,w8:()=>g});var r=n(96540),o=n(56347),a=n(22831),i=n(19802),s=n(80260),c=n(45167),l=n(86457),u=n(91704),p=n(20040);function d(e){const t=(0,u.r)();if(!e)return;const n=t.docs[e];if(!n)throw new Error(`no version doc found by id=${e}`);return n}function f(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=f(t);if(e)return e}}(e):void 0:e.href}function m(){const{pathname:e}=(0,o.zy)(),t=(0,p.t)();if(!t)throw new Error("Unexpected: cant find current sidebar in context");const n=w({sidebarItems:t.items,pathname:e,onlyCategories:!0}).slice(-1)[0];if(!n)throw new Error(`${e} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`);return n}const h=(e,t)=>void 0!==e&&(0,s.ys)(e,t),v=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?h(e.href,t):"category"===e.type&&(h(e.href,t)||v(e.items,t))}function b(e,t){switch(e.type){case"category":return g(e,t)||e.items.some((e=>b(e,t)));case"link":return!e.unlisted||g(e,t);default:return!0}}function y(e,t){return(0,r.useMemo)((()=>e.filter((e=>b(e,t)))),[e,t])}function w(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const o=[];return function e(t){for(const a of t)if("category"===a.type&&((0,s.ys)(a.href,n)||e(a.items))||"link"===a.type&&(0,s.ys)(a.href,n)){return r&&"category"!==a.type||o.unshift(a),!0}return!1}(t),o}function _(){const e=(0,p.t)(),{pathname:t}=(0,o.zy)(),n=(0,i.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?w({sidebarItems:e.items,pathname:t}):null}function x(e){const{activeVersion:t}=(0,i.zK)(e),{preferredVersion:n}=(0,l.g1)(e),o=(0,i.r7)(e);return(0,r.useMemo)((()=>(0,c.sb)([t,n,o].filter(Boolean))),[t,n,o])}function S(e,t){const n=x(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function k(e,t){const n=x(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${(0,c.sb)(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function E(e){let{route:t}=e;const n=(0,o.zy)(),r=(0,u.r)(),i=t.routes,s=i.find((e=>(0,o.B6)(n.pathname,e)));if(!s)return null;const c=s.sidebar,l=c?r.docsSidebars[c]:void 0;return{docElement:(0,a.v)(i),sidebarName:c,sidebarItems:l}}function O(e){return e.filter((e=>!("category"===e.type||"link"===e.type)||!!f(e)))}},91704:(e,t,n)=>{"use strict";n.d(t,{n:()=>s,r:()=>c});var r=n(96540),o=n(4799),a=n(74848);const i=r.createContext(null);function s(e){let{children:t,version:n}=e;return(0,a.jsx)(i.Provider,{value:n,children:t})}function c(){const e=(0,r.useContext)(i);if(null===e)throw new o.dV("DocsVersionProvider");return e}},19802:(e,t,n)=>{"use strict";n.d(t,{d1:()=>c.d1,zK:()=>b,vT:()=>m,gk:()=>h,Gy:()=>d,$S:()=>c.$S,HW:()=>y,vF:()=>u.v,ht:()=>f,g1:()=>l.g1,r7:()=>g,jh:()=>v});var r=n(56347),o=n(26503);const a=e=>e.versions.find((e=>e.isLast));function i(e,t){return[...e.versions].sort(((e,t)=>e.path===t.path?0:e.path.includes(t.path)?-1:t.path.includes(e.path)?1:0)).find((e=>!!(0,r.B6)(t,{path:e.path,exact:!1,strict:!1})))}function s(e,t){const n=i(e,t),o=n?.docs.find((e=>!!(0,r.B6)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:o,alternateDocVersions:o?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(o.id):{}}}var c=n(45357),l=n(86457),u=n(73718);const p={},d=()=>(0,o.kh)("docusaurus-plugin-content-docs")??p,f=e=>{try{return(0,o.P_)("docusaurus-plugin-content-docs",e,{failfast:!0})}catch(t){throw new Error("You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled"+("Default"===e?"":` (pluginId=${e}`),{cause:t})}};function m(e){void 0===e&&(e={});const t=d(),{pathname:n}=(0,r.zy)();return function(e,t,n){void 0===n&&(n={});const o=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.B6)(t,{path:n.path,exact:!1,strict:!1})})),a=o?{pluginId:o[0],pluginData:o[1]}:void 0;if(!a&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return a}(t,n,e)}function h(e){void 0===e&&(e={});const t=m(e),{pathname:n}=(0,r.zy)();if(!t)return;return{activePlugin:t,activeVersion:i(t.pluginData,n)}}function v(e){return f(e).versions}function g(e){const t=f(e);return a(t)}function b(e){const t=f(e),{pathname:n}=(0,r.zy)();return s(t,n)}function y(e){const t=f(e),{pathname:n}=(0,r.zy)();return function(e,t){const n=a(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},75729:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>a});var r=n(5947),o=n.n(r);o().configure({showSpinner:!1});const a={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{o().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){o().done()}}},74753:(e,t,n)=>{"use strict";var r=n(71765),o=n(4784);!function(e){const{themeConfig:{prism:t}}=o.A,{additionalLanguages:r}=t,a=globalThis.Prism;globalThis.Prism=e,r.forEach((e=>{"php"===e&&n(19700),n(97553)(`./prism-${e}`)})),delete globalThis.Prism,void 0!==a&&(globalThis.Prism=e)}(r.My)},85225:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});n(96540);var r=n(34164),o=n(23230),a=n(86957),i=n(14783),s=n(37344);const c={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var l=n(74848);function u(e){let{as:t,id:n,...u}=e;const p=(0,s.A)(),{navbar:{hideOnScroll:d}}=(0,a.p)();if("h1"===t||!n)return(0,l.jsx)(t,{...u,id:void 0});p.collectAnchor(n);const f=(0,o.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof u.children?u.children:n});return(0,l.jsxs)(t,{...u,className:(0,r.A)("anchor",d?c.anchorWithHideOnScrollNavbar:c.anchorWithStickyNavbar,u.className),id:n,children:[u.children,(0,l.jsx)(i.A,{className:"hash-link",to:`#${n}`,"aria-label":f,title:f,children:"\u200b"})]})}},90716:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(96540);const r={iconExternalLink:"iconExternalLink_nPIU"};var o=n(74848);function a(e){let{width:t=13.5,height:n=13.5}=e;return(0,o.jsx)("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:r.iconExternalLink,children:(0,o.jsx)("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"})})}},53022:(e,t,n)=>{"use strict";n.d(t,{A:()=>ai});var r=n(96540),o=n(34164),a=n(33832),i=n(69817),s=n(56347),c=n(23230),l=n(54067),u=n(74848);const p="__docusaurus_skipToContent_fallback";function d(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,s.W6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(p);t&&d(t)}),[]);return(0,l.$)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&d(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:r}=f();return(0,u.jsx)("div",{ref:n,role:"region","aria-label":m,children:(0,u.jsx)("a",{...e,href:`#${p}`,onClick:r,children:t})})}var v=n(18630),g=n(19503);const b={skipToContent:"skipToContent_fXgn"};function y(){return(0,u.jsx)(h,{className:b.skipToContent})}var w=n(86957),_=n(40002);function x(e){let{width:t=21,height:n=21,color:r="currentColor",strokeWidth:o=1.2,className:a,...i}=e;return(0,u.jsx)("svg",{viewBox:"0 0 15 15",width:t,height:n,...i,children:(0,u.jsx)("g",{stroke:r,strokeWidth:o,children:(0,u.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const S={closeButton:"closeButton_CVFx"};function k(e){return(0,u.jsx)("button",{type:"button","aria-label":(0,c.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,o.A)("clean-btn close",S.closeButton,e.className),children:(0,u.jsx)(x,{width:14,height:14,strokeWidth:3.1})})}const E={content:"content_knG7"};function O(e){const{announcementBar:t}=(0,w.p)(),{content:n}=t;return(0,u.jsx)("div",{...e,className:(0,o.A)(E.content,e.className),dangerouslySetInnerHTML:{__html:n}})}const j={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function P(){const{announcementBar:e}=(0,w.p)(),{isActive:t,close:n}=(0,_.M)();if(!t)return null;const{backgroundColor:r,textColor:o,isCloseable:a}=e;return(0,u.jsxs)("div",{className:j.announcementBar,style:{backgroundColor:r,color:o},role:"banner",children:[a&&(0,u.jsx)("div",{className:j.announcementBarPlaceholder}),(0,u.jsx)(O,{className:j.announcementBarContent}),a&&(0,u.jsx)(k,{onClick:n,className:j.announcementBarClose})]})}var C=n(61938),A=n(24245);var T=n(4799),I=n(70763);const N=r.createContext(null);function L(e){let{children:t}=e;const n=function(){const e=(0,C.M)(),t=(0,I.YL)(),[n,o]=(0,r.useState)(!1),a=null!==t.component,i=(0,T.ZC)(a);return(0,r.useEffect)((()=>{a&&!i&&o(!0)}),[a,i]),(0,r.useEffect)((()=>{a?e.shown||o(!0):o(!1)}),[e.shown,a]),(0,r.useMemo)((()=>[n,o]),[n])}();return(0,u.jsx)(N.Provider,{value:n,children:t})}function R(e){if(e.component){const t=e.component;return(0,u.jsx)(t,{...e.props})}}function D(){const e=(0,r.useContext)(N);if(!e)throw new T.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,o=(0,r.useCallback)((()=>n(!1)),[n]),a=(0,I.YL)();return(0,r.useMemo)((()=>({shown:t,hide:o,content:R(a)})),[o,a,t])}function F(e){let{header:t,primaryMenu:n,secondaryMenu:r}=e;const{shown:a}=D();return(0,u.jsxs)("div",{className:"navbar-sidebar",children:[t,(0,u.jsxs)("div",{className:(0,o.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":a}),children:[(0,u.jsx)("div",{className:"navbar-sidebar__item menu",children:n}),(0,u.jsx)("div",{className:"navbar-sidebar__item menu",children:r})]})]})}var M=n(7710),B=n(11062);function z(e){return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,u.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function $(e){return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,u.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}const U={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function H(e){let{className:t,buttonClassName:n,value:r,onChange:a}=e;const i=(0,B.A)(),s=(0,c.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===r?(0,c.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return(0,u.jsx)("div",{className:(0,o.A)(U.toggle,t),children:(0,u.jsxs)("button",{className:(0,o.A)("clean-btn",U.toggleButton,!i&&U.toggleButtonDisabled,n),type:"button",onClick:()=>a("dark"===r?"light":"dark"),disabled:!i,title:s,"aria-label":s,"aria-live":"polite","aria-pressed":"dark"===r?"true":"false",children:[(0,u.jsx)(z,{className:(0,o.A)(U.toggleIcon,U.lightToggleIcon)}),(0,u.jsx)($,{className:(0,o.A)(U.toggleIcon,U.darkToggleIcon)})]})})}const V=r.memo(H),W={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function Q(e){let{className:t}=e;const n=(0,w.p)().navbar.style,r=(0,w.p)().colorMode.disableSwitch,{colorMode:o,setColorMode:a}=(0,M.G)();return r?null:(0,u.jsx)(V,{className:t,buttonClassName:"dark"===n?W.darkNavbarColorModeToggle:void 0,value:o,onChange:a})}var q=n(20020);function G(){return(0,u.jsx)(q.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,C.M)();return(0,u.jsx)("button",{type:"button","aria-label":(0,c.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,u.jsx)(x,{color:"var(--ifm-color-emphasis-600)"})})}function Y(){return(0,u.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,u.jsx)(G,{}),(0,u.jsx)(Q,{className:"margin-right--md"}),(0,u.jsx)(K,{})]})}var Z=n(14783),X=n(98180),J=n(40877);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(90716);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:r,href:o,label:a,html:i,isDropdownLink:s,prependBaseUrlToHref:c,...l}=e;const p=(0,X.Ay)(r),d=(0,X.Ay)(t),f=(0,X.Ay)(o,{forcePrependBaseUrl:!0}),m=a&&o&&!(0,J.A)(o),h=i?{dangerouslySetInnerHTML:{__html:i}}:{children:(0,u.jsxs)(u.Fragment,{children:[a,m&&(0,u.jsx)(te.A,{...s&&{width:12,height:12}})]})};return o?(0,u.jsx)(Z.A,{href:c?f:o,...l,...h}):(0,u.jsx)(Z.A,{to:p,isNavLink:!0,...(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(d)},...l,...h})}function re(e){let{className:t,isDropdownItem:n=!1,...r}=e;const a=(0,u.jsx)(ne,{className:(0,o.A)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n,...r});return n?(0,u.jsx)("li",{children:a}):a}function oe(e){let{className:t,isDropdownItem:n,...r}=e;return(0,u.jsx)("li",{className:"menu__list-item",children:(0,u.jsx)(ne,{className:(0,o.A)("menu__link",t),...r})})}function ae(e){let{mobile:t=!1,position:n,...r}=e;const o=t?oe:re;return(0,u.jsx)(o,{...r,activeClassName:r.activeClassName??(t?"menu__link--active":"navbar__link--active")})}var ie=n(94549),se=n(80260),ce=n(97639);const le="dropdownNavbarItemMobile_S0Fm";function ue(e,t){return e.some((e=>function(e,t){return!!(0,se.ys)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function pe(e){let{items:t,position:n,className:a,onClick:i,...s}=e;const c=(0,r.useRef)(null),[l,p]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&p(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[c]),(0,u.jsxs)("div",{ref:c,className:(0,o.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":l}),children:[(0,u.jsx)(ne,{"aria-haspopup":"true","aria-expanded":l,role:"button",href:s.to?void 0:"#",className:(0,o.A)("navbar__link",a),...s,onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),p(!l))},children:s.children??s.label}),(0,u.jsx)("ul",{className:"dropdown__menu",children:t.map(((e,t)=>(0,r.createElement)(_a,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t})))})]})}function de(e){let{items:t,className:n,position:a,onClick:i,...c}=e;const l=function(){const{siteConfig:{baseUrl:e}}=(0,ce.A)(),{pathname:t}=(0,s.zy)();return t.replace(e,"/")}(),p=ue(t,l),{collapsed:d,toggleCollapsed:f,setCollapsed:m}=(0,ie.u)({initialState:()=>!p});return(0,r.useEffect)((()=>{p&&m(!p)}),[l,p,m]),(0,u.jsxs)("li",{className:(0,o.A)("menu__list-item",{"menu__list-item--collapsed":d}),children:[(0,u.jsx)(ne,{role:"button",className:(0,o.A)(le,"menu__link menu__link--sublist menu__link--sublist-caret",n),...c,onClick:e=>{e.preventDefault(),f()},children:c.children??c.label}),(0,u.jsx)(ie.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:d,children:t.map(((e,t)=>(0,r.createElement)(_a,{mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active",...e,key:t})))})]})}function fe(e){let{mobile:t=!1,...n}=e;const r=t?de:pe;return(0,u.jsx)(r,{...n})}var me=n(2098);function he(e){let{width:t=20,height:n=20,...r}=e;return(0,u.jsx)("svg",{viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0,...r,children:(0,u.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const ve="iconLanguage_nlXk";var ge=n(40961);function be(e,t){var n=void 0;return function(){for(var r=arguments.length,o=new Array(r),a=0;a<r;a++)o[a]=arguments[a];n&&clearTimeout(n),n=setTimeout((function(){return e.apply(void 0,o)}),t)}}function ye(e){return{current:e}}function we(e){return e!==Object(e)}function _e(e,t){if(e===t)return!0;if(we(e)||we(t)||"function"==typeof e||"function"==typeof t)return e===t;if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n=0,r=Object.keys(e);n<r.length;n++){var o=r[n];if(!(o in t))return!1;if(!_e(e[o],t[o]))return!1}return!0}var xe=function(){};function Se(e){var t=e.item,n=e.items,r=void 0===n?[]:n;return{index:t.__autocomplete_indexName,items:[t],positions:[1+r.findIndex((function(e){return e.objectID===t.objectID}))],queryID:t.__autocomplete_queryID,algoliaSource:["autocomplete"]}}function ke(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,a,i,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;c=!1}else for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(u){l=!0,o=u}finally{try{if(!c&&null!=n.return&&(i=n.return(),Object(i)!==i))return}finally{if(l)throw o}}return s}}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Ee(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Ee(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Ee(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}var Oe=["items"],je=["items"];function Pe(e){return Pe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Pe(e)}function Ce(e){return function(e){if(Array.isArray(e))return Ae(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Ae(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Ae(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Ae(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function Te(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function Ie(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ne(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Ie(Object(n),!0).forEach((function(t){Le(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Ie(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Le(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Pe(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Pe(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Pe(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Re(e){return e.map((function(e){var t=e.items,n=Te(e,Oe);return Ne(Ne({},n),{},{objectIDs:(null==t?void 0:t.map((function(e){return e.objectID})))||n.objectIDs})}))}function De(e){var t=function(e){var t=ke((e.version||"").split(".").map(Number),2),n=t[0],r=t[1];return n>=3||2===n&&r>=4||1===n&&r>=10}(e);function n(n,r,o){if(t&&void 0!==o){var a=o[0].__autocomplete_algoliaCredentials,i={"X-Algolia-Application-Id":a.appId,"X-Algolia-API-Key":a.apiKey};e.apply(void 0,[n].concat(Ce(r),[{headers:i}]))}else e.apply(void 0,[n].concat(Ce(r)))}return{init:function(t,n){e("init",{appId:t,apiKey:n})},setAuthenticatedUserToken:function(t){e("setAuthenticatedUserToken",t)},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&n("clickedObjectIDsAfterSearch",Re(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&n("clickedObjectIDs",Re(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];n.length>0&&e.apply(void 0,["clickedFilters"].concat(n))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&n("convertedObjectIDsAfterSearch",Re(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&n("convertedObjectIDs",Re(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];n.length>0&&e.apply(void 0,["convertedFilters"].concat(n))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&t.reduce((function(e,t){var n=t.items,r=Te(t,je);return[].concat(Ce(e),Ce(function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,n=[],r=0;r<e.objectIDs.length;r+=t)n.push(Ne(Ne({},e),{},{objectIDs:e.objectIDs.slice(r,r+t)}));return n}(Ne(Ne({},r),{},{objectIDs:(null==n?void 0:n.map((function(e){return e.objectID})))||r.objectIDs})).map((function(e){return{items:n,payload:e}}))))}),[]).forEach((function(e){var t=e.items;return n("viewedObjectIDs",[e.payload],t)}))},viewedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];n.length>0&&e.apply(void 0,["viewedFilters"].concat(n))}}}function Fe(e){var t=e.items.reduce((function(e,t){var n;return e[t.__autocomplete_indexName]=(null!==(n=e[t.__autocomplete_indexName])&&void 0!==n?n:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function Me(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function Be(e){return Be="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Be(e)}function ze(e){return function(e){if(Array.isArray(e))return $e(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return $e(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return $e(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function $e(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function Ue(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function He(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Ue(Object(n),!0).forEach((function(t){Ve(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Ue(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Ve(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Be(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Be(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Be(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var We="2.15.0",Qe="https://cdn.jsdelivr.net/npm/search-insights@".concat(We,"/dist/search-insights.min.js"),qe=be((function(e){var t=e.onItemsChange,n=e.items,r=e.insights,o=e.state;t({insights:r,insightsEvents:Fe({items:n}).map((function(e){return He({eventName:"Items Viewed"},e)})),state:o})}),400);function Ge(e){var t=function(e){return He({onItemsChange:function(e){var t=e.insights,n=e.insightsEvents,r=e.state;t.viewedObjectIDs.apply(t,ze(n.map((function(e){return He(He({},e),{},{algoliaSource:Ke(e.algoliaSource,r.context)})}))))},onSelect:function(e){var t=e.insights,n=e.insightsEvents,r=e.state;t.clickedObjectIDsAfterSearch.apply(t,ze(n.map((function(e){return He(He({},e),{},{algoliaSource:Ke(e.algoliaSource,r.context)})}))))},onActive:xe,__autocomplete_clickAnalytics:!0},e)}(e),n=t.insightsClient,r=t.insightsInitParams,o=t.onItemsChange,a=t.onSelect,i=t.onActive,s=t.__autocomplete_clickAnalytics,c=n;if(n||function(e){if("undefined"!=typeof window)e({window:window})}((function(e){var t=e.window,n=t.AlgoliaAnalyticsObject||"aa";"string"==typeof n&&(c=t[n]),c||(t.AlgoliaAnalyticsObject=n,t[n]||(t[n]=function(){t[n].queue||(t[n].queue=[]);for(var e=arguments.length,r=new Array(e),o=0;o<e;o++)r[o]=arguments[o];t[n].queue.push(r)}),t[n].version=We,c=t[n],function(e){var t="[Autocomplete]: Could not load search-insights.js. Please load it manually following https://alg.li/insights-autocomplete";try{var n=e.document.createElement("script");n.async=!0,n.src=Qe,n.onerror=function(){console.error(t)},document.body.appendChild(n)}catch(r){console.error(t)}}(t))})),!c)return{};r&&c("init",He({partial:!0},r));var l=De(c),u=ye([]),p=be((function(e){var t=e.state;if(t.isOpen){var n=t.collections.reduce((function(e,t){return[].concat(ze(e),ze(t.items))}),[]).filter(Me);_e(u.current.map((function(e){return e.objectID})),n.map((function(e){return e.objectID})))||(u.current=n,n.length>0&&qe({onItemsChange:o,items:n,insights:l,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,n=e.onSelect,r=e.onActive,o=!1;function u(e){t({algoliaInsightsPlugin:{__algoliaSearchParameters:He(He({},s?{clickAnalytics:!0}:{}),e?{userToken:Ye(e)}:{}),insights:l}})}c("addAlgoliaAgent","insights-plugin"),u(),c("onUserTokenChange",(function(e){o||u(e)})),c("getUserToken",null,(function(e,t){o||u(t)})),c("onAuthenticatedUserTokenChange",(function(e){e?(o=!0,u(e)):(o=!1,c("getUserToken",null,(function(e,t){return u(t)})))})),c("getAuthenticatedUserToken",null,(function(e,t){t&&(o=!0,u(t))})),n((function(e){var t=e.item,n=e.state,r=e.event,o=e.source;Me(t)&&a({state:n,event:r,insights:l,item:t,insightsEvents:[He({eventName:"Item Selected"},Se({item:t,items:o.getItems().filter(Me)}))]})})),r((function(e){var t=e.item,n=e.source,r=e.state,o=e.event;Me(t)&&i({state:r,event:o,insights:l,item:t,insightsEvents:[He({eventName:"Item Active"},Se({item:t,items:n.getItems().filter(Me)}))]})}))},onStateChange:function(e){var t=e.state;p({state:t})},__autocomplete_pluginOptions:e}}function Ke(){var e,t=arguments.length>1?arguments[1]:void 0;return[].concat(ze(arguments.length>0&&void 0!==arguments[0]?arguments[0]:[]),["autocomplete-internal"],ze(null!==(e=t.algoliaInsightsPlugin)&&void 0!==e&&e.__automaticInsights?["autocomplete-automatic"]:[]))}function Ye(e){return"number"==typeof e?e.toString():e}function Ze(e){return Ze="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ze(e)}function Xe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Je(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Ze(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Ze(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Ze(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function et(e,t,n){var r,o=t.initialState;return{getState:function(){return o},dispatch:function(r,a){var i=function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Xe(Object(n),!0).forEach((function(t){Je(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Xe(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}({},o);o=e(o,{type:r,props:t,payload:a}),n({state:o,prevState:i})},pendingRequests:(r=[],{add:function(e){return r.push(e),e.finally((function(){r=r.filter((function(t){return t!==e}))}))},cancelAll:function(){r.forEach((function(e){return e.cancel()}))},isEmpty:function(){return 0===r.length}})}}function tt(e){return e.reduce((function(e,t){return e.concat(t)}),[])}function nt(e){return nt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},nt(e)}function rt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ot(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?rt(Object(n),!0).forEach((function(t){at(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):rt(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function at(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==nt(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==nt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===nt(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function it(e){return 0===e.collections.length?0:e.collections.reduce((function(e,t){return e+t.items.length}),0)}var st=0;function ct(){return"autocomplete-".concat(st++)}function lt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ut(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?lt(Object(n),!0).forEach((function(t){pt(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):lt(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function pt(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==dt(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==dt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===dt(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function dt(e){return dt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},dt(e)}function ft(e){return ft="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},ft(e)}function mt(e){return function(e){if(Array.isArray(e))return ht(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return ht(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ht(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ht(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function vt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function gt(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?vt(Object(n),!0).forEach((function(t){bt(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):vt(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function bt(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==ft(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==ft(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ft(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function yt(e,t){var n,r="undefined"!=typeof window?window:{},o=e.plugins||[];return gt(gt({debug:!1,openOnFocus:!1,enterKeyHint:void 0,ignoreCompositionEvents:!1,placeholder:"",autoFocus:!1,defaultActiveItemId:null,stallThreshold:300,insights:void 0,environment:r,shouldPanelOpen:function(e){return it(e.state)>0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:ct(),plugins:o,initialState:gt({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(mt(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Array.isArray(e),Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:xe,onResolve:xe};Object.keys(t).forEach((function(e){t[e].__default=!0}));var r=ut(ut({},t),e);return Promise.resolve(r)})))}))}(e,n)}))).then((function(e){return tt(e)})).then((function(e){return e.map((function(e){return gt(gt({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))},onResolve:function(n){e.onResolve(n),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:gt({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}function wt(e){return wt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},wt(e)}function _t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function xt(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?_t(Object(n),!0).forEach((function(t){St(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):_t(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function St(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==wt(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==wt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===wt(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kt(e){return kt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},kt(e)}function Et(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ot(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Et(Object(n),!0).forEach((function(t){jt(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Et(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function jt(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==kt(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==kt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===kt(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Pt(e){return function(e){if(Array.isArray(e))return Ct(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Ct(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Ct(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Ct(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function At(e){return Boolean(e.execute)}function Tt(e,t,n){if(o=e,Boolean(null==o?void 0:o.execute)){var r="algolia"===e.requesterId?Object.assign.apply(Object,[{}].concat(Pt(Object.keys(n.context).map((function(e){var t;return null===(t=n.context[e])||void 0===t?void 0:t.__algoliaSearchParameters}))))):{};return Ot(Ot({},e),{},{requests:e.queries.map((function(n){return{query:"algolia"===e.requesterId?Ot(Ot({},n),{},{params:Ot(Ot({},r),n.params)}):n,sourceId:t,transformResponse:e.transformResponse}}))})}var o;return{items:e,sourceId:t}}function It(e){var t=e.reduce((function(e,t){if(!At(t))return e.push(t),e;var n=t.searchClient,r=t.execute,o=t.requesterId,a=t.requests,i=e.find((function(e){return At(t)&&At(e)&&e.searchClient===n&&Boolean(o)&&e.requesterId===o}));if(i){var s;(s=i.items).push.apply(s,Pt(a))}else{var c={execute:r,requesterId:o,items:a,searchClient:n};e.push(c)}return e}),[]).map((function(e){if(!At(e))return Promise.resolve(e);var t=e,n=t.execute,r=t.items;return n({searchClient:t.searchClient,requests:r})}));return Promise.all(t).then((function(e){return tt(e)}))}function Nt(e,t,n){return t.map((function(t){var r,o=e.filter((function(e){return e.sourceId===t.sourceId})),a=o.map((function(e){return e.items})),i=o[0].transformResponse,s=i?i({results:r=a,hits:r.map((function(e){return e.hits})).filter(Boolean),facetHits:r.map((function(e){var t;return null===(t=e.facetHits)||void 0===t?void 0:t.map((function(e){return{label:e.value,count:e.count,_highlightResult:{label:{value:e.highlighted}}}}))})).filter(Boolean)}):a;return t.onResolve({source:t,results:a,items:s,state:n.getState()}),Array.isArray(s),s.every(Boolean),'The `getItems` function from source "'.concat(t.sourceId,'" must return an array of items but returned ').concat(JSON.stringify(void 0),".\n\nDid you forget to return items?\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems"),{source:t,items:s}}))}function Lt(e,t){var n=t;return{then:function(t,r){return Lt(e.then(Ft(t,n,e),Ft(r,n,e)),n)},catch:function(t){return Lt(e.catch(Ft(t,n,e)),n)},finally:function(t){return t&&n.onCancelList.push(t),Lt(e.finally(Ft(t&&function(){return n.onCancelList=[],t()},n,e)),n)},cancel:function(){n.isCanceled=!0;var e=n.onCancelList;n.onCancelList=[],e.forEach((function(e){e()}))},isCanceled:function(){return!0===n.isCanceled}}}function Rt(e){return Lt(new Promise((function(t,n){return e(t,n)})),{isCanceled:!1,onCancelList:[]})}function Dt(e){return Lt(e,{isCanceled:!1,onCancelList:[]})}function Ft(e,t,n){return e?function(n){return t.isCanceled?n:e(n)}:n}function Mt(e){var t=function(e){var t=e.collections.map((function(e){return e.items.length})).reduce((function(e,t,n){var r=(e[n-1]||0)+t;return e.push(r),e}),[]).reduce((function(t,n){return n<=e.activeItemId?t+1:t}),0);return e.collections[t]}(e);if(!t)return null;var n=t.items[function(e){for(var t=e.state,n=e.collection,r=!1,o=0,a=0;!1===r;){var i=t.collections[o];if(i===n){r=!0;break}a+=i.items.length,o++}return t.activeItemId-a}({state:e,collection:t})],r=t.source;return{item:n,itemInputValue:r.getItemInputValue({item:n,state:e}),itemUrl:r.getItemUrl({item:n,state:e}),source:r}}function Bt(e){return Bt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Bt(e)}Rt.resolve=function(e){return Dt(Promise.resolve(e))},Rt.reject=function(e){return Dt(Promise.reject(e))};var zt=["event","nextState","props","query","refresh","store"];function $t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ut(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?$t(Object(n),!0).forEach((function(t){Ht(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):$t(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Ht(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Bt(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Bt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Bt(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Vt(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var Wt,Qt,qt,Gt=null,Kt=(Wt=-1,Qt=-1,qt=void 0,function(e){var t=++Wt;return Promise.resolve(e).then((function(e){return qt&&t<Qt?qt:(Qt=t,qt=e,e)}))});function Yt(e){var t=e.event,n=e.nextState,r=void 0===n?{}:n,o=e.props,a=e.query,i=e.refresh,s=e.store,c=Vt(e,zt);Gt&&o.environment.clearTimeout(Gt);var l=c.setCollections,u=c.setIsOpen,p=c.setQuery,d=c.setActiveItemId,f=c.setStatus,m=c.setContext;if(p(a),d(o.defaultActiveItemId),!a&&!1===o.openOnFocus){var h,v=s.getState().collections.map((function(e){return Ut(Ut({},e),{},{items:[]})}));f("idle"),l(v),u(null!==(h=r.isOpen)&&void 0!==h?h:o.shouldPanelOpen({state:s.getState()}));var g=Dt(Kt(v).then((function(){return Promise.resolve()})));return s.pendingRequests.add(g)}f("loading"),Gt=o.environment.setTimeout((function(){f("stalled")}),o.stallThreshold);var b=Dt(Kt(o.getSources(Ut({query:a,refresh:i,state:s.getState()},c)).then((function(e){return Promise.all(e.map((function(e){return Promise.resolve(e.getItems(Ut({query:a,refresh:i,state:s.getState()},c))).then((function(t){return Tt(t,e.sourceId,s.getState())}))}))).then(It).then((function(t){var n,r=t.some((function(e){return function(e){return!Array.isArray(e)&&Boolean(null==e?void 0:e._automaticInsights)}(e.items)}));r&&m({algoliaInsightsPlugin:Ut(Ut({},(null===(n=s.getState().context)||void 0===n?void 0:n.algoliaInsightsPlugin)||{}),{},{__automaticInsights:r})});return Nt(t,e,s)})).then((function(e){return function(e){var t=e.collections,n=e.props,r=e.state,o=t.reduce((function(e,t){return xt(xt({},e),{},St({},t.source.sourceId,xt(xt({},t.source),{},{getItems:function(){return tt(t.items)}})))}),{}),a=n.plugins.reduce((function(e,t){return t.reshape?t.reshape(e):e}),{sourcesBySourceId:o,state:r}).sourcesBySourceId;return tt(n.reshape({sourcesBySourceId:a,sources:Object.values(a),state:r})).filter(Boolean).map((function(e){return{source:e,items:e.getItems()}}))}({collections:e,props:o,state:s.getState()})}))})))).then((function(e){var n;f("idle"),l(e);var p=o.shouldPanelOpen({state:s.getState()});u(null!==(n=r.isOpen)&&void 0!==n?n:o.openOnFocus&&!a&&p||p);var d=Mt(s.getState());if(null!==s.getState().activeItemId&&d){var m=d.item,h=d.itemInputValue,v=d.itemUrl,g=d.source;g.onActive(Ut({event:t,item:m,itemInputValue:h,itemUrl:v,refresh:i,source:g,state:s.getState()},c))}})).finally((function(){f("idle"),Gt&&o.environment.clearTimeout(Gt)}));return s.pendingRequests.add(b)}function Zt(e,t,n){return[e,null==n?void 0:n.sourceId,t].filter(Boolean).join("-").replace(/\s/g,"")}function Xt(e){return Xt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Xt(e)}var Jt=["event","props","refresh","store"];function en(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function tn(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?en(Object(n),!0).forEach((function(t){nn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):en(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function nn(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Xt(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Xt(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Xt(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function rn(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var on=/((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i;function an(e){return e.nativeEvent||e}function sn(e){return sn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},sn(e)}var cn=["props","refresh","store"],ln=["inputElement","formElement","panelElement"],un=["inputElement"],pn=["inputElement","maxLength"],dn=["source"],fn=["item","source"];function mn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function hn(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?mn(Object(n),!0).forEach((function(t){vn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):mn(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function vn(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==sn(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==sn(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===sn(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function gn(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function bn(e){var t=e.props,n=e.refresh,r=e.store,o=gn(e,cn);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,a=e.panelElement;function i(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,a].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())}return hn({onTouchStart:i,onMouseDown:i,onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},gn(e,ln))},getRootProps:function(e){return hn({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-controls":r.getState().isOpen?r.getState().collections.map((function(e){var n=e.source;return Zt(t.id,"list",n)})).join(" "):void 0,"aria-labelledby":Zt(t.id,"label")},e)},getFormProps:function(e){e.inputElement;return hn({action:"",noValidate:!0,role:"search",onSubmit:function(a){var i;a.preventDefault(),t.onSubmit(hn({event:a,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(i=e.inputElement)||void 0===i||i.blur()},onReset:function(a){var i;a.preventDefault(),t.onReset(hn({event:a,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(i=e.inputElement)||void 0===i||i.focus()}},gn(e,un))},getLabelProps:function(e){return hn({htmlFor:Zt(t.id,"input"),id:Zt(t.id,"label")},e)},getInputProps:function(e){var a;function i(e){(t.openOnFocus||Boolean(r.getState().query))&&Yt(hn({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var s=e||{},c=(s.inputElement,s.maxLength),l=void 0===c?512:c,u=gn(s,pn),p=Mt(r.getState()),d=function(e){return Boolean(e&&e.match(on))}((null===(a=t.environment.navigator)||void 0===a?void 0:a.userAgent)||""),f=t.enterKeyHint||(null!=p&&p.itemUrl&&!d?"go":"search");return hn({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?Zt(t.id,"item-".concat(r.getState().activeItemId),null==p?void 0:p.source):void 0,"aria-controls":r.getState().isOpen?r.getState().collections.map((function(e){var n=e.source;return Zt(t.id,"list",n)})).join(" "):void 0,"aria-labelledby":Zt(t.id,"label"),value:r.getState().completion||r.getState().query,id:Zt(t.id,"input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:f,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:l,type:"search",onChange:function(e){var a=e.currentTarget.value;t.ignoreCompositionEvents&&an(e).isComposing?o.setQuery(a):Yt(hn({event:e,props:t,query:a.slice(0,l),refresh:n,store:r},o))},onCompositionEnd:function(e){Yt(hn({event:e,props:t,query:e.currentTarget.value.slice(0,l),refresh:n,store:r},o))},onKeyDown:function(e){an(e).isComposing||function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,a=rn(e,Jt);if("ArrowUp"===t.key||"ArrowDown"===t.key){var i=function(){var e=Mt(o.getState()),t=n.environment.document.getElementById(Zt(n.id,"item-".concat(o.getState().activeItemId),null==e?void 0:e.source));t&&(t.scrollIntoViewIfNeeded?t.scrollIntoViewIfNeeded(!1):t.scrollIntoView(!1))},s=function(){var e=Mt(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,i=e.itemInputValue,s=e.itemUrl,c=e.source;c.onActive(tn({event:t,item:n,itemInputValue:i,itemUrl:s,refresh:r,source:c,state:o.getState()},a))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?Yt(tn({event:t,props:n,query:o.getState().query,refresh:r,store:o},a)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),s(),setTimeout(i,0)})):(o.dispatch(t.key,{}),s(),i())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(n.debug||o.pendingRequests.cancelAll());t.preventDefault();var c=Mt(o.getState()),l=c.item,u=c.itemInputValue,p=c.itemUrl,d=c.source;if(t.metaKey||t.ctrlKey)void 0!==p&&(d.onSelect(tn({event:t,item:l,itemInputValue:u,itemUrl:p,refresh:r,source:d,state:o.getState()},a)),n.navigator.navigateNewTab({itemUrl:p,item:l,state:o.getState()}));else if(t.shiftKey)void 0!==p&&(d.onSelect(tn({event:t,item:l,itemInputValue:u,itemUrl:p,refresh:r,source:d,state:o.getState()},a)),n.navigator.navigateNewWindow({itemUrl:p,item:l,state:o.getState()}));else if(t.altKey);else{if(void 0!==p)return d.onSelect(tn({event:t,item:l,itemInputValue:u,itemUrl:p,refresh:r,source:d,state:o.getState()},a)),void n.navigator.navigate({itemUrl:p,item:l,state:o.getState()});Yt(tn({event:t,nextState:{isOpen:!1},props:n,query:u,refresh:r,store:o},a)).then((function(){d.onSelect(tn({event:t,item:l,itemInputValue:u,itemUrl:p,refresh:r,source:d,state:o.getState()},a))}))}}}(hn({event:e,props:t,refresh:n,store:r},o))},onFocus:i,onBlur:xe,onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||i(n)}},u)},getPanelProps:function(e){return hn({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){var n=e||{},r=n.source,o=gn(n,dn);return hn({role:"listbox","aria-labelledby":Zt(t.id,"label"),id:Zt(t.id,"list",r)},o)},getItemProps:function(e){var a=e.item,i=e.source,s=gn(e,fn);return hn({id:Zt(t.id,"item-".concat(a.__autocomplete_id),i),role:"option","aria-selected":r.getState().activeItemId===a.__autocomplete_id,onMouseMove:function(e){if(a.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",a.__autocomplete_id);var t=Mt(r.getState());if(null!==r.getState().activeItemId&&t){var i=t.item,s=t.itemInputValue,c=t.itemUrl,l=t.source;l.onActive(hn({event:e,item:i,itemInputValue:s,itemUrl:c,refresh:n,source:l,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var s=i.getItemInputValue({item:a,state:r.getState()}),c=i.getItemUrl({item:a,state:r.getState()});(c?Promise.resolve():Yt(hn({event:e,nextState:{isOpen:!1},props:t,query:s,refresh:n,store:r},o))).then((function(){i.onSelect(hn({event:e,item:a,itemInputValue:s,itemUrl:c,refresh:n,source:i,state:r.getState()},o))}))}},s)}}}var yn="1.17.7",wn=[{segment:"autocomplete-core",version:yn}];function _n(e){return _n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},_n(e)}function xn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Sn(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?xn(Object(n),!0).forEach((function(t){kn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):xn(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function kn(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==_n(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==_n(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===_n(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function En(e){var t,n,r,o,a=e.plugins,i=e.options,s=null===(t=((null===(n=i.__autocomplete_metadata)||void 0===n?void 0:n.userAgents)||[])[0])||void 0===t?void 0:t.segment,c=s?kn({},s,Object.keys((null===(r=i.__autocomplete_metadata)||void 0===r?void 0:r.options)||{})):{};return{plugins:a.map((function(e){return{name:e.name,options:Object.keys(e.__autocomplete_pluginOptions||[])}})),options:Sn({"autocomplete-core":Object.keys(i)},c),ua:wn.concat((null===(o=i.__autocomplete_metadata)||void 0===o?void 0:o.userAgents)||[])}}function On(e){var t,n=e.state;return!1===n.isOpen||null===n.activeItemId?null:(null===(t=Mt(n))||void 0===t?void 0:t.itemInputValue)||null}function jn(e,t,n,r){if(!n)return null;if(e<0&&(null===t||null!==r&&0===t))return n+e;var o=(null===t?-1:t)+e;return o<=-1||o>=n?null===r?null:0:o}function Pn(e){return Pn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Pn(e)}function Cn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function An(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Cn(Object(n),!0).forEach((function(t){Tn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Cn(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Tn(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Pn(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Pn(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Pn(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var In=function(e,t){switch(t.type){case"setActiveItemId":case"mousemove":return An(An({},e),{},{activeItemId:t.payload});case"setQuery":return An(An({},e),{},{query:t.payload,completion:null});case"setCollections":return An(An({},e),{},{collections:t.payload});case"setIsOpen":return An(An({},e),{},{isOpen:t.payload});case"setStatus":return An(An({},e),{},{status:t.payload});case"setContext":return An(An({},e),{},{context:An(An({},e.context),t.payload)});case"ArrowDown":var n=An(An({},e),{},{activeItemId:t.payload.hasOwnProperty("nextActiveItemId")?t.payload.nextActiveItemId:jn(1,e.activeItemId,it(e),t.props.defaultActiveItemId)});return An(An({},n),{},{completion:On({state:n})});case"ArrowUp":var r=An(An({},e),{},{activeItemId:jn(-1,e.activeItemId,it(e),t.props.defaultActiveItemId)});return An(An({},r),{},{completion:On({state:r})});case"Escape":return e.isOpen?An(An({},e),{},{activeItemId:null,isOpen:!1,completion:null}):An(An({},e),{},{activeItemId:null,query:"",status:"idle",collections:[]});case"submit":return An(An({},e),{},{activeItemId:null,isOpen:!1,status:"idle"});case"reset":return An(An({},e),{},{activeItemId:!0===t.props.openOnFocus?t.props.defaultActiveItemId:null,status:"idle",completion:null,query:""});case"focus":return An(An({},e),{},{activeItemId:t.props.defaultActiveItemId,isOpen:(t.props.openOnFocus||Boolean(e.query))&&t.props.shouldPanelOpen({state:e})});case"blur":return t.props.debug?e:An(An({},e),{},{isOpen:!1,activeItemId:null});case"mouseleave":return An(An({},e),{},{activeItemId:t.props.defaultActiveItemId});default:return"The reducer action ".concat(JSON.stringify(t.type)," is not supported."),e}};function Nn(e){return Nn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Nn(e)}function Ln(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Rn(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Ln(Object(n),!0).forEach((function(t){Dn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Ln(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Dn(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Nn(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Nn(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Nn(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Fn(e){var t=[],n=yt(e,t),r=et(In,n,(function(e){var t,r,a=e.prevState,l=e.state;if(n.onStateChange(Rn({prevState:a,state:l,refresh:i,navigator:n.navigator},o)),!c()&&null!==(t=l.context)&&void 0!==t&&null!==(r=t.algoliaInsightsPlugin)&&void 0!==r&&r.__automaticInsights&&!1!==n.insights){var u=Ge({__autocomplete_clickAnalytics:!1});n.plugins.push(u),s([u])}})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var n=0,r=e.map((function(e){return ot(ot({},e),{},{items:tt(e.items).map((function(e){return ot(ot({},e),{},{__autocomplete_id:n++})}))})}));t.dispatch("setCollections",r)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:r}),a=bn(Rn({props:n,refresh:i,store:r,navigator:n.navigator},o));function i(){return Yt(Rn({event:new Event("input"),nextState:{isOpen:r.getState().isOpen},props:n,navigator:n.navigator,query:r.getState().query,refresh:i,store:r},o))}function s(e){e.forEach((function(e){var r;return null===(r=e.subscribe)||void 0===r?void 0:r.call(e,Rn(Rn({},o),{},{navigator:n.navigator,refresh:i,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})},onResolve:function(e){t.push({onResolve:e})}}))}))}function c(){return n.plugins.some((function(e){return"aa.algoliaInsightsPlugin"===e.name}))}if(n.insights&&!c()){var l="boolean"==typeof n.insights?{}:n.insights;n.plugins.push(Ge(l))}return s(n.plugins),function(e){var t,n,r=e.metadata,o=e.environment;if(null===(t=o.navigator)||void 0===t||null===(n=t.userAgent)||void 0===n?void 0:n.includes("Algolia Crawler")){var a=o.document.createElement("meta"),i=o.document.querySelector("head");a.name="algolia:metadata",setTimeout((function(){a.content=JSON.stringify(r),i.appendChild(a)}),0)}}({metadata:En({plugins:n.plugins,options:e}),environment:n.environment}),Rn(Rn({refresh:i,navigator:n.navigator},a),o)}var Mn=function(e,t,n,r){var o;t[0]=0;for(var a=1;a<t.length;a++){var i=t[a++],s=t[a]?(t[0]|=i?1:2,n[t[a++]]):t[++a];3===i?r[0]=s:4===i?r[1]=Object.assign(r[1]||{},s):5===i?(r[1]=r[1]||{})[t[++a]]=s:6===i?r[1][t[++a]]+=s+"":i?(o=e.apply(s,Mn(e,s,n,["",null])),r.push(o),s[0]?t[0]|=2:(t[a-2]=0,t[a]=o)):r.push(s)}return r},Bn=new Map;function zn(e){var t=Bn.get(this);return t||(t=new Map,Bn.set(this,t)),(t=Mn(this,t.get(e)||(t.set(e,t=function(e){for(var t,n,r=1,o="",a="",i=[0],s=function(e){1===r&&(e||(o=o.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?i.push(0,e,o):3===r&&(e||o)?(i.push(3,e,o),r=2):2===r&&"..."===o&&e?i.push(4,e,0):2===r&&o&&!e?i.push(5,0,!0,o):r>=5&&((o||!e&&5===r)&&(i.push(r,0,o,n),r=6),e&&(i.push(r,e,0,n),r=6)),o=""},c=0;c<e.length;c++){c&&(1===r&&s(),s(c));for(var l=0;l<e[c].length;l++)t=e[c][l],1===r?"<"===t?(s(),i=[i],r=3):o+=t:4===r?"--"===o&&">"===t?(r=1,o=""):o=t+o[0]:a?t===a?a="":o+=t:'"'===t||"'"===t?a=t:">"===t?(s(),r=1):r&&("="===t?(r=5,n=o,o=""):"/"===t&&(r<5||">"===e[c][l+1])?(s(),3===r&&(i=i[0]),r=i,(i=i[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(s(),r=2):o+=t),3===r&&"!--"===o&&(r=4,i=i[0])}return s(),i}(e)),t),arguments,[])).length>1?t:t[0]}var $n=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-SubmitIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","20"),n.setAttribute("height","20"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M16.041 15.856c-0.034 0.026-0.067 0.055-0.099 0.087s-0.060 0.064-0.087 0.099c-1.258 1.213-2.969 1.958-4.855 1.958-1.933 0-3.682-0.782-4.95-2.050s-2.050-3.017-2.050-4.95 0.782-3.682 2.050-4.95 3.017-2.050 4.95-2.050 3.682 0.782 4.95 2.050 2.050 3.017 2.050 4.95c0 1.886-0.745 3.597-1.959 4.856zM21.707 20.293l-3.675-3.675c1.231-1.54 1.968-3.493 1.968-5.618 0-2.485-1.008-4.736-2.636-6.364s-3.879-2.636-6.364-2.636-4.736 1.008-6.364 2.636-2.636 3.879-2.636 6.364 1.008 4.736 2.636 6.364 3.879 2.636 6.364 2.636c2.125 0 4.078-0.737 5.618-1.968l3.675 3.675c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414z"),n.appendChild(r),n},Un=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n},Hn=function(e){var t=e.environment.document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("class","aa-LoadingIcon"),t.setAttribute("viewBox","0 0 100 100"),t.setAttribute("width","20"),t.setAttribute("height","20"),t.innerHTML='<circle\n cx="50"\n cy="50"\n fill="none"\n r="35"\n stroke="currentColor"\n stroke-dasharray="164.93361431346415 56.97787143782138"\n stroke-width="6"\n>\n <animateTransform\n attributeName="transform"\n type="rotate"\n repeatCount="indefinite"\n dur="1s"\n values="0 50 50;90 50 50;180 50 50;360 50 50"\n keyTimes="0;0.40;0.65;1"\n />\n</circle>',t},Vn=["ontouchstart","ontouchend","ontouchmove","ontouchcancel"];function Wn(e,t,n){e[t]=null===n?"":"number"!=typeof n?n:n+"px"}function Qn(e){this._listeners[e.type](e)}function qn(e,t,n){var r,o,a=e[t];if("style"===t)if("string"==typeof n)e.style=n;else if(null===n)e.style="";else for(t in n)a&&n[t]===a[t]||Wn(e.style,t,n[t]);else"o"===t[0]&&"n"===t[1]?(r=t!==(t=t.replace(/Capture$/,"")),((o=t.toLowerCase())in e||Vn.includes(o))&&(t=o),t=t.slice(2),e._listeners||(e._listeners={}),e._listeners[t]=n,n?a||e.addEventListener(t,Qn,r):e.removeEventListener(t,Qn,r)):"list"!==t&&"tagName"!==t&&"form"!==t&&"type"!==t&&"size"!==t&&"download"!==t&&"href"!==t&&t in e?e[t]=null==n?"":n:"function"!=typeof n&&"dangerouslySetInnerHTML"!==t&&(null==n||!1===n&&!/^ar/.test(t)?e.removeAttribute(t):e.setAttribute(t,n))}function Gn(e){switch(e){case"onChange":return"onInput";case"onCompositionEnd":return"oncompositionend";default:return e}}function Kn(e,t){for(var n in t)qn(e,Gn(n),t[n])}function Yn(e,t){for(var n in t)"o"===n[0]&&"n"===n[1]||qn(e,Gn(n),t[n])}var Zn=["children"];function Xn(e){return function(e){if(Array.isArray(e))return Jn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Jn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Jn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Jn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function er(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function tr(e){return function(t,n){var r=n.children,o=void 0===r?[]:r,a=er(n,Zn),i=e.document.createElement(t);return Kn(i,a),i.append.apply(i,Xn(o)),i}}function nr(e){return nr="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},nr(e)}var rr=["autocompleteScopeApi","environment","classNames","getInputProps","getInputPropsCore","isDetached","state"];function or(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ar(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?or(Object(n),!0).forEach((function(t){ir(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):or(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function ir(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==nr(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==nr(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===nr(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function sr(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function cr(e){return cr="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},cr(e)}function lr(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ur(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?lr(Object(n),!0).forEach((function(t){pr(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):lr(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function pr(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==cr(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==cr(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===cr(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function dr(e){var t=e.autocomplete,n=e.autocompleteScopeApi,r=e.classNames,o=e.environment,a=e.isDetached,i=e.placeholder,s=void 0===i?"Search":i,c=e.propGetters,l=e.setIsModalOpen,u=e.state,p=e.translations,d=tr(o),f=c.getRootProps(ur({state:u,props:t.getRootProps({})},n)),m=d("div",ur({class:r.root},f)),h=d("div",{class:r.detachedContainer,onMouseDown:function(e){e.stopPropagation()}}),v=d("div",{class:r.detachedOverlay,children:[h],onMouseDown:function(){l(!1),t.setIsOpen(!1)}}),g=c.getLabelProps(ur({state:u,props:t.getLabelProps({})},n)),b=d("button",{class:r.submitButton,type:"submit",title:p.submitButtonTitle,children:[$n({environment:o})]}),y=d("label",ur({class:r.label,children:[b],ariaLabel:p.submitButtonTitle},g)),w=d("button",{class:r.clearButton,type:"reset",title:p.clearButtonTitle,children:[Un({environment:o})]}),_=d("div",{class:r.loadingIndicator,children:[Hn({environment:o})]}),x=function(e){var t=e.autocompleteScopeApi,n=e.environment,r=(e.classNames,e.getInputProps),o=e.getInputPropsCore,a=e.isDetached,i=e.state,s=sr(e,rr),c=tr(n)("input",s),l=r(ar({state:i,props:o({inputElement:c}),inputElement:c},t));return Kn(c,ar(ar({},l),{},{onKeyDown:function(e){a&&"Tab"===e.key||l.onKeyDown(e)}})),c}({class:r.input,environment:o,state:u,getInputProps:c.getInputProps,getInputPropsCore:t.getInputProps,autocompleteScopeApi:n,isDetached:a}),S=d("div",{class:r.inputWrapperPrefix,children:[y,_]}),k=d("div",{class:r.inputWrapperSuffix,children:[w]}),E=d("div",{class:r.inputWrapper,children:[x]}),O=c.getFormProps(ur({state:u,props:t.getFormProps({inputElement:x})},n)),j=d("form",ur({class:r.form,children:[S,E,k]},O)),P=c.getPanelProps(ur({state:u,props:t.getPanelProps({})},n)),C=d("div",ur({class:r.panel},P)),A=d("div",{class:r.detachedSearchButtonQuery,textContent:u.query}),T=d("div",{class:r.detachedSearchButtonPlaceholder,hidden:Boolean(u.query),textContent:s});if(a){var I=d("div",{class:r.detachedSearchButtonIcon,children:[$n({environment:o})]}),N=d("button",{type:"button",class:r.detachedSearchButton,title:p.detachedSearchButtonTitle,id:g.id,onClick:function(){l(!0)},children:[I,T,A]}),L=d("button",{type:"button",class:r.detachedCancelButton,textContent:p.detachedCancelButtonText,onTouchStart:function(e){e.stopPropagation()},onClick:function(){t.setIsOpen(!1),l(!1)}}),R=d("div",{class:r.detachedFormContainer,children:[j,L]});h.appendChild(R),m.appendChild(N)}else m.appendChild(j);return{detachedContainer:h,detachedOverlay:v,detachedSearchButtonQuery:A,detachedSearchButtonPlaceholder:T,inputWrapper:E,input:x,root:m,form:j,label:y,submitButton:b,clearButton:w,loadingIndicator:_,panel:C}}var fr,mr,hr,vr,gr,br,yr,wr,_r,xr,Sr={},kr=[],Er=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Or=Array.isArray;function jr(e,t){for(var n in t)e[n]=t[n];return e}function Pr(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Cr(e,t,n){var r,o,a,i={};for(a in t)"key"==a?r=t[a]:"ref"==a?o=t[a]:i[a]=t[a];if(arguments.length>2&&(i.children=arguments.length>3?fr.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(a in e.defaultProps)void 0===i[a]&&(i[a]=e.defaultProps[a]);return Ar(e,i,r,o,null)}function Ar(e,t,n,r,o){var a={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:null==o?++hr:o,__i:-1,__u:0};return null==o&&null!=mr.vnode&&mr.vnode(a),a}function Tr(e){return e.children}function Ir(e,t){this.props=e,this.context=t}function Nr(e,t){if(null==t)return e.__?Nr(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if(null!=(n=e.__k[t])&&null!=n.__e)return n.__e;return"function"==typeof e.type?Nr(e):null}function Lr(e){var t,n;if(null!=(e=e.__)&&null!=e.__c){for(e.__e=e.__c.base=null,t=0;t<e.__k.length;t++)if(null!=(n=e.__k[t])&&null!=n.__e){e.__e=e.__c.base=n.__e;break}return Lr(e)}}function Rr(e){(!e.__d&&(e.__d=!0)&&vr.push(e)&&!Dr.__r++||gr!==mr.debounceRendering)&&((gr=mr.debounceRendering)||br)(Dr)}function Dr(){var e,t,n,r,o,a,i,s;for(vr.sort(yr);e=vr.shift();)e.__d&&(t=vr.length,r=void 0,a=(o=(n=e).__v).__e,i=[],s=[],n.__P&&((r=jr({},o)).__v=o.__v+1,mr.vnode&&mr.vnode(r),Vr(n.__P,r,o,n.__n,n.__P.namespaceURI,32&o.__u?[a]:null,i,null==a?Nr(o):a,!!(32&o.__u),s),r.__v=o.__v,r.__.__k[r.__i]=r,Wr(i,r,s),r.__e!=a&&Lr(r)),vr.length>t&&vr.sort(yr));Dr.__r=0}function Fr(e,t,n,r,o,a,i,s,c,l,u){var p,d,f,m,h,v=r&&r.__k||kr,g=t.length;for(n.__d=c,Mr(n,t,v),c=n.__d,p=0;p<g;p++)null!=(f=n.__k[p])&&(d=-1===f.__i?Sr:v[f.__i]||Sr,f.__i=p,Vr(e,f,d,o,a,i,s,c,l,u),m=f.__e,f.ref&&d.ref!=f.ref&&(d.ref&&qr(d.ref,null,f),u.push(f.ref,f.__c||m,f)),null==h&&null!=m&&(h=m),65536&f.__u||d.__k===f.__k?c=Br(f,c,e):"function"==typeof f.type&&void 0!==f.__d?c=f.__d:m&&(c=m.nextSibling),f.__d=void 0,f.__u&=-196609);n.__d=c,n.__e=h}function Mr(e,t,n){var r,o,a,i,s,c=t.length,l=n.length,u=l,p=0;for(e.__k=[],r=0;r<c;r++)null!=(o=t[r])&&"boolean"!=typeof o&&"function"!=typeof o?(i=r+p,(o=e.__k[r]="string"==typeof o||"number"==typeof o||"bigint"==typeof o||o.constructor==String?Ar(null,o,null,null,null):Or(o)?Ar(Tr,{children:o},null,null,null):void 0===o.constructor&&o.__b>0?Ar(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):o).__=e,o.__b=e.__b+1,a=null,-1!==(s=o.__i=zr(o,n,i,u))&&(u--,(a=n[s])&&(a.__u|=131072)),null==a||null===a.__v?(-1==s&&p--,"function"!=typeof o.type&&(o.__u|=65536)):s!==i&&(s==i-1?p--:s==i+1?p++:(s>i?p--:p++,o.__u|=65536))):o=e.__k[r]=null;if(u)for(r=0;r<l;r++)null!=(a=n[r])&&!(131072&a.__u)&&(a.__e==e.__d&&(e.__d=Nr(a)),Gr(a,a))}function Br(e,t,n){var r,o;if("function"==typeof e.type){for(r=e.__k,o=0;r&&o<r.length;o++)r[o]&&(r[o].__=e,t=Br(r[o],t,n));return t}e.__e!=t&&(t&&e.type&&!n.contains(t)&&(t=Nr(e)),n.insertBefore(e.__e,t||null),t=e.__e);do{t=t&&t.nextSibling}while(null!=t&&8===t.nodeType);return t}function zr(e,t,n,r){var o=e.key,a=e.type,i=n-1,s=n+1,c=t[n];if(null===c||c&&o==c.key&&a===c.type&&!(131072&c.__u))return n;if(("function"!=typeof a||a===Tr||o)&&r>(null==c||131072&c.__u?0:1))for(;i>=0||s<t.length;){if(i>=0){if((c=t[i])&&!(131072&c.__u)&&o==c.key&&a===c.type)return i;i--}if(s<t.length){if((c=t[s])&&!(131072&c.__u)&&o==c.key&&a===c.type)return s;s++}}return-1}function $r(e,t,n){"-"===t[0]?e.setProperty(t,null==n?"":n):e[t]=null==n?"":"number"!=typeof n||Er.test(t)?n:n+"px"}function Ur(e,t,n,r,o){var a;e:if("style"===t)if("string"==typeof n)e.style.cssText=n;else{if("string"==typeof r&&(e.style.cssText=r=""),r)for(t in r)n&&t in n||$r(e.style,t,"");if(n)for(t in n)r&&n[t]===r[t]||$r(e.style,t,n[t])}else if("o"===t[0]&&"n"===t[1])a=t!==(t=t.replace(/(PointerCapture)$|Capture$/i,"$1")),t=t.toLowerCase()in e||"onFocusOut"===t||"onFocusIn"===t?t.toLowerCase().slice(2):t.slice(2),e.l||(e.l={}),e.l[t+a]=n,n?r?n.u=r.u:(n.u=wr,e.addEventListener(t,a?xr:_r,a)):e.removeEventListener(t,a?xr:_r,a);else{if("http://www.w3.org/2000/svg"==o)t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!=t&&"height"!=t&&"href"!=t&&"list"!=t&&"form"!=t&&"tabIndex"!=t&&"download"!=t&&"rowSpan"!=t&&"colSpan"!=t&&"role"!=t&&"popover"!=t&&t in e)try{e[t]=null==n?"":n;break e}catch(e){}"function"==typeof n||(null==n||!1===n&&"-"!==t[4]?e.removeAttribute(t):e.setAttribute(t,"popover"==t&&1==n?"":n))}}function Hr(e){return function(t){if(this.l){var n=this.l[t.type+e];if(null==t.t)t.t=wr++;else if(t.t<n.u)return;return mr.event&&(t=mr.event(t)),"handleEvent"in n?n.handleEvent(t):n(t)}}}function Vr(e,t,n,r,o,a,i,s,c,l){var u,p,d,f,m,h,v,g,b,y,w,_,x,S,k,E,O=t.type;if(void 0!==t.constructor)return null;128&n.__u&&(c=!!(32&n.__u),a=[s=t.__e=n.__e]),(u=mr.__b)&&u(t);e:if("function"==typeof O)try{if(g=t.props,b="prototype"in O&&O.prototype.render,y=(u=O.contextType)&&r[u.__c],w=u?y?y.props.value:u.__:r,n.__c?v=(p=t.__c=n.__c).__=p.__E:(b?t.__c=p=new O(g,w):(t.__c=p=new Ir(g,w),p.constructor=O,p.render=Kr),y&&y.sub(p),p.props=g,p.state||(p.state={}),p.context=w,p.__n=r,d=p.__d=!0,p.__h=[],p._sb=[]),b&&null==p.__s&&(p.__s=p.state),b&&null!=O.getDerivedStateFromProps&&(p.__s==p.state&&(p.__s=jr({},p.__s)),jr(p.__s,O.getDerivedStateFromProps(g,p.__s))),f=p.props,m=p.state,p.__v=t,d)b&&null==O.getDerivedStateFromProps&&null!=p.componentWillMount&&p.componentWillMount(),b&&null!=p.componentDidMount&&p.__h.push(p.componentDidMount);else{if(b&&null==O.getDerivedStateFromProps&&g!==f&&null!=p.componentWillReceiveProps&&p.componentWillReceiveProps(g,w),!p.__e&&(null!=p.shouldComponentUpdate&&!1===p.shouldComponentUpdate(g,p.__s,w)||t.__v===n.__v)){for(t.__v!==n.__v&&(p.props=g,p.state=p.__s,p.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some((function(e){e&&(e.__=t)})),_=0;_<p._sb.length;_++)p.__h.push(p._sb[_]);p._sb=[],p.__h.length&&i.push(p);break e}null!=p.componentWillUpdate&&p.componentWillUpdate(g,p.__s,w),b&&null!=p.componentDidUpdate&&p.__h.push((function(){p.componentDidUpdate(f,m,h)}))}if(p.context=w,p.props=g,p.__P=e,p.__e=!1,x=mr.__r,S=0,b){for(p.state=p.__s,p.__d=!1,x&&x(t),u=p.render(p.props,p.state,p.context),k=0;k<p._sb.length;k++)p.__h.push(p._sb[k]);p._sb=[]}else do{p.__d=!1,x&&x(t),u=p.render(p.props,p.state,p.context),p.state=p.__s}while(p.__d&&++S<25);p.state=p.__s,null!=p.getChildContext&&(r=jr(jr({},r),p.getChildContext())),b&&!d&&null!=p.getSnapshotBeforeUpdate&&(h=p.getSnapshotBeforeUpdate(f,m)),Fr(e,Or(E=null!=u&&u.type===Tr&&null==u.key?u.props.children:u)?E:[E],t,n,r,o,a,i,s,c,l),p.base=t.__e,t.__u&=-161,p.__h.length&&i.push(p),v&&(p.__E=p.__=null)}catch(e){if(t.__v=null,c||null!=a){for(t.__u|=c?160:128;s&&8===s.nodeType&&s.nextSibling;)s=s.nextSibling;a[a.indexOf(s)]=null,t.__e=s}else t.__e=n.__e,t.__k=n.__k;mr.__e(e,t,n)}else null==a&&t.__v===n.__v?(t.__k=n.__k,t.__e=n.__e):t.__e=Qr(n.__e,t,n,r,o,a,i,c,l);(u=mr.diffed)&&u(t)}function Wr(e,t,n){t.__d=void 0;for(var r=0;r<n.length;r++)qr(n[r],n[++r],n[++r]);mr.__c&&mr.__c(t,e),e.some((function(t){try{e=t.__h,t.__h=[],e.some((function(e){e.call(t)}))}catch(e){mr.__e(e,t.__v)}}))}function Qr(e,t,n,r,o,a,i,s,c){var l,u,p,d,f,m,h,v=n.props,g=t.props,b=t.type;if("svg"===b?o="http://www.w3.org/2000/svg":"math"===b?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),null!=a)for(l=0;l<a.length;l++)if((f=a[l])&&"setAttribute"in f==!!b&&(b?f.localName===b:3===f.nodeType)){e=f,a[l]=null;break}if(null==e){if(null===b)return document.createTextNode(g);e=document.createElementNS(o,b,g.is&&g),s&&(mr.__m&&mr.__m(t,a),s=!1),a=null}if(null===b)v===g||s&&e.data===g||(e.data=g);else{if(a=a&&fr.call(e.childNodes),v=n.props||Sr,!s&&null!=a)for(v={},l=0;l<e.attributes.length;l++)v[(f=e.attributes[l]).name]=f.value;for(l in v)if(f=v[l],"children"==l);else if("dangerouslySetInnerHTML"==l)p=f;else if(!(l in g)){if("value"==l&&"defaultValue"in g||"checked"==l&&"defaultChecked"in g)continue;Ur(e,l,null,f,o)}for(l in g)f=g[l],"children"==l?d=f:"dangerouslySetInnerHTML"==l?u=f:"value"==l?m=f:"checked"==l?h=f:s&&"function"!=typeof f||v[l]===f||Ur(e,l,f,v[l],o);if(u)s||p&&(u.__html===p.__html||u.__html===e.innerHTML)||(e.innerHTML=u.__html),t.__k=[];else if(p&&(e.innerHTML=""),Fr(e,Or(d)?d:[d],t,n,r,"foreignObject"===b?"http://www.w3.org/1999/xhtml":o,a,i,a?a[0]:n.__k&&Nr(n,0),s,c),null!=a)for(l=a.length;l--;)Pr(a[l]);s||(l="value","progress"===b&&null==m?e.removeAttribute("value"):void 0!==m&&(m!==e[l]||"progress"===b&&!m||"option"===b&&m!==v[l])&&Ur(e,l,m,v[l],o),l="checked",void 0!==h&&h!==e[l]&&Ur(e,l,h,v[l],o))}return e}function qr(e,t,n){try{if("function"==typeof e){var r="function"==typeof e.__u;r&&e.__u(),r&&null==t||(e.__u=e(t))}else e.current=t}catch(e){mr.__e(e,n)}}function Gr(e,t,n){var r,o;if(mr.unmount&&mr.unmount(e),(r=e.ref)&&(r.current&&r.current!==e.__e||qr(r,null,t)),null!=(r=e.__c)){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(e){mr.__e(e,t)}r.base=r.__P=null}if(r=e.__k)for(o=0;o<r.length;o++)r[o]&&Gr(r[o],t,n||"function"!=typeof e.type);n||Pr(e.__e),e.__c=e.__=e.__e=e.__d=void 0}function Kr(e,t,n){return this.constructor(e,n)}function Yr(e,t,n){var r,o,a,i;mr.__&&mr.__(e,t),o=(r="function"==typeof n)?null:n&&n.__k||t.__k,a=[],i=[],Vr(t,e=(!r&&n||t).__k=Cr(Tr,null,[e]),o||Sr,Sr,t.namespaceURI,!r&&n?[n]:o?null:t.firstChild?fr.call(t.childNodes):null,a,!r&&n?n:o?o.__e:t.firstChild,r,i),Wr(a,e,i)}function Zr(e,t){return t.reduce((function(e,t){return e&&e[t]}),e)}fr=kr.slice,mr={__e:function(e,t,n,r){for(var o,a,i;t=t.__;)if((o=t.__c)&&!o.__)try{if((a=o.constructor)&&null!=a.getDerivedStateFromError&&(o.setState(a.getDerivedStateFromError(e)),i=o.__d),null!=o.componentDidCatch&&(o.componentDidCatch(e,r||{}),i=o.__d),i)return o.__E=o}catch(t){e=t}throw e}},hr=0,Ir.prototype.setState=function(e,t){var n;n=null!=this.__s&&this.__s!==this.state?this.__s:this.__s=jr({},this.state),"function"==typeof e&&(e=e(jr({},n),this.props)),e&&jr(n,e),null!=e&&this.__v&&(t&&this._sb.push(t),Rr(this))},Ir.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Rr(this))},Ir.prototype.render=Tr,vr=[],br="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,yr=function(e,t){return e.__v.__b-t.__v.__b},Dr.__r=0,wr=0,_r=Hr(!1),xr=Hr(!0);function Xr(e){var t=e.highlightedValue.split("__aa-highlight__"),n=t.shift(),r=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split("__/aa-highlight__");r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Jr(e){return function(e){if(Array.isArray(e))return eo(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return eo(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return eo(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function eo(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function to(e){var t=e.hit,n=e.attribute,r=Array.isArray(n)?n:[n],o=Zr(t,["_highlightResult"].concat(Jr(r),["value"]));return"string"!=typeof o&&(o=Zr(t,r)||""),Xr({highlightedValue:o})}function no(e){var t=e.createElement,n=e.Fragment;function r(e){var r=e.hit,o=e.attribute,a=e.tagName,i=void 0===a?"mark":a;return t(n,{},to({hit:r,attribute:o}).map((function(e,n){return e.isHighlighted?t(i,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="Highlight",r}var ro={"&":"&","<":"<",">":">",""":'"',"'":"'"},oo=new RegExp(/\w/i),ao=/&(amp|quot|lt|gt|#39);/g,io=RegExp(ao.source);function so(e,t){var n,r,o,a=e[t],i=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,s=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return oo.test((o=a.value)&&io.test(o)?o.replace(ao,(function(e){return ro[e]})):o)||s!==i?a.isHighlighted:s}function co(e){return co="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},co(e)}function lo(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function uo(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?lo(Object(n),!0).forEach((function(t){po(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):lo(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function po(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==co(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==co(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===co(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function fo(e){return e.some((function(e){return e.isHighlighted}))?e.map((function(t,n){return uo(uo({},t),{},{isHighlighted:!so(e,n)})})):e.map((function(e){return uo(uo({},e),{},{isHighlighted:!1})}))}function mo(e){var t=e.createElement,n=e.Fragment;function r(e){var r,o=e.hit,a=e.attribute,i=e.tagName,s=void 0===i?"mark":i;return t(n,{},(r={hit:o,attribute:a},fo(to(r))).map((function(e,n){return e.isHighlighted?t(s,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="ReverseHighlight",r}function ho(e){return function(e){if(Array.isArray(e))return vo(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return vo(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return vo(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function vo(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function go(e){var t=e.hit,n=e.attribute,r=Array.isArray(n)?n:[n],o=Zr(t,["_snippetResult"].concat(ho(r),["value"]));return"string"!=typeof o&&(o=Zr(t,r)||""),Xr({highlightedValue:o})}function bo(e){var t=e.createElement,n=e.Fragment;function r(e){var r,o=e.hit,a=e.attribute,i=e.tagName,s=void 0===i?"mark":i;return t(n,{},(r={hit:o,attribute:a},fo(go(r))).map((function(e,n){return e.isHighlighted?t(s,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="ReverseSnippet",r}function yo(e){var t=e.createElement,n=e.Fragment;function r(e){var r=e.hit,o=e.attribute,a=e.tagName,i=void 0===a?"mark":a;return t(n,{},go({hit:r,attribute:o}).map((function(e,n){return e.isHighlighted?t(i,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="Snippet",r}function wo(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function _o(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.reduce((function(e,t){return Object.keys(t).forEach((function(n){var r=e[n],o=t[n];r!==o&&(e[n]=[r,o].filter(Boolean).join(" "))})),e}),{})}function xo(e){return xo="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},xo(e)}var So=["classNames","container","getEnvironmentProps","getFormProps","getInputProps","getItemProps","getLabelProps","getListProps","getPanelProps","getRootProps","panelContainer","panelPlacement","render","renderNoResults","renderer","detachedMediaQuery","components","translations"];function ko(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Eo(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?ko(Object(n),!0).forEach((function(t){Oo(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):ko(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Oo(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==xo(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==xo(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===xo(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function jo(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var Po={clearButton:"aa-ClearButton",detachedCancelButton:"aa-DetachedCancelButton",detachedContainer:"aa-DetachedContainer",detachedFormContainer:"aa-DetachedFormContainer",detachedOverlay:"aa-DetachedOverlay",detachedSearchButton:"aa-DetachedSearchButton",detachedSearchButtonIcon:"aa-DetachedSearchButtonIcon",detachedSearchButtonPlaceholder:"aa-DetachedSearchButtonPlaceholder",detachedSearchButtonQuery:"aa-DetachedSearchButtonQuery",form:"aa-Form",input:"aa-Input",inputWrapper:"aa-InputWrapper",inputWrapperPrefix:"aa-InputWrapperPrefix",inputWrapperSuffix:"aa-InputWrapperSuffix",item:"aa-Item",label:"aa-Label",list:"aa-List",loadingIndicator:"aa-LoadingIndicator",panel:"aa-Panel",panelLayout:"aa-PanelLayout aa-Panel--scrollable",root:"aa-Autocomplete",source:"aa-Source",sourceFooter:"aa-SourceFooter",sourceHeader:"aa-SourceHeader",sourceNoResults:"aa-SourceNoResults",submitButton:"aa-SubmitButton"},Co=function(e,t){var n=e.children;(0,e.render)(n,t)},Ao={createElement:Cr,Fragment:Tr,render:Yr};function To(e){var t=e.panelPlacement,n=e.container,r=e.form,o=e.environment,a=n.getBoundingClientRect(),i=(o.pageYOffset||o.document.documentElement.scrollTop||o.document.body.scrollTop||0)+a.top+a.height;switch(t){case"start":return{top:i,left:a.left};case"end":return{top:i,right:o.document.documentElement.clientWidth-(a.left+a.width)};case"full-width":return{top:i,left:0,right:0,width:"unset",maxWidth:"unset"};case"input-wrapper-width":var s=r.getBoundingClientRect();return{top:i,left:s.left,right:o.document.documentElement.clientWidth-(s.left+s.width),width:"unset",maxWidth:"unset"};default:throw new Error("[Autocomplete] The `panelPlacement` value ".concat(JSON.stringify(t)," is not valid."))}}function Io(e){return Io="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Io(e)}function No(){return No=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},No.apply(this,arguments)}function Lo(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ro(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Lo(Object(n),!0).forEach((function(t){Do(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Lo(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Do(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Io(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Io(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Io(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var Fo=[{segment:"autocomplete-js",version:yn}];function Mo(e){return function(e){if(Array.isArray(e))return Bo(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Bo(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Bo(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Bo(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function zo(e){return zo="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},zo(e)}var $o=function(e){return e&&"object"===zo(e)&&"[object Object]"===Object.prototype.toString.call(e)};function Uo(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.reduce((function(e,t){return Object.keys(t).forEach((function(n){var r=e[n],o=t[n];Array.isArray(r)&&Array.isArray(o)?e[n]=r.concat.apply(r,Mo(o)):$o(r)&&$o(o)?e[n]=Uo(r,o):e[n]=o})),e}),{})}function Ho(e){return Ho="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ho(e)}function Vo(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Wo(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Vo(Object(n),!0).forEach((function(t){Qo(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Vo(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Qo(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Ho(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Ho(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Ho(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function qo(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,a,i,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;c=!1}else for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(u){l=!0,o=u}finally{try{if(!c&&null!=n.return&&(i=n.return(),Object(i)!==i))return}finally{if(l)throw o}}return s}}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Go(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Go(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Go(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}var Ko=["components"];function Yo(e){return Yo="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Yo(e)}function Zo(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function Xo(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Jo(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Xo(Object(n),!0).forEach((function(t){ea(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Xo(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function ea(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==Yo(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==Yo(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Yo(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ta(e){var t,n=function(){var e=[],t=[];function n(n){e.push(n);var r=n();t.push(r)}return{runEffect:n,cleanupEffects:function(){var e=t;t=[],e.forEach((function(e){e()}))},runEffects:function(){var t=e;e=[],t.forEach((function(e){n(e)}))}}}(),r=n.runEffect,o=n.cleanupEffects,a=n.runEffects,i=(t=[],{reactive:function(e){var n=e(),r={_fn:e,_ref:{current:n},get value(){return this._ref.current},set value(e){this._ref.current=e}};return t.push(r),r},runReactives:function(){t.forEach((function(e){e._ref.current=e._fn()}))}}),s=i.reactive,c=i.runReactives,l=ye(!1),u=ye(e),p=ye(void 0),d=s((function(){return function(e){var t,n=e.classNames,r=e.container,o=e.getEnvironmentProps,a=e.getFormProps,i=e.getInputProps,s=e.getItemProps,c=e.getLabelProps,l=e.getListProps,u=e.getPanelProps,p=e.getRootProps,d=e.panelContainer,f=e.panelPlacement,m=e.render,h=e.renderNoResults,v=e.renderer,g=e.detachedMediaQuery,b=e.components,y=e.translations,w=jo(e,So),_="undefined"!=typeof window?window:{},x=wo(_,r);x.tagName;var S=Eo(Eo({},Ao),v),k={Highlight:no(S),ReverseHighlight:mo(S),ReverseSnippet:bo(S),Snippet:yo(S)};return{renderer:{classNames:_o(Po,null!=n?n:{}),container:x,getEnvironmentProps:null!=o?o:function(e){return e.props},getFormProps:null!=a?a:function(e){return e.props},getInputProps:null!=i?i:function(e){return e.props},getItemProps:null!=s?s:function(e){return e.props},getLabelProps:null!=c?c:function(e){return e.props},getListProps:null!=l?l:function(e){return e.props},getPanelProps:null!=u?u:function(e){return e.props},getRootProps:null!=p?p:function(e){return e.props},panelContainer:d?wo(_,d):_.document.body,panelPlacement:null!=f?f:"input-wrapper-width",render:null!=m?m:Co,renderNoResults:h,renderer:S,detachedMediaQuery:null!=g?g:getComputedStyle(_.document.documentElement).getPropertyValue("--aa-detached-media-query"),components:Eo(Eo({},k),b),translations:Eo(Eo({},{clearButtonTitle:"Clear",detachedCancelButtonText:"Cancel",detachedSearchButtonTitle:"Search",submitButtonTitle:"Submit"}),y)},core:Eo(Eo({},w),{},{id:null!==(t=w.id)&&void 0!==t?t:ct(),environment:_})}}(u.current)})),f=s((function(){return d.value.core.environment.matchMedia(d.value.renderer.detachedMediaQuery).matches})),m=s((function(){return Fn(Jo(Jo({},d.value.core),{},{onStateChange:function(e){var t,n,r;l.current=e.state.collections.some((function(e){return e.source.templates.noResults})),null===(t=p.current)||void 0===t||t.call(p,e),null===(n=(r=d.value.core).onStateChange)||void 0===n||n.call(r,e)},shouldPanelOpen:u.current.shouldPanelOpen||function(e){var t=e.state;if(f.value)return!0;var n=it(t)>0;if(!d.value.core.openOnFocus&&!t.query)return n;var r=Boolean(l.current||d.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:Fo,options:e}}))})),h=ye(Jo({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},d.value.core.initialState)),v={getEnvironmentProps:d.value.renderer.getEnvironmentProps,getFormProps:d.value.renderer.getFormProps,getInputProps:d.value.renderer.getInputProps,getItemProps:d.value.renderer.getItemProps,getLabelProps:d.value.renderer.getLabelProps,getListProps:d.value.renderer.getListProps,getPanelProps:d.value.renderer.getPanelProps,getRootProps:d.value.renderer.getRootProps},g={setActiveItemId:m.value.setActiveItemId,setQuery:m.value.setQuery,setCollections:m.value.setCollections,setIsOpen:m.value.setIsOpen,setStatus:m.value.setStatus,setContext:m.value.setContext,refresh:m.value.refresh,navigator:m.value.navigator},b=s((function(){return zn.bind(d.value.renderer.renderer.createElement)})),y=s((function(){return dr({autocomplete:m.value,autocompleteScopeApi:g,classNames:d.value.renderer.classNames,environment:d.value.core.environment,isDetached:f.value,placeholder:d.value.core.placeholder,propGetters:v,setIsModalOpen:S,state:h.current,translations:d.value.renderer.translations})}));function w(){Kn(y.value.panel,{style:f.value?{}:To({panelPlacement:d.value.renderer.panelPlacement,container:y.value.root,form:y.value.form,environment:d.value.core.environment})})}function _(e){h.current=e;var t={autocomplete:m.value,autocompleteScopeApi:g,classNames:d.value.renderer.classNames,components:d.value.renderer.components,container:d.value.renderer.container,html:b.value,dom:y.value,panelContainer:f.value?y.value.detachedContainer:d.value.renderer.panelContainer,propGetters:v,state:h.current,renderer:d.value.renderer.renderer},n=!it(e)&&!l.current&&d.value.renderer.renderNoResults||d.value.renderer.render;!function(e){var t=e.autocomplete,n=e.autocompleteScopeApi,r=e.dom,o=e.propGetters,a=e.state;Yn(r.root,o.getRootProps(Ro({state:a,props:t.getRootProps({})},n))),Yn(r.input,o.getInputProps(Ro({state:a,props:t.getInputProps({inputElement:r.input}),inputElement:r.input},n))),Kn(r.label,{hidden:"stalled"===a.status}),Kn(r.loadingIndicator,{hidden:"stalled"!==a.status}),Kn(r.clearButton,{hidden:!a.query}),Kn(r.detachedSearchButtonQuery,{textContent:a.query}),Kn(r.detachedSearchButtonPlaceholder,{hidden:Boolean(a.query)})}(t),function(e,t){var n=t.autocomplete,r=t.autocompleteScopeApi,o=t.classNames,a=t.html,i=t.dom,s=t.panelContainer,c=t.propGetters,l=t.state,u=t.components,p=t.renderer;if(l.isOpen){s.contains(i.panel)||"loading"===l.status||s.appendChild(i.panel),i.panel.classList.toggle("aa-Panel--stalled","stalled"===l.status);var d=l.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var i=e.source,s=e.items;return p.createElement("section",{key:t,className:o.source,"data-autocomplete-source-id":i.sourceId},i.templates.header&&p.createElement("div",{className:o.sourceHeader},i.templates.header({components:u,createElement:p.createElement,Fragment:p.Fragment,items:s,source:i,state:l,html:a})),i.templates.noResults&&0===s.length?p.createElement("div",{className:o.sourceNoResults},i.templates.noResults({components:u,createElement:p.createElement,Fragment:p.Fragment,source:i,state:l,html:a})):p.createElement("ul",No({className:o.list},c.getListProps(Ro({state:l,props:n.getListProps({source:i})},r))),s.map((function(e){var t=n.getItemProps({item:e,source:i});return p.createElement("li",No({key:t.id,className:o.item},c.getItemProps(Ro({state:l,props:t},r))),i.templates.item({components:u,createElement:p.createElement,Fragment:p.Fragment,item:e,state:l,html:a}))}))),i.templates.footer&&p.createElement("div",{className:o.sourceFooter},i.templates.footer({components:u,createElement:p.createElement,Fragment:p.Fragment,items:s,source:i,state:l,html:a})))})),f=p.createElement(p.Fragment,null,p.createElement("div",{className:o.panelLayout},d),p.createElement("div",{className:"aa-GradientBottom"})),m=d.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(Ro(Ro({children:f,state:l,sections:d,elements:m},p),{},{components:u,html:a},r),i.panel)}else s.contains(i.panel)&&s.removeChild(i.panel)}(n,t)}function x(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o();var t,n,r=d.value.renderer,i=r.components,s=Zo(r,Ko);u.current=Uo(s,d.value.core,{components:(t=i,n=function(e){return!e.value.hasOwnProperty("__autocomplete_componentName")},Object.entries(t).reduce((function(e,t){var r=qo(t,2),o=r[0],a=r[1];return n({key:o,value:a})?Wo(Wo({},e),{},Qo({},o,a)):e}),{})),initialState:h.current},e),c(),a(),m.value.refresh().then((function(){_(h.current)}))}function S(e){e!==d.value.core.environment.document.body.contains(y.value.detachedOverlay)&&(e?(d.value.core.environment.document.body.appendChild(y.value.detachedOverlay),d.value.core.environment.document.body.classList.add("aa-Detached"),y.value.input.focus()):(d.value.core.environment.document.body.removeChild(y.value.detachedOverlay),d.value.core.environment.document.body.classList.remove("aa-Detached")))}return r((function(){var e=m.value.getEnvironmentProps({formElement:y.value.form,panelElement:y.value.panel,inputElement:y.value.input});return Kn(d.value.core.environment,e),function(){Kn(d.value.core.environment,Object.keys(e).reduce((function(e,t){return Jo(Jo({},e),{},ea({},t,void 0))}),{}))}})),r((function(){var e=f.value?d.value.core.environment.document.body:d.value.renderer.panelContainer,t=f.value?y.value.detachedOverlay:y.value.panel;return f.value&&h.current.isOpen&&S(!0),_(h.current),function(){e.contains(t)&&(e.removeChild(t),e.classList.remove("aa-Detached"))}})),r((function(){var e=d.value.renderer.container;return e.appendChild(y.value.root),function(){e.removeChild(y.value.root)}})),r((function(){var e=be((function(e){_(e.state)}),0);return p.current=function(t){var n=t.state,r=t.prevState;(f.value&&r.isOpen!==n.isOpen&&S(n.isOpen),f.value||!n.isOpen||r.isOpen||w(),n.query!==r.query)&&d.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){p.current=void 0}})),r((function(){var e=be((function(){var e=f.value;f.value=d.value.core.environment.matchMedia(d.value.renderer.detachedMediaQuery).matches,e!==f.value?x({}):requestAnimationFrame(w)}),20);return d.value.core.environment.addEventListener("resize",e),function(){d.value.core.environment.removeEventListener("resize",e)}})),r((function(){if(!f.value)return function(){};function e(e){y.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=d.value.core.environment.matchMedia(getComputedStyle(d.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),r((function(){return requestAnimationFrame(w),function(){}})),Jo(Jo({},g),{},{update:x,destroy:function(){o()}})}var na=n(21141);const ra=n(60774);ra.tokenizer.separator=/[\s\-]+/;const oa=ra;var aa=n(689),ia=n.n(aa);function sa(){const e=(0,s.zy)(),t=(0,s.W6)(),{siteConfig:{baseUrl:n}}=(0,ce.A)(),[o,a]=(0,r.useState)({terms:[],isDocsOrBlog:!1});return(0,r.useEffect)((()=>{if(!e.state?.cmfcmfhighlight||0===e.state.cmfcmfhighlight.terms.length)return;a(e.state.cmfcmfhighlight);const{cmfcmfhighlight:n,...r}=e.state;t.replace({...e,state:r})}),[e.state?.cmfcmfhighlight,t,e]),(0,r.useEffect)((()=>{if(0===o.terms.length)return;const e=o.isDocsOrBlog?document.getElementsByTagName("article")[0]:document.getElementsByTagName("main")[0];if(!e)return;const t=new(ia())(e),n={ignoreJoiners:!0};return t.mark(o.terms,n),()=>t.unmark(n)}),[o,n]),null}var ca=n(26503),la=n(61482);function ua(e){let{document:t}=e;const[n,r]=t.sectionRoute.split("#");let o=n;return r&&(o+="#"+r),o}const pa={documents:[],index:oa((function(){this.ref("id"),this.field("title"),this.field("content")}))};const da=()=>{const e=(0,B.A)(),[t,o]=(0,r.useState)((()=>!!e&&"dark"===document.documentElement.getAttribute("data-theme")));(0,r.useEffect)((()=>{const e=new MutationObserver((()=>{o("dark"===document.documentElement.getAttribute("data-theme"))}));return e.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme"]}),()=>e.disconnect()}),[]);const{siteConfig:{baseUrl:a}}=(0,ce.A)(),{titleBoost:i,contentBoost:l,tagsBoost:u,parentCategoriesBoost:p,indexDocSidebarParentCategories:d,maxSearchResults:f}=(0,ca.P_)("@cmfcmf/docusaurus-search-local"),m=(0,s.W6)(),{tags:h}=function(){const{i18n:e}=(0,ce.A)(),t=n(19802).vF(),r=[la.C,...t];return{locale:e.currentLocale,tags:r}}(),v=(0,r.useRef)(h);(0,r.useEffect)((()=>{v.current=h}),[h]);const g=(0,r.useRef)({}),b=async e=>{const t=g.current[e];switch(t?.state){case"ready":return t;case void 0:{const t=[];g.current[e]={state:"loading",callbacks:t};const n=await async function(e,t){{let r;try{const n=await fetch(`${e}search-index-${t}.json`);if(!n.ok)return pa;r=await n.json()}catch(n){return pa}return{documents:r.documents,index:oa.Index.load(r.index)}}}(a,e);return t.forEach((e=>e(n))),g.current[e]={state:"ready",...n}}case"loading":return new Promise((e=>{t.callbacks.push(e)}))}},y=(0,c.T)({message:"cmfcmf/d-s-l.searchBar.placeholder",description:"Placeholder shown in the searchbar"}),w=(0,r.useRef)(null),_=(0,r.useRef)(null);return(0,r.useEffect)((()=>{if(w.current)return _.current=ta({container:w.current,placeholder:y,renderer:{createElement:r.createElement,Fragment:r.Fragment,render:ge.render},navigator:{navigate(e){let{item:t,itemUrl:n}=e;m.push(n,{cmfcmfhighlight:{terms:t.terms,isDocsOrBlog:"docs"===t.document.type||"blog"===t.document.type}})}},detachedMediaQuery:"",defaultActiveItemId:0,translations:{clearButtonTitle:(0,c.T)({message:"cmfcmf/d-s-l.searchBar.clearButtonTitle",description:"Title of the button to clear the current search input"}),detachedCancelButtonText:(0,c.T)({message:"cmfcmf/d-s-l.searchBar.detachedCancelButtonText",description:"Text of the button to close the detached search window"}),submitButtonTitle:(0,c.T)({message:"cmfcmf/d-s-l.searchBar.submitButtonTitle",description:"Title of the button to submit a new search"})},getSources(e){let{query:t}=e;return[{sourceId:"search-results",templates:{item(e){let{item:t}=e;const n=ua(t);return r.createElement("a",{href:n,className:"aa-ItemLink",onClick:e=>{e.preventDefault(),m.push(n,{cmfcmfhighlight:{terms:t.terms,isDocsOrBlog:"docs"===t.document.type||"blog"===t.document.type}})}},r.createElement("div",{className:"aa-ItemContent"},r.createElement("div",{className:"aa-ItemContentBody"},r.createElement("div",{className:"aa-ItemContentTitle"},t.document.sectionTitle),t.document.pageTitle!==t.document.sectionTitle&&r.createElement("div",{className:"aa-ItemContentDescription"},t.document.pageTitle))),r.createElement("div",{className:"aa-ItemActions"},r.createElement("button",{className:"aa-ItemActionButton aa-DesktopOnly aa-ActiveOnly",type:"button",title:"Select"},r.createElement("svg",{viewBox:"0 0 24 24",width:"20",height:"20",fill:"currentColor"},r.createElement("path",{d:"M18.984 6.984h2.016v6h-15.188l3.609 3.609-1.406 1.406-6-6 6-6 1.406 1.406-3.609 3.609h13.172v-4.031z"})))))},noResults:()=>r.createElement("div",{className:"aa-ItemContent"},r.createElement("div",{className:"aa-ItemContentBody"},(0,c.T)({message:"cmfcmf/d-s-l.searchBar.noResults",description:"message shown if no results are found"})))},getItemUrl(e){let{item:t}=e;return ua(t)},async getItems(){const e=v.current,n=await Promise.all(e.map((e=>b(e)))),r=(e=>ra.tokenizer(e).map((e=>e.str)))(t);return n.flatMap((e=>{let{index:t,documents:n}=e;return t.query((e=>{e.term(r,{fields:["title"],boost:i}),e.term(r,{fields:["title"],boost:i,wildcard:oa.Query.wildcard.TRAILING}),e.term(r,{fields:["content"],boost:l}),e.term(r,{fields:["content"],boost:l,wildcard:oa.Query.wildcard.TRAILING}),e.term(r,{fields:["tags"],boost:u}),e.term(r,{fields:["tags"],boost:u,wildcard:oa.Query.wildcard.TRAILING}),d&&(e.term(r,{fields:["sidebarParentCategories"],boost:p}),e.term(r,{fields:["sidebarParentCategories"],boost:p,wildcard:oa.Query.wildcard.TRAILING}))})).slice(0,f).map((e=>({document:n.find((t=>t.id.toString()===e.ref)),score:e.score,terms:r})))})).sort(((e,t)=>t.score-e.score)).slice(0,f)}}]}}),()=>_.current?.destroy()}),[f]),r.createElement(r.Fragment,null,r.createElement(na.A,null,r.createElement("body",{"data-theme":t?"dark":"light"})),r.createElement(sa,null),r.createElement("div",{className:"dsla-search-wrapper"},r.createElement("div",{className:"dsla-search-field",ref:w,"data-tags":h.join(",")})))},fa={navbarSearchContainer:"navbarSearchContainer_Bca1"};function ma(e){let{children:t,className:n}=e;return(0,u.jsx)("div",{className:(0,o.A)(n,fa.navbarSearchContainer),children:t})}var ha=n(19802),va=n(45357);var ga=n(86457);function ba(e,t){return t.alternateDocVersions[e.name]??function(e){return e.docs.find((t=>t.id===e.mainDocId))}(e)}const ya={default:ae,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:r,queryString:o="",...a}=e;const{i18n:{currentLocale:i,locales:l,localeConfigs:p}}=(0,ce.A)(),d=(0,me.o)(),{search:f,hash:m}=(0,s.zy)(),h=[...n,...l.map((e=>{const n=`${`pathname://${d.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}${o}`;return{label:p[e].label,lang:p[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...r],v=t?(0,c.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):p[i].label;return(0,u.jsx)(fe,{...a,mobile:t,label:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(he,{className:ve}),v]}),items:h})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,u.jsx)(ma,{className:n,children:(0,u.jsx)(da,{})})},dropdown:fe,html:function(e){let{value:t,className:n,mobile:r=!1,isDropdownItem:a=!1}=e;const i=a?"li":"div";return(0,u.jsx)(i,{className:(0,o.A)({navbar__item:!r&&!a,"menu__list-item":r},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:r,...o}=e;const{activeDoc:a}=(0,ha.zK)(r),i=(0,va.QB)(t,r),s=a?.path===i?.path;return null===i||i.unlisted&&!s?null:(0,u.jsx)(ae,{exact:!0,...o,isActive:()=>s||!!a?.sidebar&&a.sidebar===i.sidebar,label:n??i.id,to:i.path})},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:r,...o}=e;const{activeDoc:a}=(0,ha.zK)(r),i=(0,va.fW)(t,r).link;if(!i)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return(0,u.jsx)(ae,{exact:!0,...o,isActive:()=>a?.sidebar===t,label:n??i.label,to:i.path})},docsVersion:function(e){let{label:t,to:n,docsPluginId:r,...o}=e;const a=(0,va.Vd)(r)[0],i=t??a.label,s=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(a).path;return(0,u.jsx)(ae,{...o,label:i,to:s})},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:r,dropdownItemsBefore:o,dropdownItemsAfter:a,...i}=e;const{search:l,hash:p}=(0,s.zy)(),d=(0,ha.zK)(n),f=(0,ha.jh)(n),{savePreferredVersionName:m}=(0,ga.g1)(n),h=[...o,...f.map((function(e){const t=ba(e,d);return{label:e.label,to:`${t.path}${l}${p}`,isActive:()=>e===d.activeVersion,onClick:()=>m(e.name)}})),...a],v=(0,va.Vd)(n)[0],g=t&&h.length>1?(0,c.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):v.label,b=t&&h.length>1?void 0:ba(v,d).path;return h.length<=1?(0,u.jsx)(ae,{...i,mobile:t,label:g,to:b,isActive:r?()=>!1:void 0}):(0,u.jsx)(fe,{...i,mobile:t,label:g,to:b,items:h,isActive:r?()=>!1:void 0})}},wa=ya;function _a(e){let{type:t,...n}=e;const r=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=wa[r];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return(0,u.jsx)(o,{...n})}function xa(){const e=(0,C.M)(),t=(0,w.p)().navbar.items;return(0,u.jsx)("ul",{className:"menu__list",children:t.map(((t,n)=>(0,r.createElement)(_a,{mobile:!0,...t,onClick:()=>e.toggle(),key:n})))})}function Sa(e){return(0,u.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,u.jsx)(c.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function ka(){const e=0===(0,w.p)().navbar.items.length,t=D();return(0,u.jsxs)(u.Fragment,{children:[!e&&(0,u.jsx)(Sa,{onClick:()=>t.hide()}),t.content]})}function Ea(){const e=(0,C.M)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?(0,u.jsx)(F,{header:(0,u.jsx)(Y,{}),primaryMenu:(0,u.jsx)(xa,{}),secondaryMenu:(0,u.jsx)(ka,{})}):null}const Oa={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function ja(e){return(0,u.jsx)("div",{role:"presentation",...e,className:(0,o.A)("navbar-sidebar__backdrop",e.className)})}function Pa(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:a}}=(0,w.p)(),i=(0,C.M)(),{navbarRef:s,isNavbarVisible:p}=function(e){const[t,n]=(0,r.useState)(e),o=(0,r.useRef)(!1),a=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(a.current=e.getBoundingClientRect().height)}),[]);return(0,A.Mq)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i<a.current)return void n(!0);if(o.current)return void(o.current=!1);const s=r?.scrollY,c=document.documentElement.scrollHeight-a.current,l=window.innerHeight;s&&i>=s?n(!1):i+l<c&&n(!0)})),(0,l.$)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return o.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return(0,u.jsxs)("nav",{ref:s,"aria-label":(0,c.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,o.A)("navbar","navbar--fixed-top",n&&[Oa.navbarHideable,!p&&Oa.navbarHidden],{"navbar--dark":"dark"===a,"navbar--primary":"primary"===a,"navbar-sidebar--show":i.shown}),children:[t,(0,u.jsx)(ja,{onClick:i.toggle}),(0,u.jsx)(Ea,{})]})}var Ca=n(34176);const Aa="right";function Ta(e){let{width:t=30,height:n=30,className:r,...o}=e;return(0,u.jsx)("svg",{className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...o,children:(0,u.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function Ia(){const{toggle:e,shown:t}=(0,C.M)();return(0,u.jsx)("button",{onClick:e,"aria-label":(0,c.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,u.jsx)(Ta,{})})}const Na={colorModeToggle:"colorModeToggle_DEke"};function La(e){let{items:t}=e;return(0,u.jsx)(u.Fragment,{children:t.map(((e,t)=>(0,u.jsx)(Ca.k2,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,u.jsx)(_a,{...e})},t)))})}function Ra(e){let{left:t,right:n}=e;return(0,u.jsxs)("div",{className:"navbar__inner",children:[(0,u.jsx)("div",{className:"navbar__items",children:t}),(0,u.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function Da(){const e=(0,C.M)(),t=(0,w.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??Aa)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return(0,u.jsx)(Ra,{left:(0,u.jsxs)(u.Fragment,{children:[!e.disabled&&(0,u.jsx)(Ia,{}),(0,u.jsx)(G,{}),(0,u.jsx)(La,{items:n})]}),right:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(La,{items:r}),(0,u.jsx)(Q,{className:Na.colorModeToggle}),!o&&(0,u.jsx)(ma,{children:(0,u.jsx)(da,{})})]})})}function Fa(){return(0,u.jsx)(Pa,{children:(0,u.jsx)(Da,{})})}function Ma(e){let{item:t}=e;const{to:n,href:r,label:o,prependBaseUrlToHref:a,...i}=t,s=(0,X.Ay)(n),c=(0,X.Ay)(r,{forcePrependBaseUrl:!0});return(0,u.jsxs)(Z.A,{className:"footer__link-item",...r?{href:a?c:r}:{to:s},...i,children:[o,r&&!(0,J.A)(r)&&(0,u.jsx)(te.A,{})]})}function Ba(e){let{item:t}=e;return t.html?(0,u.jsx)("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):(0,u.jsx)("li",{className:"footer__item",children:(0,u.jsx)(Ma,{item:t})},t.href??t.to)}function za(e){let{column:t}=e;return(0,u.jsxs)("div",{className:"col footer__col",children:[(0,u.jsx)("div",{className:"footer__title",children:t.title}),(0,u.jsx)("ul",{className:"footer__items clean-list",children:t.items.map(((e,t)=>(0,u.jsx)(Ba,{item:e},t)))})]})}function $a(e){let{columns:t}=e;return(0,u.jsx)("div",{className:"row footer__links",children:t.map(((e,t)=>(0,u.jsx)(za,{column:e},t)))})}function Ua(){return(0,u.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function Ha(e){let{item:t}=e;return t.html?(0,u.jsx)("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):(0,u.jsx)(Ma,{item:t})}function Va(e){let{links:t}=e;return(0,u.jsx)("div",{className:"footer__links text--center",children:(0,u.jsx)("div",{className:"footer__links",children:t.map(((e,n)=>(0,u.jsxs)(r.Fragment,{children:[(0,u.jsx)(Ha,{item:e}),t.length!==n+1&&(0,u.jsx)(Ua,{})]},n)))})})}function Wa(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?(0,u.jsx)($a,{columns:t}):(0,u.jsx)(Va,{links:t})}var Qa=n(40975);const qa="footerLogoLink_BH7S";function Ga(e){let{logo:t}=e;const{withBaseUrl:n}=(0,X.hH)(),r={light:n(t.src),dark:n(t.srcDark??t.src)};return(0,u.jsx)(Qa.A,{className:(0,o.A)("footer__logo",t.className),alt:t.alt,sources:r,width:t.width,height:t.height,style:t.style})}function Ka(e){let{logo:t}=e;return t.href?(0,u.jsx)(Z.A,{href:t.href,className:qa,target:t.target,children:(0,u.jsx)(Ga,{logo:t})}):(0,u.jsx)(Ga,{logo:t})}function Ya(e){let{copyright:t}=e;return(0,u.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Za(e){let{style:t,links:n,logo:r,copyright:a}=e;return(0,u.jsx)("footer",{className:(0,o.A)("footer",{"footer--dark":"dark"===t}),children:(0,u.jsxs)("div",{className:"container container-fluid",children:[n,(r||a)&&(0,u.jsxs)("div",{className:"footer__bottom text--center",children:[r&&(0,u.jsx)("div",{className:"margin-bottom--sm",children:r}),a]})]})})}function Xa(){const{footer:e}=(0,w.p)();if(!e)return null;const{copyright:t,links:n,logo:r,style:o}=e;return(0,u.jsx)(Za,{style:o,links:n&&n.length>0&&(0,u.jsx)(Wa,{links:n}),logo:r&&(0,u.jsx)(Ka,{logo:r}),copyright:t&&(0,u.jsx)(Ya,{copyright:t})})}const Ja=r.memo(Xa),ei=(0,T.fM)([M.a,_.o,A.Tv,ga.VQ,i.Jx,function(e){let{children:t}=e;return(0,u.jsx)(I.y_,{children:(0,u.jsx)(C.e,{children:(0,u.jsx)(L,{children:t})})})}]);function ti(e){let{children:t}=e;return(0,u.jsx)(ei,{children:t})}var ni=n(85225);function ri(e){let{error:t,tryAgain:n}=e;return(0,u.jsx)("main",{className:"container margin-vert--xl",children:(0,u.jsx)("div",{className:"row",children:(0,u.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,u.jsx)(ni.A,{as:"h1",className:"hero__title",children:(0,u.jsx)(c.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,u.jsx)("div",{className:"margin-vert--lg",children:(0,u.jsx)(Ca.a2,{onClick:n,className:"button button--primary shadow--lw"})}),(0,u.jsx)("hr",{}),(0,u.jsx)("div",{className:"margin-vert--md",children:(0,u.jsx)(Ca.bq,{error:t})})]})})})}const oi={mainWrapper:"mainWrapper_z2l0"};function ai(e){const{children:t,noFooter:n,wrapperClassName:r,title:s,description:c}=e;return(0,g.J)(),(0,u.jsxs)(ti,{children:[(0,u.jsx)(i.be,{title:s,description:c}),(0,u.jsx)(y,{}),(0,u.jsx)(P,{}),(0,u.jsx)(Fa,{}),(0,u.jsx)("div",{id:p,className:(0,o.A)(v.G.wrapper.main,oi.mainWrapper,r),children:(0,u.jsx)(a.A,{fallback:e=>(0,u.jsx)(ri,{...e}),children:t})}),!n&&(0,u.jsx)(Ja,{})]})}},20020:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});n(96540);var r=n(14783),o=n(98180),a=n(97639),i=n(86957),s=n(40975),c=n(74848);function l(e){let{logo:t,alt:n,imageClassName:r}=e;const a={light:(0,o.Ay)(t.src),dark:(0,o.Ay)(t.srcDark||t.src)},i=(0,c.jsx)(s.A,{className:t.className,sources:a,height:t.height,width:t.width,alt:n,style:t.style});return r?(0,c.jsx)("div",{className:r,children:i}):i}function u(e){const{siteConfig:{title:t}}=(0,a.A)(),{navbar:{title:n,logo:s}}=(0,i.p)(),{imageClassName:u,titleClassName:p,...d}=e,f=(0,o.Ay)(s?.href||"/"),m=n?"":t,h=s?.alt??m;return(0,c.jsxs)(r.A,{to:f,...d,...s?.target&&{target:s.target},children:[s&&(0,c.jsx)(l,{logo:s,alt:h,imageClassName:u}),null!=n&&(0,c.jsx)("b",{className:p,children:n})]})}},51210:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(96540);var r=n(21141),o=n(74848);function a(e){let{locale:t,version:n,tag:a}=e;const i=t;return(0,o.jsxs)(r.A,{children:[t&&(0,o.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,o.jsx)("meta",{name:"docusaurus_version",content:n}),a&&(0,o.jsx)("meta",{name:"docusaurus_tag",content:a}),i&&(0,o.jsx)("meta",{name:"docsearch:language",content:i}),n&&(0,o.jsx)("meta",{name:"docsearch:version",content:n}),a&&(0,o.jsx)("meta",{name:"docsearch:docusaurus_tag",content:a})]})}},40975:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var r=n(96540),o=n(34164),a=n(11062),i=n(7710);const s={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var c=n(74848);function l(e){let{className:t,children:n}=e;const l=(0,a.A)(),{colorMode:u}=(0,i.G)();return(0,c.jsx)(c.Fragment,{children:(l?"dark"===u?["dark"]:["light"]:["light","dark"]).map((e=>{const a=n({theme:e,className:(0,o.A)(t,s.themedComponent,s[`themedComponent--${e}`])});return(0,c.jsx)(r.Fragment,{children:a},e)}))})}function u(e){const{sources:t,className:n,alt:r,...o}=e;return(0,c.jsx)(l,{className:n,children:e=>{let{theme:n,className:a}=e;return(0,c.jsx)("img",{src:t[n],alt:r,className:a,...o})}})}},94549:(e,t,n)=>{"use strict";n.d(t,{N:()=>g,u:()=>l});var r=n(96540),o=n(31712),a=n(36494),i=n(36350),s=n(74848);const c="ease-in-out";function l(e){let{initialState:t}=e;const[n,o]=(0,r.useState)(t??!1),a=(0,r.useCallback)((()=>{o((e=>!e))}),[]);return{collapsed:n,setCollapsed:o,toggleCollapsed:a}}const u={display:"none",overflow:"hidden",height:"0px"},p={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?u:p;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:o}=e;const a=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=e.scrollHeight,n=o?.duration??function(e){if((0,i.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${o?.easing??c}`,height:`${t}px`}}function s(){const t=r();e.style.transition=t.transition,e.style.height=t.height}if(!a.current)return d(e,n),void(a.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(s(),requestAnimationFrame((()=>{e.style.height=u.height,e.style.overflow=u.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{s()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,o])}function m(e){if(!o.A.canUseDOM)return e?u:p}function h(e){let{as:t="div",collapsed:n,children:o,animation:a,onCollapseTransitionEnd:i,className:c,disableSSRStyle:l}=e;const u=(0,r.useRef)(null);return f({collapsibleRef:u,collapsed:n,animation:a}),(0,s.jsx)(t,{ref:u,style:l?void 0:m(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(u.current,n),i?.(n))},className:c,children:o})}function v(e){let{collapsed:t,...n}=e;const[o,i]=(0,r.useState)(!t),[c,l]=(0,r.useState)(t);return(0,a.A)((()=>{t||i(!0)}),[t]),(0,a.A)((()=>{o&&l(t)}),[o,t]),o?(0,s.jsx)(h,{...n,collapsed:c}):null}function g(e){let{lazy:t,...n}=e;const r=t?v:h;return(0,s.jsx)(r,{...n})}},40002:(e,t,n)=>{"use strict";n.d(t,{M:()=>h,o:()=>m});var r=n(96540),o=n(11062),a=n(69900),i=n(4799),s=n(86957),c=n(74848);const l=(0,a.Wf)("docusaurus.announcement.dismiss"),u=(0,a.Wf)("docusaurus.announcement.id"),p=()=>"true"===l.get(),d=e=>l.set(String(e)),f=r.createContext(null);function m(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,s.p)(),t=(0,o.A)(),[n,a]=(0,r.useState)((()=>!!t&&p()));(0,r.useEffect)((()=>{a(p())}),[]);const i=(0,r.useCallback)((()=>{d(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&d(!1),!r&&p()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return(0,c.jsx)(f.Provider,{value:n,children:t})}function h(){const e=(0,r.useContext)(f);if(!e)throw new i.dV("AnnouncementBarProvider");return e}},7710:(e,t,n)=>{"use strict";n.d(t,{G:()=>g,a:()=>v});var r=n(96540),o=n(31712),a=n(4799),i=n(69900),s=n(86957),c=n(74848);const l=r.createContext(void 0),u="theme",p=(0,i.Wf)(u),d={light:"light",dark:"dark"},f=e=>e===d.dark?d.dark:d.light,m=e=>o.A.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),h=e=>{p.set(f(e))};function v(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,s.p)(),[o,a]=(0,r.useState)(m(e));(0,r.useEffect)((()=>{t&&p.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:o=!0}=r;t?(a(t),o&&h(t)):(a(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),p.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(o))}),[o]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=p.get();null!==t&&i(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const c=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||c.current?c.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:o,setColorMode:i,get isDarkTheme(){return o===d.dark},setLightTheme(){i(d.light)},setDarkTheme(){i(d.dark)}})),[o,i])}();return(0,c.jsx)(l.Provider,{value:n,children:t})}function g(){const e=(0,r.useContext)(l);if(null==e)throw new a.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},61938:(e,t,n)=>{"use strict";n.d(t,{M:()=>f,e:()=>d});var r=n(96540),o=n(70763),a=n(82216),i=n(62814),s=n(86957),c=n(4799),l=n(74848);const u=r.createContext(void 0);function p(){const e=function(){const e=(0,o.YL)(),{items:t}=(0,s.p)().navbar;return 0===t.length&&!e.component}(),t=(0,a.l)(),n=!e&&"mobile"===t,[c,l]=(0,r.useState)(!1);(0,i.$Z)((()=>{if(c)return l(!1),!1}));const u=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:c})),[e,n,u,c])}function d(e){let{children:t}=e;const n=p();return(0,l.jsx)(u.Provider,{value:n,children:t})}function f(){const e=r.useContext(u);if(void 0===e)throw new c.dV("NavbarMobileSidebarProvider");return e}},70763:(e,t,n)=>{"use strict";n.d(t,{GX:()=>l,YL:()=>c,y_:()=>s});var r=n(96540),o=n(4799),a=n(74848);const i=r.createContext(null);function s(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return(0,a.jsx)(i.Provider,{value:n,children:t})}function c(){const e=(0,r.useContext)(i);if(!e)throw new o.dV("NavbarSecondaryMenuContentProvider");return e[0]}function l(e){let{component:t,props:n}=e;const a=(0,r.useContext)(i);if(!a)throw new o.dV("NavbarSecondaryMenuContentProvider");const[,s]=a,c=(0,o.Be)(n);return(0,r.useEffect)((()=>{s({component:t,props:c})}),[s,t,c]),(0,r.useEffect)((()=>()=>s({component:null,props:null})),[s]),null}},19503:(e,t,n)=>{"use strict";n.d(t,{w:()=>o,J:()=>a});var r=n(96540);const o="navigation-with-keyboard";function a(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},82216:(e,t,n)=>{"use strict";n.d(t,{l:()=>s});var r=n(96540),o=n(31712);const a={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function s(e){let{desktopBreakpoint:t=i}=void 0===e?{}:e;const[n,s]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function e(){s(function(e){if(!o.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>e?a.desktop:a.mobile}(t))}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[t]),n}},18630:(e,t,n)=>{"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",blogAuthorsListPage:"blog-authors-list-page",blogAuthorsPostsPage:"blog-authors-posts-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",draftBanner:"theme-draft-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{blogFooterTagsRow:"theme-blog-footer-tags-row",blogFooterEditMetaRow:"theme-blog-footer-edit-meta-row"},pages:{pageFooterEditMetaRow:"theme-pages-footer-edit-meta-row"}}},36350:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>r})},34176:(e,t,n)=>{"use strict";n.d(t,{bq:()=>u,MN:()=>l,a2:()=>c,k2:()=>p});var r=n(96540),o=n(23230),a=n(64609);const i={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};var s=n(74848);function c(e){return(0,s.jsx)("button",{type:"button",...e,children:(0,s.jsx)(o.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function l(e){let{error:t,tryAgain:n}=e;return(0,s.jsxs)("div",{className:i.errorBoundaryFallback,children:[(0,s.jsx)("p",{children:t.message}),(0,s.jsx)(c,{onClick:n})]})}function u(e){let{error:t}=e;const n=(0,a.rA)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,s.jsx)("p",{className:i.errorBoundaryError,children:n})}class p extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}},62814:(e,t,n)=>{"use strict";n.d(t,{$Z:()=>i,aZ:()=>c});var r=n(96540),o=n(56347),a=n(4799);function i(e){!function(e){const t=(0,o.W6)(),n=(0,a._q)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function s(e){const t=(0,o.W6)();return(0,r.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}function c(e){return s((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}},45167:(e,t,n)=>{"use strict";function r(e,t){return void 0===t&&(t=(e,t)=>e===t),e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function o(e){return Array.from(new Set(e))}n.d(t,{XI:()=>r,sb:()=>o})},69817:(e,t,n)=>{"use strict";n.d(t,{e3:()=>f,be:()=>p,Jx:()=>m});var r=n(96540),o=n(34164),a=n(21141),i=n(23363);function s(){const e=r.useContext(i.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var c=n(98180),l=n(97639);var u=n(74848);function p(e){let{title:t,description:n,keywords:r,image:o,children:i}=e;const s=function(e){const{siteConfig:t}=(0,l.A)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:p}=(0,c.hH)(),d=o?p(o,{absolute:!0}):void 0;return(0,u.jsxs)(a.A,{children:[t&&(0,u.jsx)("title",{children:s}),t&&(0,u.jsx)("meta",{property:"og:title",content:s}),n&&(0,u.jsx)("meta",{name:"description",content:n}),n&&(0,u.jsx)("meta",{property:"og:description",content:n}),r&&(0,u.jsx)("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),d&&(0,u.jsx)("meta",{property:"og:image",content:d}),d&&(0,u.jsx)("meta",{name:"twitter:image",content:d}),i]})}const d=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(d),s=(0,o.A)(i,t);return(0,u.jsxs)(d.Provider,{value:s,children:[(0,u.jsx)(a.A,{children:(0,u.jsx)("html",{className:s})}),n]})}function m(e){let{children:t}=e;const n=s(),r=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const a=`plugin-id-${n.plugin.id}`;return(0,u.jsx)(f,{className:(0,o.A)(r,a),children:t})}},4799:(e,t,n)=>{"use strict";n.d(t,{Be:()=>l,ZC:()=>s,_q:()=>i,dV:()=>c,fM:()=>u});var r=n(96540),o=n(36494),a=n(74848);function i(e){const t=(0,r.useRef)(e);return(0,o.A)((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function s(e){const t=(0,r.useRef)();return(0,o.A)((()=>{t.current=e})),t.current}class c extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function l(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function u(e){return t=>{let{children:n}=t;return(0,a.jsx)(a.Fragment,{children:e.reduceRight(((e,t)=>(0,a.jsx)(t,{children:e})),n)})}}},80260:(e,t,n)=>{"use strict";n.d(t,{Dt:()=>s,ys:()=>i});var r=n(96540),o=n(92413),a=n(97639);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function s(){const{baseUrl:e}=(0,a.A)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function o(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(o).flatMap((e=>e.routes??[])))}(n)}({routes:o.A,baseUrl:e})),[e])}},24245:(e,t,n)=>{"use strict";n.d(t,{Mq:()=>f,Tv:()=>u,a_:()=>m,gk:()=>h});var r=n(96540),o=n(31712),a=n(11062),i=n(36494),s=n(4799),c=n(74848);const l=r.createContext(void 0);function u(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return(0,c.jsx)(l.Provider,{value:n,children:t})}function p(){const e=(0,r.useContext)(l);if(null==e)throw new s.dV("ScrollControllerProvider");return e}const d=()=>o.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function f(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=p(),o=(0,r.useRef)(d()),a=(0,s._q)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=d();a(e,o.current),o.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[a,n,...t])}function m(){const e=p(),t=function(){const e=(0,r.useRef)({elem:null,top:0}),t=(0,r.useCallback)((t=>{e.current={elem:t,top:t.getBoundingClientRect().top}}),[]),n=(0,r.useCallback)((()=>{const{current:{elem:t,top:n}}=e;if(!t)return{restored:!1};const r=t.getBoundingClientRect().top-n;return r&&window.scrollBy({left:0,top:r}),e.current={elem:null,top:0},{restored:0!==r}}),[]);return(0,r.useMemo)((()=>({save:t,restore:n})),[n,t])}(),n=(0,r.useRef)(void 0),o=(0,r.useCallback)((r=>{t.save(r),e.disableScrollEvents(),n.current=()=>{const{restored:r}=t.restore();if(n.current=void 0,r){const t=()=>{e.enableScrollEvents(),window.removeEventListener("scroll",t)};window.addEventListener("scroll",t)}else e.enableScrollEvents()}}),[e,t]);return(0,i.A)((()=>{queueMicrotask((()=>n.current?.()))})),{blockElementScrollPositionUntilNextRender:o}}function h(){const e=(0,r.useRef)(null),t=(0,a.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const o=document.documentElement.scrollTop;(n&&o>e||!n&&o<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(o-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},61482:(e,t,n)=>{"use strict";n.d(t,{C:()=>r});const r="default"},69900:(e,t,n)=>{"use strict";n.d(t,{Wf:()=>u,Dv:()=>p});var r=n(96540);const o=JSON.parse('{"N":"localStorage","M":""}'),a=o.N;function i(e){let{key:t,oldValue:n,newValue:r,storage:o}=e;if(n===r)return;const a=document.createEvent("StorageEvent");a.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,o),window.dispatchEvent(a)}function s(e){if(void 0===e&&(e=a),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,c||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),c=!0),null}var t}let c=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function u(e,t){const n=`${e}${o.M}`;if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(n);const r=s(t?.persistence);return null===r?l:{get:()=>{try{return r.getItem(n)}catch(e){return console.error(`Docusaurus storage error, can't get key=${n}`,e),null}},set:e=>{try{const t=r.getItem(n);r.setItem(n,e),i({key:n,oldValue:t,newValue:e,storage:r})}catch(t){console.error(`Docusaurus storage error, can't set ${n}=${e}`,t)}},del:()=>{try{const e=r.getItem(n);r.removeItem(n),i({key:n,oldValue:e,newValue:null,storage:r})}catch(e){console.error(`Docusaurus storage error, can't delete key=${n}`,e)}},listen:e=>{try{const t=t=>{t.storageArea===r&&t.key===n&&e(t)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)}catch(t){return console.error(`Docusaurus storage error, can't listen for changes of key=${n}`,t),()=>{}}}}}function p(e,t){const n=(0,r.useRef)((()=>null===e?l:u(e,t))).current(),o=(0,r.useCallback)((e=>"undefined"==typeof window?()=>{}:n.listen(e)),[n]);return[(0,r.useSyncExternalStore)(o,(()=>"undefined"==typeof window?null:n.get()),(()=>null)),n]}},2098:(e,t,n)=>{"use strict";n.d(t,{o:()=>i});var r=n(97639),o=n(56347),a=n(64609);function i(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:i,currentLocale:s}}=(0,r.A)(),{pathname:c}=(0,o.zy)(),l=(0,a.Ks)(c,{trailingSlash:n,baseUrl:e}),u=s===i?e:e.replace(`/${s}/`,"/"),p=l.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:r}=e;return`${r?t:""}${function(e){return e===i?`${u}`:`${u}${e}/`}(n)}${p}`}}}},54067:(e,t,n)=>{"use strict";n.d(t,{$:()=>i});var r=n(96540),o=n(56347),a=n(4799);function i(e){const t=(0,o.zy)(),n=(0,a.ZC)(t),i=(0,a._q)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},86957:(e,t,n)=>{"use strict";n.d(t,{p:()=>o});var r=n(97639);function o(){return(0,r.A)().siteConfig.themeConfig}},44356:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addTrailingSlash=o,t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[i]=e.split(/[#?]/),s="/"===i||i===r?i:(c=i,l=n,l?o(c):a(c));var c,l;return e.replace(i,s)},t.addLeadingSlash=function(e){return(0,r.addPrefix)(e,"/")},t.removeTrailingSlash=a;const r=n(50835);function o(e){return e.endsWith("/")?e:`${e}/`}function a(e){return(0,r.removeSuffix)(e,"/")}},68274:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=function e(t){if(t.cause)return[t,...e(t.cause)];return[t]}},64609:(e,t,n)=>{"use strict";t.rA=t.Ks=void 0;const r=n(31635);var o=n(44356);Object.defineProperty(t,"Ks",{enumerable:!0,get:function(){return r.__importDefault(o).default}});var a=n(50835);var i=n(68274);Object.defineProperty(t,"rA",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},50835:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addPrefix=function(e,t){return e.startsWith(t)?e:`${t}${e}`},t.removeSuffix=function(e,t){if(""===t)return e;return e.endsWith(t)?e.slice(0,-t.length):e},t.addSuffix=function(e,t){return e.endsWith(t)?e:`${e}${t}`},t.removePrefix=function(e,t){return e.startsWith(t)?e.slice(t.length):e}},31513:(e,t,n)=>{"use strict";n.d(t,{zR:()=>w,TM:()=>O,yJ:()=>f,sC:()=>P,AO:()=>d});var r=n(58168);function o(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,o=e.length;r<o;n+=1,r+=1)e[n]=e[r];e.pop()}const i=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],i=t&&t.split("/")||[],s=e&&o(e),c=t&&o(t),l=s||c;if(e&&o(e)?i=r:r.length&&(i.pop(),i=i.concat(r)),!i.length)return"/";if(i.length){var u=i[i.length-1];n="."===u||".."===u||""===u}else n=!1;for(var p=0,d=i.length;d>=0;d--){var f=i[d];"."===f?a(i,d):".."===f?(a(i,d),p++):p&&(a(i,d),p--)}if(!l)for(;p--;p)i.unshift("..");!l||""===i[0]||i[0]&&o(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var s=n(11561);function c(e){return"/"===e.charAt(0)?e:"/"+e}function l(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function p(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function d(e){var t=e.pathname,n=e.search,r=e.hash,o=t||"/";return n&&"?"!==n&&(o+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(o+="#"===r.charAt(0)?r:"#"+r),o}function f(e,t,n,o){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",o=t.indexOf("#");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf("?");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=(0,r.A)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(s){throw s instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):s}return n&&(a.key=n),o?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname="/"),a}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function v(e,t){t(window.confirm(e))}var g="popstate",b="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),h||(0,s.A)(!1);var t,n=window.history,o=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,a=!(-1===window.navigator.userAgent.indexOf("Trident")),i=e,l=i.forceRefresh,w=void 0!==l&&l,_=i.getUserConfirmation,x=void 0===_?v:_,S=i.keyLength,k=void 0===S?6:S,E=e.basename?p(c(e.basename)):"";function O(e){var t=e||{},n=t.key,r=t.state,o=window.location,a=o.pathname+o.search+o.hash;return E&&(a=u(a,E)),f(a,r,n)}function j(){return Math.random().toString(36).substr(2,k)}var P=m();function C(e){(0,r.A)($,e),$.length=n.length,P.notifyListeners($.location,$.action)}function A(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||N(O(e.state))}function T(){N(O(y()))}var I=!1;function N(e){if(I)I=!1,C();else{P.confirmTransitionTo(e,"POP",x,(function(t){t?C({action:"POP",location:e}):function(e){var t=$.location,n=R.indexOf(t.key);-1===n&&(n=0);var r=R.indexOf(e.key);-1===r&&(r=0);var o=n-r;o&&(I=!0,F(o))}(e)}))}}var L=O(y()),R=[L.key];function D(e){return E+d(e)}function F(e){n.go(e)}var M=0;function B(e){1===(M+=e)&&1===e?(window.addEventListener(g,A),a&&window.addEventListener(b,T)):0===M&&(window.removeEventListener(g,A),a&&window.removeEventListener(b,T))}var z=!1;var $={length:n.length,action:"POP",location:L,createHref:D,push:function(e,t){var r="PUSH",a=f(e,t,j(),$.location);P.confirmTransitionTo(a,r,x,(function(e){if(e){var t=D(a),i=a.key,s=a.state;if(o)if(n.pushState({key:i,state:s},null,t),w)window.location.href=t;else{var c=R.indexOf($.location.key),l=R.slice(0,c+1);l.push(a.key),R=l,C({action:r,location:a})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,j(),$.location);P.confirmTransitionTo(a,r,x,(function(e){if(e){var t=D(a),i=a.key,s=a.state;if(o)if(n.replaceState({key:i,state:s},null,t),w)window.location.replace(t);else{var c=R.indexOf($.location.key);-1!==c&&(R[c]=a.key),C({action:r,location:a})}else window.location.replace(t)}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=P.setPrompt(e);return z||(B(1),z=!0),function(){return z&&(z=!1,B(-1)),t()}},listen:function(e){var t=P.appendListener(e);return B(1),function(){B(-1),t()}}};return $}var _="hashchange",x={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+l(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:l,decodePath:c},slash:{encodePath:c,decodePath:c}};function S(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function k(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function E(e){window.location.replace(S(window.location.href)+"#"+e)}function O(e){void 0===e&&(e={}),h||(0,s.A)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),o=n.getUserConfirmation,a=void 0===o?v:o,i=n.hashType,l=void 0===i?"slash":i,g=e.basename?p(c(e.basename)):"",b=x[l],y=b.encodePath,w=b.decodePath;function O(){var e=w(k());return g&&(e=u(e,g)),f(e)}var j=m();function P(e){(0,r.A)(z,e),z.length=t.length,j.notifyListeners(z.location,z.action)}var C=!1,A=null;function T(){var e,t,n=k(),r=y(n);if(n!==r)E(r);else{var o=O(),i=z.location;if(!C&&(t=o,(e=i).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(A===d(o))return;A=null,function(e){if(C)C=!1,P();else{var t="POP";j.confirmTransitionTo(e,t,a,(function(n){n?P({action:t,location:e}):function(e){var t=z.location,n=R.lastIndexOf(d(t));-1===n&&(n=0);var r=R.lastIndexOf(d(e));-1===r&&(r=0);var o=n-r;o&&(C=!0,D(o))}(e)}))}}(o)}}var I=k(),N=y(I);I!==N&&E(N);var L=O(),R=[d(L)];function D(e){t.go(e)}var F=0;function M(e){1===(F+=e)&&1===e?window.addEventListener(_,T):0===F&&window.removeEventListener(_,T)}var B=!1;var z={length:t.length,action:"POP",location:L,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=S(window.location.href)),n+"#"+y(g+d(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,z.location);j.confirmTransitionTo(r,n,a,(function(e){if(e){var t=d(r),o=y(g+t);if(k()!==o){A=t,function(e){window.location.hash=e}(o);var a=R.lastIndexOf(d(z.location)),i=R.slice(0,a+1);i.push(t),R=i,P({action:n,location:r})}else P()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,z.location);j.confirmTransitionTo(r,n,a,(function(e){if(e){var t=d(r),o=y(g+t);k()!==o&&(A=t,E(o));var a=R.indexOf(d(z.location));-1!==a&&(R[a]=t),P({action:n,location:r})}}))},go:D,goBack:function(){D(-1)},goForward:function(){D(1)},block:function(e){void 0===e&&(e=!1);var t=j.setPrompt(e);return B||(M(1),B=!0),function(){return B&&(B=!1,M(-1)),t()}},listen:function(e){var t=j.appendListener(e);return M(1),function(){M(-1),t()}}};return z}function j(e,t,n){return Math.min(Math.max(e,t),n)}function P(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,o=t.initialEntries,a=void 0===o?["/"]:o,i=t.initialIndex,s=void 0===i?0:i,c=t.keyLength,l=void 0===c?6:c,u=m();function p(e){(0,r.A)(w,e),w.length=w.entries.length,u.notifyListeners(w.location,w.action)}function h(){return Math.random().toString(36).substr(2,l)}var v=j(s,0,a.length-1),g=a.map((function(e){return f(e,void 0,"string"==typeof e?h():e.key||h())})),b=d;function y(e){var t=j(w.index+e,0,w.entries.length-1),r=w.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?p({action:"POP",location:r,index:t}):p()}))}var w={length:g.length,action:"POP",location:g[v],index:v,entries:g,createHref:b,push:function(e,t){var r="PUSH",o=f(e,t,h(),w.location);u.confirmTransitionTo(o,r,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,o):n.push(o),p({action:r,location:o,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",o=f(e,t,h(),w.location);u.confirmTransitionTo(o,r,n,(function(e){e&&(w.entries[w.index]=o,p({action:r,location:o}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t<w.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return w}},4146:(e,t,n)=>{"use strict";var r=n(44363),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},s={};function c(e){return r.isMemo(e)?i:s[e.$$typeof]||o}s[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[r.Memo]=i;var l=Object.defineProperty,u=Object.getOwnPropertyNames,p=Object.getOwnPropertySymbols,d=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var o=f(n);o&&o!==m&&e(t,o,r)}var i=u(n);p&&(i=i.concat(p(n)));for(var s=c(t),h=c(n),v=0;v<i.length;++v){var g=i[v];if(!(a[g]||r&&r[g]||h&&h[g]||s&&s[g])){var b=d(n,g);try{l(t,g,b)}catch(y){}}}}return t}},20311:e=>{"use strict";e.exports=function(e,t,n,r,o,a,i,s){if(!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,o,a,i,s],u=0;(c=new Error(t.replace(/%s/g,(function(){return l[u++]})))).name="Invariant Violation"}throw c.framesToPop=1,c}}},64634:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},689:function(e){e.exports=function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),r=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o=function(){function e(n){var r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=o,this.iframesTimeout=a}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach((function(t){var n=e.filter((function(e){return e.contains(t)})).length>0;-1!==e.indexOf(t)||n||e.push(t)})),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var o=e.contentWindow;if(r=o.document,!o||!r)throw new Error("iframe inaccessible")}catch(a){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,o=!1,a=null,i=function i(){if(!o){o=!0,clearTimeout(a);try{r.isIframeBlank(e)||(e.removeEventListener("load",i),r.getIframeContents(e,t,n))}catch(s){n()}}};e.addEventListener("load",i),a=setTimeout(i,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(r){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,(function(){return!0}),(function(e){r++,n.waitForIframes(e.querySelector("html"),(function(){--r||t()}))}),(function(e){e||t()}))}},{key:"forEachIframe",value:function(t,n,r){var o=this,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},i=t.querySelectorAll("iframe"),s=i.length,c=0;i=Array.prototype.slice.call(i);var l=function(){--s<=0&&a(c)};s||l(),i.forEach((function(t){e.matches(t,o.exclude)?l():o.onIframeReady(t,(function(e){n(t)&&(c++,r(e)),l()}),l)}))}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:(null===t||e.nextNode())&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var o=!1,a=!1;return r.forEach((function(e,t){e.val===n&&(o=t,a=e.handled)})),this.compareNodeIframe(e,t,n)?(!1!==o||a?!1===o||a||(r[o].handled=!0):r.push({val:n,handled:!0}),!0):(!1===o&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var o=this;e.forEach((function(e){e.handled||o.getIframeContents(e.val,(function(e){o.createInstanceOnIframe(e).forEachNode(t,n,r)}))}))}},{key:"iterateThroughNodes",value:function(e,t,n,r,o){for(var a=this,i=this.createIterator(t,e,r),s=[],c=[],l=void 0,u=void 0,p=function(){var e=a.getIteratorNode(i);return u=e.prevNode,l=e.node};p();)this.iframes&&this.forEachIframe(t,(function(e){return a.checkIframeFilter(l,u,e,s)}),(function(t){a.createInstanceOnIframe(t).forEachNode(e,(function(e){return c.push(e)}),r)})),c.push(l);c.forEach((function(e){n(e)})),this.iframes&&this.handleOpenIframes(s,e,n,r),o()}},{key:"forEachNode",value:function(e,t,n){var r=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=this.getContexts(),i=a.length;i||o(),a.forEach((function(a){var s=function(){r.iterateThroughNodes(e,a,t,n,(function(){--i<=0&&o()}))};r.iframes?r.waitForIframes(a,s):s()}))}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var o=!1;return n.every((function(t){return!r.call(e,t)||(o=!0,!1)})),o}return!1}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var o in t)if(t.hasOwnProperty(o)){var a=t[o],i="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(a):this.escapeStr(a);""!==i&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(i)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(i)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,(function(e){return"\\"===e.charAt(0)?"?":"\x01"}))).replace(/(?:\\)*\*/g,(function(e){return"\\"===e.charAt(0)?"*":"\x02"}))}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,(function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"}))}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["a\xe0\xe1\u1ea3\xe3\u1ea1\u0103\u1eb1\u1eaf\u1eb3\u1eb5\u1eb7\xe2\u1ea7\u1ea5\u1ea9\u1eab\u1ead\xe4\xe5\u0101\u0105","A\xc0\xc1\u1ea2\xc3\u1ea0\u0102\u1eb0\u1eae\u1eb2\u1eb4\u1eb6\xc2\u1ea6\u1ea4\u1ea8\u1eaa\u1eac\xc4\xc5\u0100\u0104","c\xe7\u0107\u010d","C\xc7\u0106\u010c","d\u0111\u010f","D\u0110\u010e","e\xe8\xe9\u1ebb\u1ebd\u1eb9\xea\u1ec1\u1ebf\u1ec3\u1ec5\u1ec7\xeb\u011b\u0113\u0119","E\xc8\xc9\u1eba\u1ebc\u1eb8\xca\u1ec0\u1ebe\u1ec2\u1ec4\u1ec6\xcb\u011a\u0112\u0118","i\xec\xed\u1ec9\u0129\u1ecb\xee\xef\u012b","I\xcc\xcd\u1ec8\u0128\u1eca\xce\xcf\u012a","l\u0142","L\u0141","n\xf1\u0148\u0144","N\xd1\u0147\u0143","o\xf2\xf3\u1ecf\xf5\u1ecd\xf4\u1ed3\u1ed1\u1ed5\u1ed7\u1ed9\u01a1\u1edf\u1ee1\u1edb\u1edd\u1ee3\xf6\xf8\u014d","O\xd2\xd3\u1ece\xd5\u1ecc\xd4\u1ed2\u1ed0\u1ed4\u1ed6\u1ed8\u01a0\u1ede\u1ee0\u1eda\u1edc\u1ee2\xd6\xd8\u014c","r\u0159","R\u0158","s\u0161\u015b\u0219\u015f","S\u0160\u015a\u0218\u015e","t\u0165\u021b\u0163","T\u0164\u021a\u0162","u\xf9\xfa\u1ee7\u0169\u1ee5\u01b0\u1eeb\u1ee9\u1eed\u1eef\u1ef1\xfb\xfc\u016f\u016b","U\xd9\xda\u1ee6\u0168\u1ee4\u01af\u1eea\u1ee8\u1eec\u1eee\u1ef0\xdb\xdc\u016e\u016a","y\xfd\u1ef3\u1ef7\u1ef9\u1ef5\xff","Y\xdd\u1ef2\u1ef6\u1ef8\u1ef4\u0178","z\u017e\u017c\u017a","Z\u017d\u017b\u0179"]:["a\xe0\xe1\u1ea3\xe3\u1ea1\u0103\u1eb1\u1eaf\u1eb3\u1eb5\u1eb7\xe2\u1ea7\u1ea5\u1ea9\u1eab\u1ead\xe4\xe5\u0101\u0105A\xc0\xc1\u1ea2\xc3\u1ea0\u0102\u1eb0\u1eae\u1eb2\u1eb4\u1eb6\xc2\u1ea6\u1ea4\u1ea8\u1eaa\u1eac\xc4\xc5\u0100\u0104","c\xe7\u0107\u010dC\xc7\u0106\u010c","d\u0111\u010fD\u0110\u010e","e\xe8\xe9\u1ebb\u1ebd\u1eb9\xea\u1ec1\u1ebf\u1ec3\u1ec5\u1ec7\xeb\u011b\u0113\u0119E\xc8\xc9\u1eba\u1ebc\u1eb8\xca\u1ec0\u1ebe\u1ec2\u1ec4\u1ec6\xcb\u011a\u0112\u0118","i\xec\xed\u1ec9\u0129\u1ecb\xee\xef\u012bI\xcc\xcd\u1ec8\u0128\u1eca\xce\xcf\u012a","l\u0142L\u0141","n\xf1\u0148\u0144N\xd1\u0147\u0143","o\xf2\xf3\u1ecf\xf5\u1ecd\xf4\u1ed3\u1ed1\u1ed5\u1ed7\u1ed9\u01a1\u1edf\u1ee1\u1edb\u1edd\u1ee3\xf6\xf8\u014dO\xd2\xd3\u1ece\xd5\u1ecc\xd4\u1ed2\u1ed0\u1ed4\u1ed6\u1ed8\u01a0\u1ede\u1ee0\u1eda\u1edc\u1ee2\xd6\xd8\u014c","r\u0159R\u0158","s\u0161\u015b\u0219\u015fS\u0160\u015a\u0218\u015e","t\u0165\u021b\u0163T\u0164\u021a\u0162","u\xf9\xfa\u1ee7\u0169\u1ee5\u01b0\u1eeb\u1ee9\u1eed\u1eef\u1ef1\xfb\xfc\u016f\u016bU\xd9\xda\u1ee6\u0168\u1ee4\u01af\u1eea\u1ee8\u1eec\u1eee\u1ef0\xdb\xdc\u016e\u016a","y\xfd\u1ef3\u1ef7\u1ef9\u1ef5\xffY\xdd\u1ef2\u1ef6\u1ef8\u1ef4\u0178","z\u017e\u017c\u017aZ\u017d\u017b\u0179"],r=[];return e.split("").forEach((function(o){n.every((function(n){if(-1!==n.indexOf(o)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0}))})),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\xa1\xbf",r=this.opt.accuracy,o="string"==typeof r?r:r.value,a="string"==typeof r?[]:r.limiters,i="";switch(a.forEach((function(e){i+="|"+t.escapeStr(e)})),o){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr(n)))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach((function(e){t.opt.separateWordSearch?e.split(" ").forEach((function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)})):e.trim()&&-1===n.indexOf(e)&&n.push(e)})),{keywords:n.sort((function(e,t){return t.length-e.length})),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort((function(e,t){return e.start-t.start})).forEach((function(e){var o=t.callNoMatchOnInvalidRanges(e,r),a=o.start,i=o.end;o.valid&&(e.start=a,e.length=i-a,n.push(e),r=i)})),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,o=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?o=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:o}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,o=!0,a=n.length,i=t-a,s=parseInt(e.start,10)-i;return(r=(s=s>a?a:s)+parseInt(e.length,10))>a&&(r=a,this.log("End range automatically set to the max value of "+a)),s<0||r-s<0||s>a||r>a?(o=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(o=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:o}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,(function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})}),(function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}),(function(){e({value:n,nodes:r})}))}},{key:"matchesExclude",value:function(e){return o.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",o=e.splitText(t),a=o.splitText(n-t),i=document.createElement(r);return i.setAttribute("data-markjs","true"),this.opt.className&&i.setAttribute("class",this.opt.className),i.textContent=o.textContent,o.parentNode.replaceChild(i,o),a}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,o){var a=this;e.nodes.every((function(i,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(i.node))return!1;var l=t-i.start,u=(n>i.end?i.end:n)-i.start,p=e.value.substr(0,i.start),d=e.value.substr(u+i.start);if(i.node=a.wrapRangeInTextNode(i.node,l,u),e.value=p+d,e.nodes.forEach((function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=u),e.nodes[n].end-=u)})),n-=u,o(i.node.previousSibling,i.start),!(n>i.end))return!1;t=i.end}return!0}))}},{key:"wrapMatches",value:function(e,t,n,r,o){var a=this,i=0===t?0:t+1;this.getTextNodes((function(t){t.nodes.forEach((function(t){t=t.node;for(var o=void 0;null!==(o=e.exec(t.textContent))&&""!==o[i];)if(n(o[i],t)){var s=o.index;if(0!==i)for(var c=1;c<i;c++)s+=o[c].length;t=a.wrapRangeInTextNode(t,s,s+o[i].length),r(t.previousSibling),e.lastIndex=0}})),o()}))}},{key:"wrapMatchesAcrossElements",value:function(e,t,n,r,o){var a=this,i=0===t?0:t+1;this.getTextNodes((function(t){for(var s=void 0;null!==(s=e.exec(t.value))&&""!==s[i];){var c=s.index;if(0!==i)for(var l=1;l<i;l++)c+=s[l].length;var u=c+s[i].length;a.wrapRangeInMappedTextNode(t,c,u,(function(e){return n(s[i],e)}),(function(t,n){e.lastIndex=n,r(t)}))}o()}))}},{key:"wrapRangeFromIndex",value:function(e,t,n,r){var o=this;this.getTextNodes((function(a){var i=a.value.length;e.forEach((function(e,r){var s=o.checkWhitespaceRanges(e,i,a.value),c=s.start,l=s.end;s.valid&&o.wrapRangeInMappedTextNode(a,c,l,(function(n){return t(n,e,a.value.substring(c,l),r)}),(function(t){n(t,e)}))})),r()}))}},{key:"unwrapMatches",value:function(e){for(var t=e.parentNode,n=document.createDocumentFragment();e.firstChild;)n.appendChild(e.removeChild(e.firstChild));t.replaceChild(n,e),this.ie?this.normalizeTextNode(t):t.normalize()}},{key:"normalizeTextNode",value:function(e){if(e){if(3===e.nodeType)for(;e.nextSibling&&3===e.nextSibling.nodeType;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}},{key:"markRegExp",value:function(e,t){var n=this;this.opt=t,this.log('Searching with expression "'+e+'"');var r=0,o="wrapMatches",a=function(e){r++,n.opt.each(e)};this.opt.acrossElements&&(o="wrapMatchesAcrossElements"),this[o](e,this.opt.ignoreGroups,(function(e,t){return n.opt.filter(t,e,r)}),a,(function(){0===r&&n.opt.noMatch(e),n.opt.done(r)}))}},{key:"mark",value:function(e,t){var n=this;this.opt=t;var r=0,o="wrapMatches",a=this.getSeparatedKeywords("string"==typeof e?[e]:e),i=a.keywords,s=a.length,c=this.opt.caseSensitive?"":"i",l=function e(t){var a=new RegExp(n.createRegExp(t),"gm"+c),l=0;n.log('Searching with expression "'+a+'"'),n[o](a,1,(function(e,o){return n.opt.filter(o,t,r,l)}),(function(e){l++,r++,n.opt.each(e)}),(function(){0===l&&n.opt.noMatch(t),i[s-1]===t?n.opt.done(r):e(i[i.indexOf(t)+1])}))};this.opt.acrossElements&&(o="wrapMatchesAcrossElements"),0===s?this.opt.done(r):l(i[0])}},{key:"markRanges",value:function(e,t){var n=this;this.opt=t;var r=0,o=this.checkRanges(e);o&&o.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(o)),this.wrapRangeFromIndex(o,(function(e,t,r,o){return n.opt.filter(e,t,r,o)}),(function(e,t){r++,n.opt.each(e,t)}),(function(){n.opt.done(r)}))):this.opt.done(r)}},{key:"unmark",value:function(e){var t=this;this.opt=e;var n=this.opt.element?this.opt.element:"*";n+="[data-markjs]",this.opt.className&&(n+="."+this.opt.className),this.log('Removal selector "'+n+'"'),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,(function(e){t.unwrapMatches(e)}),(function(e){var r=o.matches(e,n),a=t.matchesExclude(e);return!r||a?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}),this.opt.done)}},{key:"opt",set:function(e){this._opt=r({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:function(){},noMatch:function(){},filter:function(){return!0},done:function(){},debug:!1,log:window.console},e)},get:function(){return this._opt}},{key:"iterator",get:function(){return new o(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}}]),a}();function i(e){var t=this,n=new a(e);return this.mark=function(e,r){return n.mark(e,r),t},this.markRegExp=function(e,r){return n.markRegExp(e,r),t},this.markRanges=function(e,r){return n.markRanges(e,r),t},this.unmark=function(e){return n.unmark(e),t},this}return i}()},85300:(e,t,n)=>{"use strict";n.r(t)},58252:(e,t,n)=>{"use strict";n.r(t)},5947:function(e,t,n){var r,o;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function o(e,t,n){return e<t?t:e>n?n:e}function a(e){return 100*(-1+e)}function i(e,t,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+a(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+a(e)+"%,0)"}:{"margin-left":a(e)+"%"}).transition="all "+t+"ms "+n,o}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=o(e,r.minimum,1),n.status=1===e?null:e;var a=n.render(!t),l=a.querySelector(r.barSelector),u=r.speed,p=r.easing;return a.offsetWidth,s((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),c(l,i(e,u,p)),1===e?(c(a,{transition:"none",opacity:1}),a.offsetWidth,setTimeout((function(){c(a,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*o(Math.random()*t,.1,.95)),t=o(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var o,i=t.querySelector(r.barSelector),s=e?"-100":a(n.status||0),l=document.querySelector(r.parent);return c(i,{transition:"all 0 linear",transform:"translate3d("+s+"%,0,0)"}),r.showSpinner||(o=t.querySelector(r.spinnerSelector))&&f(o),l!=document.body&&u(l,"nprogress-custom-parent"),l.appendChild(t),t},n.remove=function(){p(document.documentElement,"nprogress-busy"),p(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var s=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),c=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,o=e.length,a=t.charAt(0).toUpperCase()+t.slice(1);o--;)if((r=e[o]+a)in n)return r;return t}function o(e){return e=n(e),t[e]||(t[e]=r(e))}function a(e,t,n){t=o(t),e.style[t]=n}return function(e,t){var n,r,o=arguments;if(2==o.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&a(e,n,r);else a(e,o[1],o[2])}}();function l(e,t){return("string"==typeof e?e:d(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=d(e),r=n+t;l(n,t)||(e.className=r.substring(1))}function p(e,t){var n,r=d(e);l(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function d(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},57022:()=>{!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var o=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],a=r.variable[1].inside,i=0;i<o.length;i++)a[o[i]]=e.languages.bash[o[i]];e.languages.sh=e.languages.bash,e.languages.shell=e.languages.bash}(Prism)},47839:()=>{!function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],o=[];/^\w+$/.test(n)||o.push(/\w+/.exec(n)[0]),"diff"===n&&o.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:o,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(Prism)},72514:()=>{Prism.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},Prism.languages.webmanifest=Prism.languages.json},19700:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,s=i.length;-1!==n.code.indexOf(o=t(r,s));)++s;return i[s]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(s){for(var c=0;c<s.length&&!(o>=a.length);c++){var l=s[c];if("string"==typeof l||l.content&&"string"==typeof l.content){var u=a[o],p=n.tokenStack[u],d="string"==typeof l?l:l.content,f=t(r,u),m=d.indexOf(f);if(m>-1){++o;var h=d.substring(0,m),v=new e.Token(r,e.tokenize(p,n.grammar),"language-"+r,p),g=d.substring(m+f.length),b=[];h&&b.push.apply(b,i([h])),b.push(v),g&&b.push.apply(b,i([g])),"string"==typeof l?s.splice.apply(s,[c,1].concat(b)):l.content=b}}else l.content&&i(l.content)}return s}(n.tokens)}}}})}(Prism)},60061:()=>{!function(e){var t=[/"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,/'[^']*'/.source,/\$'(?:[^'\\]|\\[\s\S])*'/.source,/<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source].join("|");e.languages["shell-session"]={command:{pattern:RegExp(/^/.source+"(?:"+/[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+(?::[^\0-\x1F$#%*?"<>:;|]+)?/.source+"|"+/[/~.][^\0-\x1F$#%*?"<>@:;|]*/.source+")?"+/[$#%](?=\s)/.source+/(?:[^\\\r\n \t'"<$]|[ \t](?:(?!#)|#.*$)|\\(?:[^\r]|\r\n?)|\$(?!')|<(?!<)|<<str>>)+/.source.replace(/<<str>>/g,(function(){return t})),"m"),greedy:!0,inside:{info:{pattern:/^[^#$%]+/,alias:"punctuation",inside:{user:/^[^\s@:$#%*!/\\]+@[^\r\n@:$#%*!/\\]+/,punctuation:/:/,path:/[\s\S]+/}},bash:{pattern:/(^[$#%]\s*)\S[\s\S]*/,lookbehind:!0,alias:"language-bash",inside:e.languages.bash},"shell-symbol":{pattern:/^[$#%]/,alias:"important"}}},output:/.(?:.*(?:[\r\n]|.$))*/},e.languages["sh-session"]=e.languages.shellsession=e.languages["shell-session"]}(Prism)},97553:(e,t,n)=>{var r={"./prism-bash":57022,"./prism-diff":47839,"./prism-json":72514,"./prism-shell-session":60061};function o(e){var t=a(e);return n(t)}function a(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}o.keys=function(){return Object.keys(r)},o.resolve=a,e.exports=o,o.id=97553},2694:(e,t,n)=>{"use strict";var r=n(6925);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var s=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},5556:(e,t,n)=>{e.exports=n(2694)()},6925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},22551:(e,t,n)=>{"use strict";var r=n(96540),o=n(69982);function a(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var i=new Set,s={};function c(e,t){l(e,t),l(e+"Capture",t)}function l(e,t){for(s[e]=t,e=0;e<t.length;e++)i.add(t[e])}var u=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),p=Object.prototype.hasOwnProperty,d=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f={},m={};function h(e,t,n,r,o,a,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=i}var v={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){v[e]=new h(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];v[t]=new h(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){v[e]=new h(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){v[e]=new h(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){v[e]=new h(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){v[e]=new h(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){v[e]=new h(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){v[e]=new h(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){v[e]=new h(e,5,!1,e.toLowerCase(),null,!1,!1)}));var g=/[\-:]([a-z])/g;function b(e){return e[1].toUpperCase()}function y(e,t,n,r){var o=v.hasOwnProperty(t)?v[t]:null;(null!==o?0!==o.type:r||!(2<t.length)||"o"!==t[0]&&"O"!==t[0]||"n"!==t[1]&&"N"!==t[1])&&(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,o,r)&&(n=null),r||null===o?function(e){return!!p.call(m,e)||!p.call(f,e)&&(d.test(e)?m[e]=!0:(f[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):o.mustUseProperty?e[o.propertyName]=null===n?3!==o.type&&"":n:(t=o.attributeName,r=o.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(o=o.type)||4===o&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(g,b);v[t]=new h(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(g,b);v[t]=new h(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(g,b);v[t]=new h(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){v[e]=new h(e,1,!1,e.toLowerCase(),null,!1,!1)})),v.xlinkHref=new h("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){v[e]=new h(e,1,!1,e.toLowerCase(),null,!0,!0)}));var w=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,_=Symbol.for("react.element"),x=Symbol.for("react.portal"),S=Symbol.for("react.fragment"),k=Symbol.for("react.strict_mode"),E=Symbol.for("react.profiler"),O=Symbol.for("react.provider"),j=Symbol.for("react.context"),P=Symbol.for("react.forward_ref"),C=Symbol.for("react.suspense"),A=Symbol.for("react.suspense_list"),T=Symbol.for("react.memo"),I=Symbol.for("react.lazy");Symbol.for("react.scope"),Symbol.for("react.debug_trace_mode");var N=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden"),Symbol.for("react.cache"),Symbol.for("react.tracing_marker");var L=Symbol.iterator;function R(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=L&&e[L]||e["@@iterator"])?e:null}var D,F=Object.assign;function M(e){if(void 0===D)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);D=t&&t[1]||""}return"\n"+D+e}var B=!1;function z(e,t){if(!e||B)return"";B=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(l){var r=l}Reflect.construct(e,[],t)}else{try{t.call()}catch(l){r=l}e.call(t.prototype)}else{try{throw Error()}catch(l){r=l}e()}}catch(l){if(l&&r&&"string"==typeof l.stack){for(var o=l.stack.split("\n"),a=r.stack.split("\n"),i=o.length-1,s=a.length-1;1<=i&&0<=s&&o[i]!==a[s];)s--;for(;1<=i&&0<=s;i--,s--)if(o[i]!==a[s]){if(1!==i||1!==s)do{if(i--,0>--s||o[i]!==a[s]){var c="\n"+o[i].replace(" at new "," at ");return e.displayName&&c.includes("<anonymous>")&&(c=c.replace("<anonymous>",e.displayName)),c}}while(1<=i&&0<=s);break}}}finally{B=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?M(e):""}function $(e){switch(e.tag){case 5:return M(e.type);case 16:return M("Lazy");case 13:return M("Suspense");case 19:return M("SuspenseList");case 0:case 2:case 15:return e=z(e.type,!1);case 11:return e=z(e.type.render,!1);case 1:return e=z(e.type,!0);default:return""}}function U(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case S:return"Fragment";case x:return"Portal";case E:return"Profiler";case k:return"StrictMode";case C:return"Suspense";case A:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case j:return(e.displayName||"Context")+".Consumer";case O:return(e._context.displayName||"Context")+".Provider";case P:var t=e.render;return(e=e.displayName)||(e=""!==(e=t.displayName||t.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case T:return null!==(t=e.displayName||null)?t:U(e.type)||"Memo";case I:t=e._payload,e=e._init;try{return U(e(t))}catch(n){}}return null}function H(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=(e=t.render).displayName||e.name||"",t.displayName||(""!==e?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return U(t);case 8:return t===k?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"==typeof t)return t.displayName||t.name||null;if("string"==typeof t)return t}return null}function V(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":case"object":return e;default:return""}}function W(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function Q(e){e._valueTracker||(e._valueTracker=function(e){var t=W(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var o=n.get,a=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(e){r=""+e,a.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function q(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=W(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function G(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function K(e,t){var n=t.checked;return F({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function Y(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=V(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function Z(e,t){null!=(t=t.checked)&&y(e,"checked",t,!1)}function X(e,t){Z(e,t);var n=V(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ee(e,t.type,n):t.hasOwnProperty("defaultValue")&&ee(e,t.type,V(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function J(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ee(e,t,n){"number"===t&&G(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var te=Array.isArray;function ne(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o<n.length;o++)t["$"+n[o]]=!0;for(n=0;n<e.length;n++)o=t.hasOwnProperty("$"+e[n].value),e[n].selected!==o&&(e[n].selected=o),o&&r&&(e[n].defaultSelected=!0)}else{for(n=""+V(n),t=null,o=0;o<e.length;o++){if(e[o].value===n)return e[o].selected=!0,void(r&&(e[o].defaultSelected=!0));null!==t||e[o].disabled||(t=e[o])}null!==t&&(t.selected=!0)}}function re(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(a(91));return F({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function oe(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(a(92));if(te(n)){if(1<n.length)throw Error(a(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:V(n)}}function ae(e,t){var n=V(t.value),r=V(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ie(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}function se(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function ce(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?se(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var le,ue,pe=(ue=function(e,t){if("http://www.w3.org/2000/svg"!==e.namespaceURI||"innerHTML"in e)e.innerHTML=t;else{for((le=le||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=le.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return ue(e,t)}))}:ue);function de(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var fe={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},me=["Webkit","ms","Moz","O"];function he(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||fe.hasOwnProperty(e)&&fe[e]?(""+t).trim():t+"px"}function ve(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),o=he(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}Object.keys(fe).forEach((function(e){me.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),fe[t]=fe[e]}))}));var ge=F({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function be(e,t){if(t){if(ge[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(a(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(a(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(a(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(a(62))}}function ye(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var we=null;function _e(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var xe=null,Se=null,ke=null;function Ee(e){if(e=wo(e)){if("function"!=typeof xe)throw Error(a(280));var t=e.stateNode;t&&(t=xo(t),xe(e.stateNode,e.type,t))}}function Oe(e){Se?ke?ke.push(e):ke=[e]:Se=e}function je(){if(Se){var e=Se,t=ke;if(ke=Se=null,Ee(e),t)for(e=0;e<t.length;e++)Ee(t[e])}}function Pe(e,t){return e(t)}function Ce(){}var Ae=!1;function Te(e,t,n){if(Ae)return e(t,n);Ae=!0;try{return Pe(e,t,n)}finally{Ae=!1,(null!==Se||null!==ke)&&(Ce(),je())}}function Ie(e,t){var n=e.stateNode;if(null===n)return null;var r=xo(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(a(231,t,typeof n));return n}var Ne=!1;if(u)try{var Le={};Object.defineProperty(Le,"passive",{get:function(){Ne=!0}}),window.addEventListener("test",Le,Le),window.removeEventListener("test",Le,Le)}catch(ue){Ne=!1}function Re(e,t,n,r,o,a,i,s,c){var l=Array.prototype.slice.call(arguments,3);try{t.apply(n,l)}catch(u){this.onError(u)}}var De=!1,Fe=null,Me=!1,Be=null,ze={onError:function(e){De=!0,Fe=e}};function $e(e,t,n,r,o,a,i,s,c){De=!1,Fe=null,Re.apply(ze,arguments)}function Ue(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{!!(4098&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function He(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Ve(e){if(Ue(e)!==e)throw Error(a(188))}function We(e){return null!==(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ue(e)))throw Error(a(188));return t!==e?null:e}for(var n=e,r=t;;){var o=n.return;if(null===o)break;var i=o.alternate;if(null===i){if(null!==(r=o.return)){n=r;continue}break}if(o.child===i.child){for(i=o.child;i;){if(i===n)return Ve(o),e;if(i===r)return Ve(o),t;i=i.sibling}throw Error(a(188))}if(n.return!==r.return)n=o,r=i;else{for(var s=!1,c=o.child;c;){if(c===n){s=!0,n=o,r=i;break}if(c===r){s=!0,r=o,n=i;break}c=c.sibling}if(!s){for(c=i.child;c;){if(c===n){s=!0,n=i,r=o;break}if(c===r){s=!0,r=i,n=o;break}c=c.sibling}if(!s)throw Error(a(189))}}if(n.alternate!==r)throw Error(a(190))}if(3!==n.tag)throw Error(a(188));return n.stateNode.current===n?e:t}(e))?Qe(e):null}function Qe(e){if(5===e.tag||6===e.tag)return e;for(e=e.child;null!==e;){var t=Qe(e);if(null!==t)return t;e=e.sibling}return null}var qe=o.unstable_scheduleCallback,Ge=o.unstable_cancelCallback,Ke=o.unstable_shouldYield,Ye=o.unstable_requestPaint,Ze=o.unstable_now,Xe=o.unstable_getCurrentPriorityLevel,Je=o.unstable_ImmediatePriority,et=o.unstable_UserBlockingPriority,tt=o.unstable_NormalPriority,nt=o.unstable_LowPriority,rt=o.unstable_IdlePriority,ot=null,at=null;var it=Math.clz32?Math.clz32:function(e){return e>>>=0,0===e?32:31-(st(e)/ct|0)|0},st=Math.log,ct=Math.LN2;var lt=64,ut=4194304;function pt(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return 4194240&e;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return 130023424&e;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function dt(e,t){var n=e.pendingLanes;if(0===n)return 0;var r=0,o=e.suspendedLanes,a=e.pingedLanes,i=268435455&n;if(0!==i){var s=i&~o;0!==s?r=pt(s):0!==(a&=i)&&(r=pt(a))}else 0!==(i=n&~o)?r=pt(i):0!==a&&(r=pt(a));if(0===r)return 0;if(0!==t&&t!==r&&!(t&o)&&((o=r&-r)>=(a=t&-t)||16===o&&4194240&a))return t;if(4&r&&(r|=16&n),0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)o=1<<(n=31-it(t)),r|=e[n],t&=~o;return r}function ft(e,t){switch(e){case 1:case 2:case 4:return t+250;case 8:case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;default:return-1}}function mt(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function ht(){var e=lt;return!(4194240&(lt<<=1))&&(lt=64),e}function vt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function gt(e,t,n){e.pendingLanes|=t,536870912!==t&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[t=31-it(t)]=n}function bt(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-it(n),o=1<<r;o&t|e[r]&t&&(e[r]|=t),n&=~o}}var yt=0;function wt(e){return 1<(e&=-e)?4<e?268435455&e?16:536870912:4:1}var _t,xt,St,kt,Et,Ot=!1,jt=[],Pt=null,Ct=null,At=null,Tt=new Map,It=new Map,Nt=[],Lt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function Rt(e,t){switch(e){case"focusin":case"focusout":Pt=null;break;case"dragenter":case"dragleave":Ct=null;break;case"mouseover":case"mouseout":At=null;break;case"pointerover":case"pointerout":Tt.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":It.delete(t.pointerId)}}function Dt(e,t,n,r,o,a){return null===e||e.nativeEvent!==a?(e={blockedOn:t,domEventName:n,eventSystemFlags:r,nativeEvent:a,targetContainers:[o]},null!==t&&(null!==(t=wo(t))&&xt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==o&&-1===t.indexOf(o)&&t.push(o),e)}function Ft(e){var t=yo(e.target);if(null!==t){var n=Ue(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=He(n)))return e.blockedOn=t,void Et(e.priority,(function(){St(n)}))}else if(3===t&&n.stateNode.current.memoizedState.isDehydrated)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function Mt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Kt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=wo(n))&&xt(t),e.blockedOn=n,!1;var r=new(n=e.nativeEvent).constructor(n.type,n);we=r,n.target.dispatchEvent(r),we=null,t.shift()}return!0}function Bt(e,t,n){Mt(e)&&n.delete(t)}function zt(){Ot=!1,null!==Pt&&Mt(Pt)&&(Pt=null),null!==Ct&&Mt(Ct)&&(Ct=null),null!==At&&Mt(At)&&(At=null),Tt.forEach(Bt),It.forEach(Bt)}function $t(e,t){e.blockedOn===t&&(e.blockedOn=null,Ot||(Ot=!0,o.unstable_scheduleCallback(o.unstable_NormalPriority,zt)))}function Ut(e){function t(t){return $t(t,e)}if(0<jt.length){$t(jt[0],e);for(var n=1;n<jt.length;n++){var r=jt[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==Pt&&$t(Pt,e),null!==Ct&&$t(Ct,e),null!==At&&$t(At,e),Tt.forEach(t),It.forEach(t),n=0;n<Nt.length;n++)(r=Nt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<Nt.length&&null===(n=Nt[0]).blockedOn;)Ft(n),null===n.blockedOn&&Nt.shift()}var Ht=w.ReactCurrentBatchConfig,Vt=!0;function Wt(e,t,n,r){var o=yt,a=Ht.transition;Ht.transition=null;try{yt=1,qt(e,t,n,r)}finally{yt=o,Ht.transition=a}}function Qt(e,t,n,r){var o=yt,a=Ht.transition;Ht.transition=null;try{yt=4,qt(e,t,n,r)}finally{yt=o,Ht.transition=a}}function qt(e,t,n,r){if(Vt){var o=Kt(e,t,n,r);if(null===o)Vr(e,t,r,Gt,n),Rt(e,r);else if(function(e,t,n,r,o){switch(t){case"focusin":return Pt=Dt(Pt,e,t,n,r,o),!0;case"dragenter":return Ct=Dt(Ct,e,t,n,r,o),!0;case"mouseover":return At=Dt(At,e,t,n,r,o),!0;case"pointerover":var a=o.pointerId;return Tt.set(a,Dt(Tt.get(a)||null,e,t,n,r,o)),!0;case"gotpointercapture":return a=o.pointerId,It.set(a,Dt(It.get(a)||null,e,t,n,r,o)),!0}return!1}(o,e,t,n,r))r.stopPropagation();else if(Rt(e,r),4&t&&-1<Lt.indexOf(e)){for(;null!==o;){var a=wo(o);if(null!==a&&_t(a),null===(a=Kt(e,t,n,r))&&Vr(e,t,r,Gt,n),a===o)break;o=a}null!==o&&r.stopPropagation()}else Vr(e,t,r,null,n)}}var Gt=null;function Kt(e,t,n,r){if(Gt=null,null!==(e=yo(e=_e(r))))if(null===(t=Ue(e)))e=null;else if(13===(n=t.tag)){if(null!==(e=He(t)))return e;e=null}else if(3===n){if(t.stateNode.current.memoizedState.isDehydrated)return 3===t.tag?t.stateNode.containerInfo:null;e=null}else t!==e&&(e=null);return Gt=e,null}function Yt(e){switch(e){case"cancel":case"click":case"close":case"contextmenu":case"copy":case"cut":case"auxclick":case"dblclick":case"dragend":case"dragstart":case"drop":case"focusin":case"focusout":case"input":case"invalid":case"keydown":case"keypress":case"keyup":case"mousedown":case"mouseup":case"paste":case"pause":case"play":case"pointercancel":case"pointerdown":case"pointerup":case"ratechange":case"reset":case"resize":case"seeked":case"submit":case"touchcancel":case"touchend":case"touchstart":case"volumechange":case"change":case"selectionchange":case"textInput":case"compositionstart":case"compositionend":case"compositionupdate":case"beforeblur":case"afterblur":case"beforeinput":case"blur":case"fullscreenchange":case"focus":case"hashchange":case"popstate":case"select":case"selectstart":return 1;case"drag":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"mousemove":case"mouseout":case"mouseover":case"pointermove":case"pointerout":case"pointerover":case"scroll":case"toggle":case"touchmove":case"wheel":case"mouseenter":case"mouseleave":case"pointerenter":case"pointerleave":return 4;case"message":switch(Xe()){case Je:return 1;case et:return 4;case tt:case nt:return 16;case rt:return 536870912;default:return 16}default:return 16}}var Zt=null,Xt=null,Jt=null;function en(){if(Jt)return Jt;var e,t,n=Xt,r=n.length,o="value"in Zt?Zt.value:Zt.textContent,a=o.length;for(e=0;e<r&&n[e]===o[e];e++);var i=r-e;for(t=1;t<=i&&n[r-t]===o[a-t];t++);return Jt=o.slice(e,1<t?1-t:void 0)}function tn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function nn(){return!0}function rn(){return!1}function on(e){function t(t,n,r,o,a){for(var i in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=o,this.target=a,this.currentTarget=null,e)e.hasOwnProperty(i)&&(t=e[i],this[i]=t?t(o):o[i]);return this.isDefaultPrevented=(null!=o.defaultPrevented?o.defaultPrevented:!1===o.returnValue)?nn:rn,this.isPropagationStopped=rn,this}return F(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=nn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=nn)},persist:function(){},isPersistent:nn}),t}var an,sn,cn,ln={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},un=on(ln),pn=F({},ln,{view:0,detail:0}),dn=on(pn),fn=F({},pn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:En,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==cn&&(cn&&"mousemove"===e.type?(an=e.screenX-cn.screenX,sn=e.screenY-cn.screenY):sn=an=0,cn=e),an)},movementY:function(e){return"movementY"in e?e.movementY:sn}}),mn=on(fn),hn=on(F({},fn,{dataTransfer:0})),vn=on(F({},pn,{relatedTarget:0})),gn=on(F({},ln,{animationName:0,elapsedTime:0,pseudoElement:0})),bn=F({},ln,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),yn=on(bn),wn=on(F({},ln,{data:0})),_n={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},xn={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},Sn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function kn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=Sn[e])&&!!t[e]}function En(){return kn}var On=F({},pn,{key:function(e){if(e.key){var t=_n[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=tn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?xn[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:En,charCode:function(e){return"keypress"===e.type?tn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?tn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),jn=on(On),Pn=on(F({},fn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Cn=on(F({},pn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:En})),An=on(F({},ln,{propertyName:0,elapsedTime:0,pseudoElement:0})),Tn=F({},fn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),In=on(Tn),Nn=[9,13,27,32],Ln=u&&"CompositionEvent"in window,Rn=null;u&&"documentMode"in document&&(Rn=document.documentMode);var Dn=u&&"TextEvent"in window&&!Rn,Fn=u&&(!Ln||Rn&&8<Rn&&11>=Rn),Mn=String.fromCharCode(32),Bn=!1;function zn(e,t){switch(e){case"keyup":return-1!==Nn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function $n(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Un=!1;var Hn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Vn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Hn[e.type]:"textarea"===t}function Wn(e,t,n,r){Oe(r),0<(t=Qr(t,"onChange")).length&&(n=new un("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Qn=null,qn=null;function Gn(e){Mr(e,0)}function Kn(e){if(q(_o(e)))return e}function Yn(e,t){if("change"===e)return t}var Zn=!1;if(u){var Xn;if(u){var Jn="oninput"in document;if(!Jn){var er=document.createElement("div");er.setAttribute("oninput","return;"),Jn="function"==typeof er.oninput}Xn=Jn}else Xn=!1;Zn=Xn&&(!document.documentMode||9<document.documentMode)}function tr(){Qn&&(Qn.detachEvent("onpropertychange",nr),qn=Qn=null)}function nr(e){if("value"===e.propertyName&&Kn(qn)){var t=[];Wn(t,qn,e,_e(e)),Te(Gn,t)}}function rr(e,t,n){"focusin"===e?(tr(),qn=n,(Qn=t).attachEvent("onpropertychange",nr)):"focusout"===e&&tr()}function or(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Kn(qn)}function ar(e,t){if("click"===e)return Kn(t)}function ir(e,t){if("input"===e||"change"===e)return Kn(t)}var sr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t};function cr(e,t){if(sr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++){var o=n[r];if(!p.call(t,o)||!sr(e[o],t[o]))return!1}return!0}function lr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function ur(e,t){var n,r=lr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=lr(r)}}function pr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?pr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function dr(){for(var e=window,t=G();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=G((e=t.contentWindow).document)}return t}function fr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}function mr(e){var t=dr(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&pr(n.ownerDocument.documentElement,n)){if(null!==r&&fr(n))if(t=r.start,void 0===(e=r.end)&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if((e=(t=n.ownerDocument||document)&&t.defaultView||window).getSelection){e=e.getSelection();var o=n.textContent.length,a=Math.min(r.start,o);r=void 0===r.end?a:Math.min(r.end,o),!e.extend&&a>r&&(o=r,r=a,a=o),o=ur(n,a);var i=ur(n,r);o&&i&&(1!==e.rangeCount||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==i.node||e.focusOffset!==i.offset)&&((t=t.createRange()).setStart(o.node,o.offset),e.removeAllRanges(),a>r?(e.addRange(t),e.extend(i.node,i.offset)):(t.setEnd(i.node,i.offset),e.addRange(t)))}for(t=[],e=n;e=e.parentNode;)1===e.nodeType&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for("function"==typeof n.focus&&n.focus(),n=0;n<t.length;n++)(e=t[n]).element.scrollLeft=e.left,e.element.scrollTop=e.top}}var hr=u&&"documentMode"in document&&11>=document.documentMode,vr=null,gr=null,br=null,yr=!1;function wr(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;yr||null==vr||vr!==G(r)||("selectionStart"in(r=vr)&&fr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},br&&cr(br,r)||(br=r,0<(r=Qr(gr,"onSelect")).length&&(t=new un("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=vr)))}function _r(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var xr={animationend:_r("Animation","AnimationEnd"),animationiteration:_r("Animation","AnimationIteration"),animationstart:_r("Animation","AnimationStart"),transitionend:_r("Transition","TransitionEnd")},Sr={},kr={};function Er(e){if(Sr[e])return Sr[e];if(!xr[e])return e;var t,n=xr[e];for(t in n)if(n.hasOwnProperty(t)&&t in kr)return Sr[e]=n[t];return e}u&&(kr=document.createElement("div").style,"AnimationEvent"in window||(delete xr.animationend.animation,delete xr.animationiteration.animation,delete xr.animationstart.animation),"TransitionEvent"in window||delete xr.transitionend.transition);var Or=Er("animationend"),jr=Er("animationiteration"),Pr=Er("animationstart"),Cr=Er("transitionend"),Ar=new Map,Tr="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function Ir(e,t){Ar.set(e,t),c(t,[e])}for(var Nr=0;Nr<Tr.length;Nr++){var Lr=Tr[Nr];Ir(Lr.toLowerCase(),"on"+(Lr[0].toUpperCase()+Lr.slice(1)))}Ir(Or,"onAnimationEnd"),Ir(jr,"onAnimationIteration"),Ir(Pr,"onAnimationStart"),Ir("dblclick","onDoubleClick"),Ir("focusin","onFocus"),Ir("focusout","onBlur"),Ir(Cr,"onTransitionEnd"),l("onMouseEnter",["mouseout","mouseover"]),l("onMouseLeave",["mouseout","mouseover"]),l("onPointerEnter",["pointerout","pointerover"]),l("onPointerLeave",["pointerout","pointerover"]),c("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),c("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),c("onBeforeInput",["compositionend","keypress","textInput","paste"]),c("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var Rr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Dr=new Set("cancel close invalid load scroll toggle".split(" ").concat(Rr));function Fr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,o,i,s,c,l){if($e.apply(this,arguments),De){if(!De)throw Error(a(198));var u=Fe;De=!1,Fe=null,Me||(Me=!0,Be=u)}}(r,t,void 0,e),e.currentTarget=null}function Mr(e,t){t=!!(4&t);for(var n=0;n<e.length;n++){var r=e[n],o=r.event;r=r.listeners;e:{var a=void 0;if(t)for(var i=r.length-1;0<=i;i--){var s=r[i],c=s.instance,l=s.currentTarget;if(s=s.listener,c!==a&&o.isPropagationStopped())break e;Fr(o,s,l),a=c}else for(i=0;i<r.length;i++){if(c=(s=r[i]).instance,l=s.currentTarget,s=s.listener,c!==a&&o.isPropagationStopped())break e;Fr(o,s,l),a=c}}}if(Me)throw e=Be,Me=!1,Be=null,e}function Br(e,t){var n=t[vo];void 0===n&&(n=t[vo]=new Set);var r=e+"__bubble";n.has(r)||(Hr(t,e,2,!1),n.add(r))}function zr(e,t,n){var r=0;t&&(r|=4),Hr(n,e,r,t)}var $r="_reactListening"+Math.random().toString(36).slice(2);function Ur(e){if(!e[$r]){e[$r]=!0,i.forEach((function(t){"selectionchange"!==t&&(Dr.has(t)||zr(t,!1,e),zr(t,!0,e))}));var t=9===e.nodeType?e:e.ownerDocument;null===t||t[$r]||(t[$r]=!0,zr("selectionchange",!1,t))}}function Hr(e,t,n,r){switch(Yt(t)){case 1:var o=Wt;break;case 4:o=Qt;break;default:o=qt}n=o.bind(null,t,n,e),o=void 0,!Ne||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(o=!0),r?void 0!==o?e.addEventListener(t,n,{capture:!0,passive:o}):e.addEventListener(t,n,!0):void 0!==o?e.addEventListener(t,n,{passive:o}):e.addEventListener(t,n,!1)}function Vr(e,t,n,r,o){var a=r;if(!(1&t||2&t||null===r))e:for(;;){if(null===r)return;var i=r.tag;if(3===i||4===i){var s=r.stateNode.containerInfo;if(s===o||8===s.nodeType&&s.parentNode===o)break;if(4===i)for(i=r.return;null!==i;){var c=i.tag;if((3===c||4===c)&&((c=i.stateNode.containerInfo)===o||8===c.nodeType&&c.parentNode===o))return;i=i.return}for(;null!==s;){if(null===(i=yo(s)))return;if(5===(c=i.tag)||6===c){r=a=i;continue e}s=s.parentNode}}r=r.return}Te((function(){var r=a,o=_e(n),i=[];e:{var s=Ar.get(e);if(void 0!==s){var c=un,l=e;switch(e){case"keypress":if(0===tn(n))break e;case"keydown":case"keyup":c=jn;break;case"focusin":l="focus",c=vn;break;case"focusout":l="blur",c=vn;break;case"beforeblur":case"afterblur":c=vn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":c=mn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":c=hn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":c=Cn;break;case Or:case jr:case Pr:c=gn;break;case Cr:c=An;break;case"scroll":c=dn;break;case"wheel":c=In;break;case"copy":case"cut":case"paste":c=yn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":c=Pn}var u=!!(4&t),p=!u&&"scroll"===e,d=u?null!==s?s+"Capture":null:s;u=[];for(var f,m=r;null!==m;){var h=(f=m).stateNode;if(5===f.tag&&null!==h&&(f=h,null!==d&&(null!=(h=Ie(m,d))&&u.push(Wr(m,h,f)))),p)break;m=m.return}0<u.length&&(s=new c(s,l,null,n,o),i.push({event:s,listeners:u}))}}if(!(7&t)){if(c="mouseout"===e||"pointerout"===e,(!(s="mouseover"===e||"pointerover"===e)||n===we||!(l=n.relatedTarget||n.fromElement)||!yo(l)&&!l[ho])&&(c||s)&&(s=o.window===o?o:(s=o.ownerDocument)?s.defaultView||s.parentWindow:window,c?(c=r,null!==(l=(l=n.relatedTarget||n.toElement)?yo(l):null)&&(l!==(p=Ue(l))||5!==l.tag&&6!==l.tag)&&(l=null)):(c=null,l=r),c!==l)){if(u=mn,h="onMouseLeave",d="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(u=Pn,h="onPointerLeave",d="onPointerEnter",m="pointer"),p=null==c?s:_o(c),f=null==l?s:_o(l),(s=new u(h,m+"leave",c,n,o)).target=p,s.relatedTarget=f,h=null,yo(o)===r&&((u=new u(d,m+"enter",l,n,o)).target=f,u.relatedTarget=p,h=u),p=h,c&&l)e:{for(d=l,m=0,f=u=c;f;f=qr(f))m++;for(f=0,h=d;h;h=qr(h))f++;for(;0<m-f;)u=qr(u),m--;for(;0<f-m;)d=qr(d),f--;for(;m--;){if(u===d||null!==d&&u===d.alternate)break e;u=qr(u),d=qr(d)}u=null}else u=null;null!==c&&Gr(i,s,c,u,!1),null!==l&&null!==p&&Gr(i,p,l,u,!0)}if("select"===(c=(s=r?_o(r):window).nodeName&&s.nodeName.toLowerCase())||"input"===c&&"file"===s.type)var v=Yn;else if(Vn(s))if(Zn)v=ir;else{v=or;var g=rr}else(c=s.nodeName)&&"input"===c.toLowerCase()&&("checkbox"===s.type||"radio"===s.type)&&(v=ar);switch(v&&(v=v(e,r))?Wn(i,v,n,o):(g&&g(e,s,r),"focusout"===e&&(g=s._wrapperState)&&g.controlled&&"number"===s.type&&ee(s,"number",s.value)),g=r?_o(r):window,e){case"focusin":(Vn(g)||"true"===g.contentEditable)&&(vr=g,gr=r,br=null);break;case"focusout":br=gr=vr=null;break;case"mousedown":yr=!0;break;case"contextmenu":case"mouseup":case"dragend":yr=!1,wr(i,n,o);break;case"selectionchange":if(hr)break;case"keydown":case"keyup":wr(i,n,o)}var b;if(Ln)e:{switch(e){case"compositionstart":var y="onCompositionStart";break e;case"compositionend":y="onCompositionEnd";break e;case"compositionupdate":y="onCompositionUpdate";break e}y=void 0}else Un?zn(e,n)&&(y="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(y="onCompositionStart");y&&(Fn&&"ko"!==n.locale&&(Un||"onCompositionStart"!==y?"onCompositionEnd"===y&&Un&&(b=en()):(Xt="value"in(Zt=o)?Zt.value:Zt.textContent,Un=!0)),0<(g=Qr(r,y)).length&&(y=new wn(y,e,null,n,o),i.push({event:y,listeners:g}),b?y.data=b:null!==(b=$n(n))&&(y.data=b))),(b=Dn?function(e,t){switch(e){case"compositionend":return $n(t);case"keypress":return 32!==t.which?null:(Bn=!0,Mn);case"textInput":return(e=t.data)===Mn&&Bn?null:e;default:return null}}(e,n):function(e,t){if(Un)return"compositionend"===e||!Ln&&zn(e,t)?(e=en(),Jt=Xt=Zt=null,Un=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return Fn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Qr(r,"onBeforeInput")).length&&(o=new wn("onBeforeInput","beforeinput",null,n,o),i.push({event:o,listeners:r}),o.data=b))}Mr(i,t)}))}function Wr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Qr(e,t){for(var n=t+"Capture",r=[];null!==e;){var o=e,a=o.stateNode;5===o.tag&&null!==a&&(o=a,null!=(a=Ie(e,n))&&r.unshift(Wr(e,a,o)),null!=(a=Ie(e,t))&&r.push(Wr(e,a,o))),e=e.return}return r}function qr(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Gr(e,t,n,r,o){for(var a=t._reactName,i=[];null!==n&&n!==r;){var s=n,c=s.alternate,l=s.stateNode;if(null!==c&&c===r)break;5===s.tag&&null!==l&&(s=l,o?null!=(c=Ie(n,a))&&i.unshift(Wr(n,c,s)):o||null!=(c=Ie(n,a))&&i.push(Wr(n,c,s))),n=n.return}0!==i.length&&e.push({event:t,listeners:i})}var Kr=/\r\n?/g,Yr=/\u0000|\uFFFD/g;function Zr(e){return("string"==typeof e?e:""+e).replace(Kr,"\n").replace(Yr,"")}function Xr(e,t,n){if(t=Zr(t),Zr(e)!==t&&n)throw Error(a(425))}function Jr(){}var eo=null,to=null;function no(e,t){return"textarea"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var ro="function"==typeof setTimeout?setTimeout:void 0,oo="function"==typeof clearTimeout?clearTimeout:void 0,ao="function"==typeof Promise?Promise:void 0,io="function"==typeof queueMicrotask?queueMicrotask:void 0!==ao?function(e){return ao.resolve(null).then(e).catch(so)}:ro;function so(e){setTimeout((function(){throw e}))}function co(e,t){var n=t,r=0;do{var o=n.nextSibling;if(e.removeChild(n),o&&8===o.nodeType)if("/$"===(n=o.data)){if(0===r)return e.removeChild(o),void Ut(t);r--}else"$"!==n&&"$?"!==n&&"$!"!==n||r++;n=o}while(n);Ut(t)}function lo(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break;if(8===t){if("$"===(t=e.data)||"$!"===t||"$?"===t)break;if("/$"===t)return null}}return e}function uo(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var po=Math.random().toString(36).slice(2),fo="__reactFiber$"+po,mo="__reactProps$"+po,ho="__reactContainer$"+po,vo="__reactEvents$"+po,go="__reactListeners$"+po,bo="__reactHandles$"+po;function yo(e){var t=e[fo];if(t)return t;for(var n=e.parentNode;n;){if(t=n[ho]||n[fo]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=uo(e);null!==e;){if(n=e[fo])return n;e=uo(e)}return t}n=(e=n).parentNode}return null}function wo(e){return!(e=e[fo]||e[ho])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function _o(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(a(33))}function xo(e){return e[mo]||null}var So=[],ko=-1;function Eo(e){return{current:e}}function Oo(e){0>ko||(e.current=So[ko],So[ko]=null,ko--)}function jo(e,t){ko++,So[ko]=e.current,e.current=t}var Po={},Co=Eo(Po),Ao=Eo(!1),To=Po;function Io(e,t){var n=e.type.contextTypes;if(!n)return Po;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o,a={};for(o in n)a[o]=t[o];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=a),a}function No(e){return null!=(e=e.childContextTypes)}function Lo(){Oo(Ao),Oo(Co)}function Ro(e,t,n){if(Co.current!==Po)throw Error(a(168));jo(Co,t),jo(Ao,n)}function Do(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var o in r=r.getChildContext())if(!(o in t))throw Error(a(108,H(e)||"Unknown",o));return F({},n,r)}function Fo(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Po,To=Co.current,jo(Co,e),jo(Ao,Ao.current),!0}function Mo(e,t,n){var r=e.stateNode;if(!r)throw Error(a(169));n?(e=Do(e,t,To),r.__reactInternalMemoizedMergedChildContext=e,Oo(Ao),Oo(Co),jo(Co,e)):Oo(Ao),jo(Ao,n)}var Bo=null,zo=!1,$o=!1;function Uo(e){null===Bo?Bo=[e]:Bo.push(e)}function Ho(){if(!$o&&null!==Bo){$o=!0;var e=0,t=yt;try{var n=Bo;for(yt=1;e<n.length;e++){var r=n[e];do{r=r(!0)}while(null!==r)}Bo=null,zo=!1}catch(o){throw null!==Bo&&(Bo=Bo.slice(e+1)),qe(Je,Ho),o}finally{yt=t,$o=!1}}return null}var Vo=[],Wo=0,Qo=null,qo=0,Go=[],Ko=0,Yo=null,Zo=1,Xo="";function Jo(e,t){Vo[Wo++]=qo,Vo[Wo++]=Qo,Qo=e,qo=t}function ea(e,t,n){Go[Ko++]=Zo,Go[Ko++]=Xo,Go[Ko++]=Yo,Yo=e;var r=Zo;e=Xo;var o=32-it(r)-1;r&=~(1<<o),n+=1;var a=32-it(t)+o;if(30<a){var i=o-o%5;a=(r&(1<<i)-1).toString(32),r>>=i,o-=i,Zo=1<<32-it(t)+o|n<<o|r,Xo=a+e}else Zo=1<<a|n<<o|r,Xo=e}function ta(e){null!==e.return&&(Jo(e,1),ea(e,1,0))}function na(e){for(;e===Qo;)Qo=Vo[--Wo],Vo[Wo]=null,qo=Vo[--Wo],Vo[Wo]=null;for(;e===Yo;)Yo=Go[--Ko],Go[Ko]=null,Xo=Go[--Ko],Go[Ko]=null,Zo=Go[--Ko],Go[Ko]=null}var ra=null,oa=null,aa=!1,ia=null;function sa(e,t){var n=Tl(5,null,null,0);n.elementType="DELETED",n.stateNode=t,n.return=e,null===(t=e.deletions)?(e.deletions=[n],e.flags|=16):t.push(n)}function ca(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,ra=e,oa=lo(t.firstChild),!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,ra=e,oa=null,!0);case 13:return null!==(t=8!==t.nodeType?null:t)&&(n=null!==Yo?{id:Zo,overflow:Xo}:null,e.memoizedState={dehydrated:t,treeContext:n,retryLane:1073741824},(n=Tl(18,null,null,0)).stateNode=t,n.return=e,e.child=n,ra=e,oa=null,!0);default:return!1}}function la(e){return!(!(1&e.mode)||128&e.flags)}function ua(e){if(aa){var t=oa;if(t){var n=t;if(!ca(e,t)){if(la(e))throw Error(a(418));t=lo(n.nextSibling);var r=ra;t&&ca(e,t)?sa(r,n):(e.flags=-4097&e.flags|2,aa=!1,ra=e)}}else{if(la(e))throw Error(a(418));e.flags=-4097&e.flags|2,aa=!1,ra=e}}}function pa(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;ra=e}function da(e){if(e!==ra)return!1;if(!aa)return pa(e),aa=!0,!1;var t;if((t=3!==e.tag)&&!(t=5!==e.tag)&&(t="head"!==(t=e.type)&&"body"!==t&&!no(e.type,e.memoizedProps)),t&&(t=oa)){if(la(e))throw fa(),Error(a(418));for(;t;)sa(e,t),t=lo(t.nextSibling)}if(pa(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(a(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){oa=lo(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}oa=null}}else oa=ra?lo(e.stateNode.nextSibling):null;return!0}function fa(){for(var e=oa;e;)e=lo(e.nextSibling)}function ma(){oa=ra=null,aa=!1}function ha(e){null===ia?ia=[e]:ia.push(e)}var va=w.ReactCurrentBatchConfig;function ga(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(a(309));var r=n.stateNode}if(!r)throw Error(a(147,e));var o=r,i=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===i?t.ref:(t=function(e){var t=o.refs;null===e?delete t[i]:t[i]=e},t._stringRef=i,t)}if("string"!=typeof e)throw Error(a(284));if(!n._owner)throw Error(a(290,e))}return e}function ba(e,t){throw e=Object.prototype.toString.call(t),Error(a(31,"[object Object]"===e?"object with keys {"+Object.keys(t).join(", ")+"}":e))}function ya(e){return(0,e._init)(e._payload)}function wa(e){function t(t,n){if(e){var r=t.deletions;null===r?(t.deletions=[n],t.flags|=16):r.push(n)}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function o(e,t){return(e=Nl(e,t)).index=0,e.sibling=null,e}function i(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags|=2,n):r:(t.flags|=2,n):(t.flags|=1048576,n)}function s(t){return e&&null===t.alternate&&(t.flags|=2),t}function c(e,t,n,r){return null===t||6!==t.tag?((t=Fl(n,e.mode,r)).return=e,t):((t=o(t,n)).return=e,t)}function l(e,t,n,r){var a=n.type;return a===S?p(e,t,n.props.children,r,n.key):null!==t&&(t.elementType===a||"object"==typeof a&&null!==a&&a.$$typeof===I&&ya(a)===t.type)?((r=o(t,n.props)).ref=ga(e,t,n),r.return=e,r):((r=Ll(n.type,n.key,n.props,null,e.mode,r)).ref=ga(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Ml(n,e.mode,r)).return=e,t):((t=o(t,n.children||[])).return=e,t)}function p(e,t,n,r,a){return null===t||7!==t.tag?((t=Rl(n,e.mode,r,a)).return=e,t):((t=o(t,n)).return=e,t)}function d(e,t,n){if("string"==typeof t&&""!==t||"number"==typeof t)return(t=Fl(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case _:return(n=Ll(t.type,t.key,t.props,null,e.mode,n)).ref=ga(e,null,t),n.return=e,n;case x:return(t=Ml(t,e.mode,n)).return=e,t;case I:return d(e,(0,t._init)(t._payload),n)}if(te(t)||R(t))return(t=Rl(t,e.mode,n,null)).return=e,t;ba(e,t)}return null}function f(e,t,n,r){var o=null!==t?t.key:null;if("string"==typeof n&&""!==n||"number"==typeof n)return null!==o?null:c(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case _:return n.key===o?l(e,t,n,r):null;case x:return n.key===o?u(e,t,n,r):null;case I:return f(e,t,(o=n._init)(n._payload),r)}if(te(n)||R(n))return null!==o?null:p(e,t,n,r,null);ba(e,n)}return null}function m(e,t,n,r,o){if("string"==typeof r&&""!==r||"number"==typeof r)return c(t,e=e.get(n)||null,""+r,o);if("object"==typeof r&&null!==r){switch(r.$$typeof){case _:return l(t,e=e.get(null===r.key?n:r.key)||null,r,o);case x:return u(t,e=e.get(null===r.key?n:r.key)||null,r,o);case I:return m(e,t,n,(0,r._init)(r._payload),o)}if(te(r)||R(r))return p(t,e=e.get(n)||null,r,o,null);ba(t,r)}return null}function h(o,a,s,c){for(var l=null,u=null,p=a,h=a=0,v=null;null!==p&&h<s.length;h++){p.index>h?(v=p,p=null):v=p.sibling;var g=f(o,p,s[h],c);if(null===g){null===p&&(p=v);break}e&&p&&null===g.alternate&&t(o,p),a=i(g,a,h),null===u?l=g:u.sibling=g,u=g,p=v}if(h===s.length)return n(o,p),aa&&Jo(o,h),l;if(null===p){for(;h<s.length;h++)null!==(p=d(o,s[h],c))&&(a=i(p,a,h),null===u?l=p:u.sibling=p,u=p);return aa&&Jo(o,h),l}for(p=r(o,p);h<s.length;h++)null!==(v=m(p,o,h,s[h],c))&&(e&&null!==v.alternate&&p.delete(null===v.key?h:v.key),a=i(v,a,h),null===u?l=v:u.sibling=v,u=v);return e&&p.forEach((function(e){return t(o,e)})),aa&&Jo(o,h),l}function v(o,s,c,l){var u=R(c);if("function"!=typeof u)throw Error(a(150));if(null==(c=u.call(c)))throw Error(a(151));for(var p=u=null,h=s,v=s=0,g=null,b=c.next();null!==h&&!b.done;v++,b=c.next()){h.index>v?(g=h,h=null):g=h.sibling;var y=f(o,h,b.value,l);if(null===y){null===h&&(h=g);break}e&&h&&null===y.alternate&&t(o,h),s=i(y,s,v),null===p?u=y:p.sibling=y,p=y,h=g}if(b.done)return n(o,h),aa&&Jo(o,v),u;if(null===h){for(;!b.done;v++,b=c.next())null!==(b=d(o,b.value,l))&&(s=i(b,s,v),null===p?u=b:p.sibling=b,p=b);return aa&&Jo(o,v),u}for(h=r(o,h);!b.done;v++,b=c.next())null!==(b=m(h,o,v,b.value,l))&&(e&&null!==b.alternate&&h.delete(null===b.key?v:b.key),s=i(b,s,v),null===p?u=b:p.sibling=b,p=b);return e&&h.forEach((function(e){return t(o,e)})),aa&&Jo(o,v),u}return function e(r,a,i,c){if("object"==typeof i&&null!==i&&i.type===S&&null===i.key&&(i=i.props.children),"object"==typeof i&&null!==i){switch(i.$$typeof){case _:e:{for(var l=i.key,u=a;null!==u;){if(u.key===l){if((l=i.type)===S){if(7===u.tag){n(r,u.sibling),(a=o(u,i.props.children)).return=r,r=a;break e}}else if(u.elementType===l||"object"==typeof l&&null!==l&&l.$$typeof===I&&ya(l)===u.type){n(r,u.sibling),(a=o(u,i.props)).ref=ga(r,u,i),a.return=r,r=a;break e}n(r,u);break}t(r,u),u=u.sibling}i.type===S?((a=Rl(i.props.children,r.mode,c,i.key)).return=r,r=a):((c=Ll(i.type,i.key,i.props,null,r.mode,c)).ref=ga(r,a,i),c.return=r,r=c)}return s(r);case x:e:{for(u=i.key;null!==a;){if(a.key===u){if(4===a.tag&&a.stateNode.containerInfo===i.containerInfo&&a.stateNode.implementation===i.implementation){n(r,a.sibling),(a=o(a,i.children||[])).return=r,r=a;break e}n(r,a);break}t(r,a),a=a.sibling}(a=Ml(i,r.mode,c)).return=r,r=a}return s(r);case I:return e(r,a,(u=i._init)(i._payload),c)}if(te(i))return h(r,a,i,c);if(R(i))return v(r,a,i,c);ba(r,i)}return"string"==typeof i&&""!==i||"number"==typeof i?(i=""+i,null!==a&&6===a.tag?(n(r,a.sibling),(a=o(a,i)).return=r,r=a):(n(r,a),(a=Fl(i,r.mode,c)).return=r,r=a),s(r)):n(r,a)}}var _a=wa(!0),xa=wa(!1),Sa=Eo(null),ka=null,Ea=null,Oa=null;function ja(){Oa=Ea=ka=null}function Pa(e){var t=Sa.current;Oo(Sa),e._currentValue=t}function Ca(e,t,n){for(;null!==e;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,null!==r&&(r.childLanes|=t)):null!==r&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Aa(e,t){ka=e,Oa=Ea=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(!!(e.lanes&t)&&(ys=!0),e.firstContext=null)}function Ta(e){var t=e._currentValue;if(Oa!==e)if(e={context:e,memoizedValue:t,next:null},null===Ea){if(null===ka)throw Error(a(308));Ea=e,ka.dependencies={lanes:0,firstContext:e}}else Ea=Ea.next=e;return t}var Ia=null;function Na(e){null===Ia?Ia=[e]:Ia.push(e)}function La(e,t,n,r){var o=t.interleaved;return null===o?(n.next=n,Na(t)):(n.next=o.next,o.next=n),t.interleaved=n,Ra(e,r)}function Ra(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}var Da=!1;function Fa(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Ma(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ba(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function za(e,t,n){var r=e.updateQueue;if(null===r)return null;if(r=r.shared,2&Pc){var o=r.pending;return null===o?t.next=t:(t.next=o.next,o.next=t),r.pending=t,Ra(e,n)}return null===(o=r.interleaved)?(t.next=t,Na(r)):(t.next=o.next,o.next=t),r.interleaved=t,Ra(e,n)}function $a(e,t,n){if(null!==(t=t.updateQueue)&&(t=t.shared,4194240&n)){var r=t.lanes;n|=r&=e.pendingLanes,t.lanes=n,bt(e,n)}}function Ua(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var o=null,a=null;if(null!==(n=n.firstBaseUpdate)){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===a?o=a=i:a=a.next=i,n=n.next}while(null!==n);null===a?o=a=t:a=a.next=t}else o=a=t;return n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:a,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Ha(e,t,n,r){var o=e.updateQueue;Da=!1;var a=o.firstBaseUpdate,i=o.lastBaseUpdate,s=o.shared.pending;if(null!==s){o.shared.pending=null;var c=s,l=c.next;c.next=null,null===i?a=l:i.next=l,i=c;var u=e.alternate;null!==u&&((s=(u=u.updateQueue).lastBaseUpdate)!==i&&(null===s?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(null!==a){var p=o.baseState;for(i=0,u=l=c=null,s=a;;){var d=s.lane,f=s.eventTime;if((r&d)===d){null!==u&&(u=u.next={eventTime:f,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var m=e,h=s;switch(d=t,f=n,h.tag){case 1:if("function"==typeof(m=h.payload)){p=m.call(f,p,d);break e}p=m;break e;case 3:m.flags=-65537&m.flags|128;case 0:if(null==(d="function"==typeof(m=h.payload)?m.call(f,p,d):m))break e;p=F({},p,d);break e;case 2:Da=!0}}null!==s.callback&&0!==s.lane&&(e.flags|=64,null===(d=o.effects)?o.effects=[s]:d.push(s))}else f={eventTime:f,lane:d,tag:s.tag,payload:s.payload,callback:s.callback,next:null},null===u?(l=u=f,c=p):u=u.next=f,i|=d;if(null===(s=s.next)){if(null===(s=o.shared.pending))break;s=(d=s).next,d.next=null,o.lastBaseUpdate=d,o.shared.pending=null}}if(null===u&&(c=p),o.baseState=c,o.firstBaseUpdate=l,o.lastBaseUpdate=u,null!==(t=o.shared.interleaved)){o=t;do{i|=o.lane,o=o.next}while(o!==t)}else null===a&&(o.shared.lanes=0);Dc|=i,e.lanes=i,e.memoizedState=p}}function Va(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],o=r.callback;if(null!==o){if(r.callback=null,r=n,"function"!=typeof o)throw Error(a(191,o));o.call(r)}}}var Wa={},Qa=Eo(Wa),qa=Eo(Wa),Ga=Eo(Wa);function Ka(e){if(e===Wa)throw Error(a(174));return e}function Ya(e,t){switch(jo(Ga,t),jo(qa,e),jo(Qa,Wa),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:ce(null,"");break;default:t=ce(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}Oo(Qa),jo(Qa,t)}function Za(){Oo(Qa),Oo(qa),Oo(Ga)}function Xa(e){Ka(Ga.current);var t=Ka(Qa.current),n=ce(t,e.type);t!==n&&(jo(qa,e),jo(Qa,n))}function Ja(e){qa.current===e&&(Oo(Qa),Oo(qa))}var ei=Eo(0);function ti(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(128&t.flags)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var ni=[];function ri(){for(var e=0;e<ni.length;e++)ni[e]._workInProgressVersionPrimary=null;ni.length=0}var oi=w.ReactCurrentDispatcher,ai=w.ReactCurrentBatchConfig,ii=0,si=null,ci=null,li=null,ui=!1,pi=!1,di=0,fi=0;function mi(){throw Error(a(321))}function hi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!sr(e[n],t[n]))return!1;return!0}function vi(e,t,n,r,o,i){if(ii=i,si=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,oi.current=null===e||null===e.memoizedState?Ji:es,e=n(r,o),pi){i=0;do{if(pi=!1,di=0,25<=i)throw Error(a(301));i+=1,li=ci=null,t.updateQueue=null,oi.current=ts,e=n(r,o)}while(pi)}if(oi.current=Xi,t=null!==ci&&null!==ci.next,ii=0,li=ci=si=null,ui=!1,t)throw Error(a(300));return e}function gi(){var e=0!==di;return di=0,e}function bi(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===li?si.memoizedState=li=e:li=li.next=e,li}function yi(){if(null===ci){var e=si.alternate;e=null!==e?e.memoizedState:null}else e=ci.next;var t=null===li?si.memoizedState:li.next;if(null!==t)li=t,ci=e;else{if(null===e)throw Error(a(310));e={memoizedState:(ci=e).memoizedState,baseState:ci.baseState,baseQueue:ci.baseQueue,queue:ci.queue,next:null},null===li?si.memoizedState=li=e:li=li.next=e}return li}function wi(e,t){return"function"==typeof t?t(e):t}function _i(e){var t=yi(),n=t.queue;if(null===n)throw Error(a(311));n.lastRenderedReducer=e;var r=ci,o=r.baseQueue,i=n.pending;if(null!==i){if(null!==o){var s=o.next;o.next=i.next,i.next=s}r.baseQueue=o=i,n.pending=null}if(null!==o){i=o.next,r=r.baseState;var c=s=null,l=null,u=i;do{var p=u.lane;if((ii&p)===p)null!==l&&(l=l.next={lane:0,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null}),r=u.hasEagerState?u.eagerState:e(r,u.action);else{var d={lane:p,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null};null===l?(c=l=d,s=r):l=l.next=d,si.lanes|=p,Dc|=p}u=u.next}while(null!==u&&u!==i);null===l?s=r:l.next=c,sr(r,t.memoizedState)||(ys=!0),t.memoizedState=r,t.baseState=s,t.baseQueue=l,n.lastRenderedState=r}if(null!==(e=n.interleaved)){o=e;do{i=o.lane,si.lanes|=i,Dc|=i,o=o.next}while(o!==e)}else null===o&&(n.lanes=0);return[t.memoizedState,n.dispatch]}function xi(e){var t=yi(),n=t.queue;if(null===n)throw Error(a(311));n.lastRenderedReducer=e;var r=n.dispatch,o=n.pending,i=t.memoizedState;if(null!==o){n.pending=null;var s=o=o.next;do{i=e(i,s.action),s=s.next}while(s!==o);sr(i,t.memoizedState)||(ys=!0),t.memoizedState=i,null===t.baseQueue&&(t.baseState=i),n.lastRenderedState=i}return[i,r]}function Si(){}function ki(e,t){var n=si,r=yi(),o=t(),i=!sr(r.memoizedState,o);if(i&&(r.memoizedState=o,ys=!0),r=r.queue,Di(ji.bind(null,n,r,e),[e]),r.getSnapshot!==t||i||null!==li&&1&li.memoizedState.tag){if(n.flags|=2048,Ti(9,Oi.bind(null,n,r,o,t),void 0,null),null===Cc)throw Error(a(349));30&ii||Ei(n,t,o)}return o}function Ei(e,t,n){e.flags|=16384,e={getSnapshot:t,value:n},null===(t=si.updateQueue)?(t={lastEffect:null,stores:null},si.updateQueue=t,t.stores=[e]):null===(n=t.stores)?t.stores=[e]:n.push(e)}function Oi(e,t,n,r){t.value=n,t.getSnapshot=r,Pi(t)&&Ci(e)}function ji(e,t,n){return n((function(){Pi(t)&&Ci(e)}))}function Pi(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!sr(e,n)}catch(r){return!0}}function Ci(e){var t=Ra(e,1);null!==t&&nl(t,e,1,-1)}function Ai(e){var t=bi();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:wi,lastRenderedState:e},t.queue=e,e=e.dispatch=Gi.bind(null,si,e),[t.memoizedState,e]}function Ti(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=si.updateQueue)?(t={lastEffect:null,stores:null},si.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function Ii(){return yi().memoizedState}function Ni(e,t,n,r){var o=bi();si.flags|=e,o.memoizedState=Ti(1|t,n,void 0,void 0===r?null:r)}function Li(e,t,n,r){var o=yi();r=void 0===r?null:r;var a=void 0;if(null!==ci){var i=ci.memoizedState;if(a=i.destroy,null!==r&&hi(r,i.deps))return void(o.memoizedState=Ti(t,n,a,r))}si.flags|=e,o.memoizedState=Ti(1|t,n,a,r)}function Ri(e,t){return Ni(8390656,8,e,t)}function Di(e,t){return Li(2048,8,e,t)}function Fi(e,t){return Li(4,2,e,t)}function Mi(e,t){return Li(4,4,e,t)}function Bi(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function zi(e,t,n){return n=null!=n?n.concat([e]):null,Li(4,4,Bi.bind(null,t,e),n)}function $i(){}function Ui(e,t){var n=yi();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&hi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Hi(e,t){var n=yi();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&hi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Vi(e,t,n){return 21&ii?(sr(n,t)||(n=ht(),si.lanes|=n,Dc|=n,e.baseState=!0),t):(e.baseState&&(e.baseState=!1,ys=!0),e.memoizedState=n)}function Wi(e,t){var n=yt;yt=0!==n&&4>n?n:4,e(!0);var r=ai.transition;ai.transition={};try{e(!1),t()}finally{yt=n,ai.transition=r}}function Qi(){return yi().memoizedState}function qi(e,t,n){var r=tl(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ki(e))Yi(t,n);else if(null!==(n=La(e,t,n,r))){nl(n,e,r,el()),Zi(n,t,r)}}function Gi(e,t,n){var r=tl(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ki(e))Yi(t,o);else{var a=e.alternate;if(0===e.lanes&&(null===a||0===a.lanes)&&null!==(a=t.lastRenderedReducer))try{var i=t.lastRenderedState,s=a(i,n);if(o.hasEagerState=!0,o.eagerState=s,sr(s,i)){var c=t.interleaved;return null===c?(o.next=o,Na(t)):(o.next=c.next,c.next=o),void(t.interleaved=o)}}catch(l){}null!==(n=La(e,t,o,r))&&(nl(n,e,r,o=el()),Zi(n,t,r))}}function Ki(e){var t=e.alternate;return e===si||null!==t&&t===si}function Yi(e,t){pi=ui=!0;var n=e.pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Zi(e,t,n){if(4194240&n){var r=t.lanes;n|=r&=e.pendingLanes,t.lanes=n,bt(e,n)}}var Xi={readContext:Ta,useCallback:mi,useContext:mi,useEffect:mi,useImperativeHandle:mi,useInsertionEffect:mi,useLayoutEffect:mi,useMemo:mi,useReducer:mi,useRef:mi,useState:mi,useDebugValue:mi,useDeferredValue:mi,useTransition:mi,useMutableSource:mi,useSyncExternalStore:mi,useId:mi,unstable_isNewReconciler:!1},Ji={readContext:Ta,useCallback:function(e,t){return bi().memoizedState=[e,void 0===t?null:t],e},useContext:Ta,useEffect:Ri,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,Ni(4194308,4,Bi.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ni(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ni(4,2,e,t)},useMemo:function(e,t){var n=bi();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=bi();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=qi.bind(null,si,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},bi().memoizedState=e},useState:Ai,useDebugValue:$i,useDeferredValue:function(e){return bi().memoizedState=e},useTransition:function(){var e=Ai(!1),t=e[0];return e=Wi.bind(null,e[1]),bi().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=si,o=bi();if(aa){if(void 0===n)throw Error(a(407));n=n()}else{if(n=t(),null===Cc)throw Error(a(349));30&ii||Ei(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,Ri(ji.bind(null,r,i,e),[e]),r.flags|=2048,Ti(9,Oi.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=bi(),t=Cc.identifierPrefix;if(aa){var n=Xo;t=":"+t+"R"+(n=(Zo&~(1<<32-it(Zo)-1)).toString(32)+n),0<(n=di++)&&(t+="H"+n.toString(32)),t+=":"}else t=":"+t+"r"+(n=fi++).toString(32)+":";return e.memoizedState=t},unstable_isNewReconciler:!1},es={readContext:Ta,useCallback:Ui,useContext:Ta,useEffect:Di,useImperativeHandle:zi,useInsertionEffect:Fi,useLayoutEffect:Mi,useMemo:Hi,useReducer:_i,useRef:Ii,useState:function(){return _i(wi)},useDebugValue:$i,useDeferredValue:function(e){return Vi(yi(),ci.memoizedState,e)},useTransition:function(){return[_i(wi)[0],yi().memoizedState]},useMutableSource:Si,useSyncExternalStore:ki,useId:Qi,unstable_isNewReconciler:!1},ts={readContext:Ta,useCallback:Ui,useContext:Ta,useEffect:Di,useImperativeHandle:zi,useInsertionEffect:Fi,useLayoutEffect:Mi,useMemo:Hi,useReducer:xi,useRef:Ii,useState:function(){return xi(wi)},useDebugValue:$i,useDeferredValue:function(e){var t=yi();return null===ci?t.memoizedState=e:Vi(t,ci.memoizedState,e)},useTransition:function(){return[xi(wi)[0],yi().memoizedState]},useMutableSource:Si,useSyncExternalStore:ki,useId:Qi,unstable_isNewReconciler:!1};function ns(e,t){if(e&&e.defaultProps){for(var n in t=F({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}function rs(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:F({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var os={isMounted:function(e){return!!(e=e._reactInternals)&&Ue(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=el(),o=tl(e),a=Ba(r,o);a.payload=t,null!=n&&(a.callback=n),null!==(t=za(e,a,o))&&(nl(t,e,o,r),$a(t,e,o))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=el(),o=tl(e),a=Ba(r,o);a.tag=1,a.payload=t,null!=n&&(a.callback=n),null!==(t=za(e,a,o))&&(nl(t,e,o,r),$a(t,e,o))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=el(),r=tl(e),o=Ba(n,r);o.tag=2,null!=t&&(o.callback=t),null!==(t=za(e,o,r))&&(nl(t,e,r,n),$a(t,e,r))}};function as(e,t,n,r,o,a,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,a,i):!t.prototype||!t.prototype.isPureReactComponent||(!cr(n,r)||!cr(o,a))}function is(e,t,n){var r=!1,o=Po,a=t.contextType;return"object"==typeof a&&null!==a?a=Ta(a):(o=No(t)?To:Co.current,a=(r=null!=(r=t.contextTypes))?Io(e,o):Po),t=new t(n,a),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=os,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=o,e.__reactInternalMemoizedMaskedChildContext=a),t}function ss(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&os.enqueueReplaceState(t,t.state,null)}function cs(e,t,n,r){var o=e.stateNode;o.props=n,o.state=e.memoizedState,o.refs={},Fa(e);var a=t.contextType;"object"==typeof a&&null!==a?o.context=Ta(a):(a=No(t)?To:Co.current,o.context=Io(e,a)),o.state=e.memoizedState,"function"==typeof(a=t.getDerivedStateFromProps)&&(rs(e,t,a,n),o.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof o.getSnapshotBeforeUpdate||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||(t=o.state,"function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount(),t!==o.state&&os.enqueueReplaceState(o,o.state,null),Ha(e,n,o,r),o.state=e.memoizedState),"function"==typeof o.componentDidMount&&(e.flags|=4194308)}function ls(e,t){try{var n="",r=t;do{n+=$(r),r=r.return}while(r);var o=n}catch(a){o="\nError generating stack: "+a.message+"\n"+a.stack}return{value:e,source:t,stack:o,digest:null}}function us(e,t,n){return{value:e,source:null,stack:null!=n?n:null,digest:null!=t?t:null}}function ps(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}var ds="function"==typeof WeakMap?WeakMap:Map;function fs(e,t,n){(n=Ba(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Vc||(Vc=!0,Wc=r),ps(0,t)},n}function ms(e,t,n){(n=Ba(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var o=t.value;n.payload=function(){return r(o)},n.callback=function(){ps(0,t)}}var a=e.stateNode;return null!==a&&"function"==typeof a.componentDidCatch&&(n.callback=function(){ps(0,t),"function"!=typeof r&&(null===Qc?Qc=new Set([this]):Qc.add(this));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}function hs(e,t,n){var r=e.pingCache;if(null===r){r=e.pingCache=new ds;var o=new Set;r.set(t,o)}else void 0===(o=r.get(t))&&(o=new Set,r.set(t,o));o.has(n)||(o.add(n),e=El.bind(null,e,t,n),t.then(e,e))}function vs(e){do{var t;if((t=13===e.tag)&&(t=null===(t=e.memoizedState)||null!==t.dehydrated),t)return e;e=e.return}while(null!==e);return null}function gs(e,t,n,r,o){return 1&e.mode?(e.flags|=65536,e.lanes=o,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,1===n.tag&&(null===n.alternate?n.tag=17:((t=Ba(-1,1)).tag=2,za(n,t,1))),n.lanes|=1),e)}var bs=w.ReactCurrentOwner,ys=!1;function ws(e,t,n,r){t.child=null===e?xa(t,null,n,r):_a(t,e.child,n,r)}function _s(e,t,n,r,o){n=n.render;var a=t.ref;return Aa(t,o),r=vi(e,t,n,r,a,o),n=gi(),null===e||ys?(aa&&n&&ta(t),t.flags|=1,ws(e,t,r,o),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Vs(e,t,o))}function xs(e,t,n,r,o){if(null===e){var a=n.type;return"function"!=typeof a||Il(a)||void 0!==a.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Ll(n.type,null,r,t,t.mode,o)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=a,Ss(e,t,a,r,o))}if(a=e.child,!(e.lanes&o)){var i=a.memoizedProps;if((n=null!==(n=n.compare)?n:cr)(i,r)&&e.ref===t.ref)return Vs(e,t,o)}return t.flags|=1,(e=Nl(a,r)).ref=t.ref,e.return=t,t.child=e}function Ss(e,t,n,r,o){if(null!==e){var a=e.memoizedProps;if(cr(a,r)&&e.ref===t.ref){if(ys=!1,t.pendingProps=r=a,!(e.lanes&o))return t.lanes=e.lanes,Vs(e,t,o);131072&e.flags&&(ys=!0)}}return Os(e,t,n,r,o)}function ks(e,t,n){var r=t.pendingProps,o=r.children,a=null!==e?e.memoizedState:null;if("hidden"===r.mode)if(1&t.mode){if(!(1073741824&n))return e=null!==a?a.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,jo(Nc,Ic),Ic|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=null!==a?a.baseLanes:n,jo(Nc,Ic),Ic|=r}else t.memoizedState={baseLanes:0,cachePool:null,transitions:null},jo(Nc,Ic),Ic|=n;else null!==a?(r=a.baseLanes|n,t.memoizedState=null):r=n,jo(Nc,Ic),Ic|=r;return ws(e,t,o,n),t.child}function Es(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function Os(e,t,n,r,o){var a=No(n)?To:Co.current;return a=Io(t,a),Aa(t,o),n=vi(e,t,n,r,a,o),r=gi(),null===e||ys?(aa&&r&&ta(t),t.flags|=1,ws(e,t,n,o),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Vs(e,t,o))}function js(e,t,n,r,o){if(No(n)){var a=!0;Fo(t)}else a=!1;if(Aa(t,o),null===t.stateNode)Hs(e,t),is(t,n,r),cs(t,n,r,o),r=!0;else if(null===e){var i=t.stateNode,s=t.memoizedProps;i.props=s;var c=i.context,l=n.contextType;"object"==typeof l&&null!==l?l=Ta(l):l=Io(t,l=No(n)?To:Co.current);var u=n.getDerivedStateFromProps,p="function"==typeof u||"function"==typeof i.getSnapshotBeforeUpdate;p||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(s!==r||c!==l)&&ss(t,i,r,l),Da=!1;var d=t.memoizedState;i.state=d,Ha(t,r,i,o),c=t.memoizedState,s!==r||d!==c||Ao.current||Da?("function"==typeof u&&(rs(t,n,u,r),c=t.memoizedState),(s=Da||as(t,n,s,r,d,c,l))?(p||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(t.flags|=4194308)):("function"==typeof i.componentDidMount&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=c),i.props=r,i.state=c,i.context=l,r=s):("function"==typeof i.componentDidMount&&(t.flags|=4194308),r=!1)}else{i=t.stateNode,Ma(e,t),s=t.memoizedProps,l=t.type===t.elementType?s:ns(t.type,s),i.props=l,p=t.pendingProps,d=i.context,"object"==typeof(c=n.contextType)&&null!==c?c=Ta(c):c=Io(t,c=No(n)?To:Co.current);var f=n.getDerivedStateFromProps;(u="function"==typeof f||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(s!==p||d!==c)&&ss(t,i,r,c),Da=!1,d=t.memoizedState,i.state=d,Ha(t,r,i,o);var m=t.memoizedState;s!==p||d!==m||Ao.current||Da?("function"==typeof f&&(rs(t,n,f,r),m=t.memoizedState),(l=Da||as(t,n,l,r,d,m,c)||!1)?(u||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,m,c),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,m,c)),"function"==typeof i.componentDidUpdate&&(t.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(t.flags|=1024)):("function"!=typeof i.componentDidUpdate||s===e.memoizedProps&&d===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||s===e.memoizedProps&&d===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=m),i.props=r,i.state=m,i.context=c,r=l):("function"!=typeof i.componentDidUpdate||s===e.memoizedProps&&d===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||s===e.memoizedProps&&d===e.memoizedState||(t.flags|=1024),r=!1)}return Ps(e,t,n,r,a,o)}function Ps(e,t,n,r,o,a){Es(e,t);var i=!!(128&t.flags);if(!r&&!i)return o&&Mo(t,n,!1),Vs(e,t,a);r=t.stateNode,bs.current=t;var s=i&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&i?(t.child=_a(t,e.child,null,a),t.child=_a(t,null,s,a)):ws(e,t,s,a),t.memoizedState=r.state,o&&Mo(t,n,!0),t.child}function Cs(e){var t=e.stateNode;t.pendingContext?Ro(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Ro(0,t.context,!1),Ya(e,t.containerInfo)}function As(e,t,n,r,o){return ma(),ha(o),t.flags|=256,ws(e,t,n,r),t.child}var Ts,Is,Ns,Ls,Rs={dehydrated:null,treeContext:null,retryLane:0};function Ds(e){return{baseLanes:e,cachePool:null,transitions:null}}function Fs(e,t,n){var r,o=t.pendingProps,i=ei.current,s=!1,c=!!(128&t.flags);if((r=c)||(r=(null===e||null!==e.memoizedState)&&!!(2&i)),r?(s=!0,t.flags&=-129):null!==e&&null===e.memoizedState||(i|=1),jo(ei,1&i),null===e)return ua(t),null!==(e=t.memoizedState)&&null!==(e=e.dehydrated)?(1&t.mode?"$!"===e.data?t.lanes=8:t.lanes=1073741824:t.lanes=1,null):(c=o.children,e=o.fallback,s?(o=t.mode,s=t.child,c={mode:"hidden",children:c},1&o||null===s?s=Dl(c,o,0,null):(s.childLanes=0,s.pendingProps=c),e=Rl(e,o,n,null),s.return=t,e.return=t,s.sibling=e,t.child=s,t.child.memoizedState=Ds(n),t.memoizedState=Rs,e):Ms(t,c));if(null!==(i=e.memoizedState)&&null!==(r=i.dehydrated))return function(e,t,n,r,o,i,s){if(n)return 256&t.flags?(t.flags&=-257,Bs(e,t,s,r=us(Error(a(422))))):null!==t.memoizedState?(t.child=e.child,t.flags|=128,null):(i=r.fallback,o=t.mode,r=Dl({mode:"visible",children:r.children},o,0,null),(i=Rl(i,o,s,null)).flags|=2,r.return=t,i.return=t,r.sibling=i,t.child=r,1&t.mode&&_a(t,e.child,null,s),t.child.memoizedState=Ds(s),t.memoizedState=Rs,i);if(!(1&t.mode))return Bs(e,t,s,null);if("$!"===o.data){if(r=o.nextSibling&&o.nextSibling.dataset)var c=r.dgst;return r=c,Bs(e,t,s,r=us(i=Error(a(419)),r,void 0))}if(c=!!(s&e.childLanes),ys||c){if(null!==(r=Cc)){switch(s&-s){case 4:o=2;break;case 16:o=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:o=32;break;case 536870912:o=268435456;break;default:o=0}0!==(o=o&(r.suspendedLanes|s)?0:o)&&o!==i.retryLane&&(i.retryLane=o,Ra(e,o),nl(r,e,o,-1))}return hl(),Bs(e,t,s,r=us(Error(a(421))))}return"$?"===o.data?(t.flags|=128,t.child=e.child,t=jl.bind(null,e),o._reactRetry=t,null):(e=i.treeContext,oa=lo(o.nextSibling),ra=t,aa=!0,ia=null,null!==e&&(Go[Ko++]=Zo,Go[Ko++]=Xo,Go[Ko++]=Yo,Zo=e.id,Xo=e.overflow,Yo=t),t=Ms(t,r.children),t.flags|=4096,t)}(e,t,c,o,r,i,n);if(s){s=o.fallback,c=t.mode,r=(i=e.child).sibling;var l={mode:"hidden",children:o.children};return 1&c||t.child===i?(o=Nl(i,l)).subtreeFlags=14680064&i.subtreeFlags:((o=t.child).childLanes=0,o.pendingProps=l,t.deletions=null),null!==r?s=Nl(r,s):(s=Rl(s,c,n,null)).flags|=2,s.return=t,o.return=t,o.sibling=s,t.child=o,o=s,s=t.child,c=null===(c=e.child.memoizedState)?Ds(n):{baseLanes:c.baseLanes|n,cachePool:null,transitions:c.transitions},s.memoizedState=c,s.childLanes=e.childLanes&~n,t.memoizedState=Rs,o}return e=(s=e.child).sibling,o=Nl(s,{mode:"visible",children:o.children}),!(1&t.mode)&&(o.lanes=n),o.return=t,o.sibling=null,null!==e&&(null===(n=t.deletions)?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=o,t.memoizedState=null,o}function Ms(e,t){return(t=Dl({mode:"visible",children:t},e.mode,0,null)).return=e,e.child=t}function Bs(e,t,n,r){return null!==r&&ha(r),_a(t,e.child,null,n),(e=Ms(t,t.pendingProps.children)).flags|=2,t.memoizedState=null,e}function zs(e,t,n){e.lanes|=t;var r=e.alternate;null!==r&&(r.lanes|=t),Ca(e.return,t,n)}function $s(e,t,n,r,o){var a=e.memoizedState;null===a?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:o}:(a.isBackwards=t,a.rendering=null,a.renderingStartTime=0,a.last=r,a.tail=n,a.tailMode=o)}function Us(e,t,n){var r=t.pendingProps,o=r.revealOrder,a=r.tail;if(ws(e,t,r.children,n),2&(r=ei.current))r=1&r|2,t.flags|=128;else{if(null!==e&&128&e.flags)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&zs(e,n,t);else if(19===e.tag)zs(e,n,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(jo(ei,r),1&t.mode)switch(o){case"forwards":for(n=t.child,o=null;null!==n;)null!==(e=n.alternate)&&null===ti(e)&&(o=n),n=n.sibling;null===(n=o)?(o=t.child,t.child=null):(o=n.sibling,n.sibling=null),$s(t,!1,o,n,a);break;case"backwards":for(n=null,o=t.child,t.child=null;null!==o;){if(null!==(e=o.alternate)&&null===ti(e)){t.child=o;break}e=o.sibling,o.sibling=n,n=o,o=e}$s(t,!0,n,null,a);break;case"together":$s(t,!1,null,null,void 0);break;default:t.memoizedState=null}else t.memoizedState=null;return t.child}function Hs(e,t){!(1&t.mode)&&null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2)}function Vs(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),Dc|=t.lanes,!(n&t.childLanes))return null;if(null!==e&&t.child!==e.child)throw Error(a(153));if(null!==t.child){for(n=Nl(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Nl(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function Ws(e,t){if(!aa)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function Qs(e){var t=null!==e.alternate&&e.alternate.child===e.child,n=0,r=0;if(t)for(var o=e.child;null!==o;)n|=o.lanes|o.childLanes,r|=14680064&o.subtreeFlags,r|=14680064&o.flags,o.return=e,o=o.sibling;else for(o=e.child;null!==o;)n|=o.lanes|o.childLanes,r|=o.subtreeFlags,r|=o.flags,o.return=e,o=o.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function qs(e,t,n){var r=t.pendingProps;switch(na(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Qs(t),null;case 1:case 17:return No(t.type)&&Lo(),Qs(t),null;case 3:return r=t.stateNode,Za(),Oo(Ao),Oo(Co),ri(),r.pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(da(t)?t.flags|=4:null===e||e.memoizedState.isDehydrated&&!(256&t.flags)||(t.flags|=1024,null!==ia&&(il(ia),ia=null))),Is(e,t),Qs(t),null;case 5:Ja(t);var o=Ka(Ga.current);if(n=t.type,null!==e&&null!=t.stateNode)Ns(e,t,n,r,o),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!r){if(null===t.stateNode)throw Error(a(166));return Qs(t),null}if(e=Ka(Qa.current),da(t)){r=t.stateNode,n=t.type;var i=t.memoizedProps;switch(r[fo]=t,r[mo]=i,e=!!(1&t.mode),n){case"dialog":Br("cancel",r),Br("close",r);break;case"iframe":case"object":case"embed":Br("load",r);break;case"video":case"audio":for(o=0;o<Rr.length;o++)Br(Rr[o],r);break;case"source":Br("error",r);break;case"img":case"image":case"link":Br("error",r),Br("load",r);break;case"details":Br("toggle",r);break;case"input":Y(r,i),Br("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!i.multiple},Br("invalid",r);break;case"textarea":oe(r,i),Br("invalid",r)}for(var c in be(n,i),o=null,i)if(i.hasOwnProperty(c)){var l=i[c];"children"===c?"string"==typeof l?r.textContent!==l&&(!0!==i.suppressHydrationWarning&&Xr(r.textContent,l,e),o=["children",l]):"number"==typeof l&&r.textContent!==""+l&&(!0!==i.suppressHydrationWarning&&Xr(r.textContent,l,e),o=["children",""+l]):s.hasOwnProperty(c)&&null!=l&&"onScroll"===c&&Br("scroll",r)}switch(n){case"input":Q(r),J(r,i,!0);break;case"textarea":Q(r),ie(r);break;case"select":case"option":break;default:"function"==typeof i.onClick&&(r.onclick=Jr)}r=o,t.updateQueue=r,null!==r&&(t.flags|=4)}else{c=9===o.nodeType?o:o.ownerDocument,"http://www.w3.org/1999/xhtml"===e&&(e=se(n)),"http://www.w3.org/1999/xhtml"===e?"script"===n?((e=c.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=c.createElement(n,{is:r.is}):(e=c.createElement(n),"select"===n&&(c=e,r.multiple?c.multiple=!0:r.size&&(c.size=r.size))):e=c.createElementNS(e,n),e[fo]=t,e[mo]=r,Ts(e,t,!1,!1),t.stateNode=e;e:{switch(c=ye(n,r),n){case"dialog":Br("cancel",e),Br("close",e),o=r;break;case"iframe":case"object":case"embed":Br("load",e),o=r;break;case"video":case"audio":for(o=0;o<Rr.length;o++)Br(Rr[o],e);o=r;break;case"source":Br("error",e),o=r;break;case"img":case"image":case"link":Br("error",e),Br("load",e),o=r;break;case"details":Br("toggle",e),o=r;break;case"input":Y(e,r),o=K(e,r),Br("invalid",e);break;case"option":default:o=r;break;case"select":e._wrapperState={wasMultiple:!!r.multiple},o=F({},r,{value:void 0}),Br("invalid",e);break;case"textarea":oe(e,r),o=re(e,r),Br("invalid",e)}for(i in be(n,o),l=o)if(l.hasOwnProperty(i)){var u=l[i];"style"===i?ve(e,u):"dangerouslySetInnerHTML"===i?null!=(u=u?u.__html:void 0)&&pe(e,u):"children"===i?"string"==typeof u?("textarea"!==n||""!==u)&&de(e,u):"number"==typeof u&&de(e,""+u):"suppressContentEditableWarning"!==i&&"suppressHydrationWarning"!==i&&"autoFocus"!==i&&(s.hasOwnProperty(i)?null!=u&&"onScroll"===i&&Br("scroll",e):null!=u&&y(e,i,u,c))}switch(n){case"input":Q(e),J(e,r,!1);break;case"textarea":Q(e),ie(e);break;case"option":null!=r.value&&e.setAttribute("value",""+V(r.value));break;case"select":e.multiple=!!r.multiple,null!=(i=r.value)?ne(e,!!r.multiple,i,!1):null!=r.defaultValue&&ne(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof o.onClick&&(e.onclick=Jr)}switch(n){case"button":case"input":case"select":case"textarea":r=!!r.autoFocus;break e;case"img":r=!0;break e;default:r=!1}}r&&(t.flags|=4)}null!==t.ref&&(t.flags|=512,t.flags|=2097152)}return Qs(t),null;case 6:if(e&&null!=t.stateNode)Ls(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(a(166));if(n=Ka(Ga.current),Ka(Qa.current),da(t)){if(r=t.stateNode,n=t.memoizedProps,r[fo]=t,(i=r.nodeValue!==n)&&null!==(e=ra))switch(e.tag){case 3:Xr(r.nodeValue,n,!!(1&e.mode));break;case 5:!0!==e.memoizedProps.suppressHydrationWarning&&Xr(r.nodeValue,n,!!(1&e.mode))}i&&(t.flags|=4)}else(r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[fo]=t,t.stateNode=r}return Qs(t),null;case 13:if(Oo(ei),r=t.memoizedState,null===e||null!==e.memoizedState&&null!==e.memoizedState.dehydrated){if(aa&&null!==oa&&1&t.mode&&!(128&t.flags))fa(),ma(),t.flags|=98560,i=!1;else if(i=da(t),null!==r&&null!==r.dehydrated){if(null===e){if(!i)throw Error(a(318));if(!(i=null!==(i=t.memoizedState)?i.dehydrated:null))throw Error(a(317));i[fo]=t}else ma(),!(128&t.flags)&&(t.memoizedState=null),t.flags|=4;Qs(t),i=!1}else null!==ia&&(il(ia),ia=null),i=!0;if(!i)return 65536&t.flags?t:null}return 128&t.flags?(t.lanes=n,t):((r=null!==r)!==(null!==e&&null!==e.memoizedState)&&r&&(t.child.flags|=8192,1&t.mode&&(null===e||1&ei.current?0===Lc&&(Lc=3):hl())),null!==t.updateQueue&&(t.flags|=4),Qs(t),null);case 4:return Za(),Is(e,t),null===e&&Ur(t.stateNode.containerInfo),Qs(t),null;case 10:return Pa(t.type._context),Qs(t),null;case 19:if(Oo(ei),null===(i=t.memoizedState))return Qs(t),null;if(r=!!(128&t.flags),null===(c=i.rendering))if(r)Ws(i,!1);else{if(0!==Lc||null!==e&&128&e.flags)for(e=t.child;null!==e;){if(null!==(c=ti(e))){for(t.flags|=128,Ws(i,!1),null!==(r=c.updateQueue)&&(t.updateQueue=r,t.flags|=4),t.subtreeFlags=0,r=n,n=t.child;null!==n;)e=r,(i=n).flags&=14680066,null===(c=i.alternate)?(i.childLanes=0,i.lanes=e,i.child=null,i.subtreeFlags=0,i.memoizedProps=null,i.memoizedState=null,i.updateQueue=null,i.dependencies=null,i.stateNode=null):(i.childLanes=c.childLanes,i.lanes=c.lanes,i.child=c.child,i.subtreeFlags=0,i.deletions=null,i.memoizedProps=c.memoizedProps,i.memoizedState=c.memoizedState,i.updateQueue=c.updateQueue,i.type=c.type,e=c.dependencies,i.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return jo(ei,1&ei.current|2),t.child}e=e.sibling}null!==i.tail&&Ze()>Uc&&(t.flags|=128,r=!0,Ws(i,!1),t.lanes=4194304)}else{if(!r)if(null!==(e=ti(c))){if(t.flags|=128,r=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),Ws(i,!0),null===i.tail&&"hidden"===i.tailMode&&!c.alternate&&!aa)return Qs(t),null}else 2*Ze()-i.renderingStartTime>Uc&&1073741824!==n&&(t.flags|=128,r=!0,Ws(i,!1),t.lanes=4194304);i.isBackwards?(c.sibling=t.child,t.child=c):(null!==(n=i.last)?n.sibling=c:t.child=c,i.last=c)}return null!==i.tail?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=Ze(),t.sibling=null,n=ei.current,jo(ei,r?1&n|2:1&n),t):(Qs(t),null);case 22:case 23:return pl(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&(t.flags|=8192),r&&1&t.mode?!!(1073741824&Ic)&&(Qs(t),6&t.subtreeFlags&&(t.flags|=8192)):Qs(t),null;case 24:case 25:return null}throw Error(a(156,t.tag))}function Gs(e,t){switch(na(t),t.tag){case 1:return No(t.type)&&Lo(),65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 3:return Za(),Oo(Ao),Oo(Co),ri(),65536&(e=t.flags)&&!(128&e)?(t.flags=-65537&e|128,t):null;case 5:return Ja(t),null;case 13:if(Oo(ei),null!==(e=t.memoizedState)&&null!==e.dehydrated){if(null===t.alternate)throw Error(a(340));ma()}return 65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 19:return Oo(ei),null;case 4:return Za(),null;case 10:return Pa(t.type._context),null;case 22:case 23:return pl(),null;default:return null}}Ts=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Is=function(){},Ns=function(e,t,n,r){var o=e.memoizedProps;if(o!==r){e=t.stateNode,Ka(Qa.current);var a,i=null;switch(n){case"input":o=K(e,o),r=K(e,r),i=[];break;case"select":o=F({},o,{value:void 0}),r=F({},r,{value:void 0}),i=[];break;case"textarea":o=re(e,o),r=re(e,r),i=[];break;default:"function"!=typeof o.onClick&&"function"==typeof r.onClick&&(e.onclick=Jr)}for(u in be(n,r),n=null,o)if(!r.hasOwnProperty(u)&&o.hasOwnProperty(u)&&null!=o[u])if("style"===u){var c=o[u];for(a in c)c.hasOwnProperty(a)&&(n||(n={}),n[a]="")}else"dangerouslySetInnerHTML"!==u&&"children"!==u&&"suppressContentEditableWarning"!==u&&"suppressHydrationWarning"!==u&&"autoFocus"!==u&&(s.hasOwnProperty(u)?i||(i=[]):(i=i||[]).push(u,null));for(u in r){var l=r[u];if(c=null!=o?o[u]:void 0,r.hasOwnProperty(u)&&l!==c&&(null!=l||null!=c))if("style"===u)if(c){for(a in c)!c.hasOwnProperty(a)||l&&l.hasOwnProperty(a)||(n||(n={}),n[a]="");for(a in l)l.hasOwnProperty(a)&&c[a]!==l[a]&&(n||(n={}),n[a]=l[a])}else n||(i||(i=[]),i.push(u,n)),n=l;else"dangerouslySetInnerHTML"===u?(l=l?l.__html:void 0,c=c?c.__html:void 0,null!=l&&c!==l&&(i=i||[]).push(u,l)):"children"===u?"string"!=typeof l&&"number"!=typeof l||(i=i||[]).push(u,""+l):"suppressContentEditableWarning"!==u&&"suppressHydrationWarning"!==u&&(s.hasOwnProperty(u)?(null!=l&&"onScroll"===u&&Br("scroll",e),i||c===l||(i=[])):(i=i||[]).push(u,l))}n&&(i=i||[]).push("style",n);var u=i;(t.updateQueue=u)&&(t.flags|=4)}},Ls=function(e,t,n,r){n!==r&&(t.flags|=4)};var Ks=!1,Ys=!1,Zs="function"==typeof WeakSet?WeakSet:Set,Xs=null;function Js(e,t){var n=e.ref;if(null!==n)if("function"==typeof n)try{n(null)}catch(r){kl(e,t,r)}else n.current=null}function ec(e,t,n){try{n()}catch(r){kl(e,t,r)}}var tc=!1;function nc(e,t,n){var r=t.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var o=r=r.next;do{if((o.tag&e)===e){var a=o.destroy;o.destroy=void 0,void 0!==a&&ec(t,n,a)}o=o.next}while(o!==r)}}function rc(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function oc(e){var t=e.ref;if(null!==t){var n=e.stateNode;e.tag,e=n,"function"==typeof t?t(e):t.current=e}}function ac(e){var t=e.alternate;null!==t&&(e.alternate=null,ac(t)),e.child=null,e.deletions=null,e.sibling=null,5===e.tag&&(null!==(t=e.stateNode)&&(delete t[fo],delete t[mo],delete t[vo],delete t[go],delete t[bo])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function ic(e){return 5===e.tag||3===e.tag||4===e.tag}function sc(e){e:for(;;){for(;null===e.sibling;){if(null===e.return||ic(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;5!==e.tag&&6!==e.tag&&18!==e.tag;){if(2&e.flags)continue e;if(null===e.child||4===e.tag)continue e;e.child.return=e,e=e.child}if(!(2&e.flags))return e.stateNode}}function cc(e,t,n){var r=e.tag;if(5===r||6===r)e=e.stateNode,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=Jr));else if(4!==r&&null!==(e=e.child))for(cc(e,t,n),e=e.sibling;null!==e;)cc(e,t,n),e=e.sibling}function lc(e,t,n){var r=e.tag;if(5===r||6===r)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(lc(e,t,n),e=e.sibling;null!==e;)lc(e,t,n),e=e.sibling}var uc=null,pc=!1;function dc(e,t,n){for(n=n.child;null!==n;)fc(e,t,n),n=n.sibling}function fc(e,t,n){if(at&&"function"==typeof at.onCommitFiberUnmount)try{at.onCommitFiberUnmount(ot,n)}catch(s){}switch(n.tag){case 5:Ys||Js(n,t);case 6:var r=uc,o=pc;uc=null,dc(e,t,n),pc=o,null!==(uc=r)&&(pc?(e=uc,n=n.stateNode,8===e.nodeType?e.parentNode.removeChild(n):e.removeChild(n)):uc.removeChild(n.stateNode));break;case 18:null!==uc&&(pc?(e=uc,n=n.stateNode,8===e.nodeType?co(e.parentNode,n):1===e.nodeType&&co(e,n),Ut(e)):co(uc,n.stateNode));break;case 4:r=uc,o=pc,uc=n.stateNode.containerInfo,pc=!0,dc(e,t,n),uc=r,pc=o;break;case 0:case 11:case 14:case 15:if(!Ys&&(null!==(r=n.updateQueue)&&null!==(r=r.lastEffect))){o=r=r.next;do{var a=o,i=a.destroy;a=a.tag,void 0!==i&&(2&a||4&a)&&ec(n,t,i),o=o.next}while(o!==r)}dc(e,t,n);break;case 1:if(!Ys&&(Js(n,t),"function"==typeof(r=n.stateNode).componentWillUnmount))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(s){kl(n,t,s)}dc(e,t,n);break;case 21:dc(e,t,n);break;case 22:1&n.mode?(Ys=(r=Ys)||null!==n.memoizedState,dc(e,t,n),Ys=r):dc(e,t,n);break;default:dc(e,t,n)}}function mc(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new Zs),t.forEach((function(t){var r=Pl.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function hc(e,t){var n=t.deletions;if(null!==n)for(var r=0;r<n.length;r++){var o=n[r];try{var i=e,s=t,c=s;e:for(;null!==c;){switch(c.tag){case 5:uc=c.stateNode,pc=!1;break e;case 3:case 4:uc=c.stateNode.containerInfo,pc=!0;break e}c=c.return}if(null===uc)throw Error(a(160));fc(i,s,o),uc=null,pc=!1;var l=o.alternate;null!==l&&(l.return=null),o.return=null}catch(u){kl(o,t,u)}}if(12854&t.subtreeFlags)for(t=t.child;null!==t;)vc(t,e),t=t.sibling}function vc(e,t){var n=e.alternate,r=e.flags;switch(e.tag){case 0:case 11:case 14:case 15:if(hc(t,e),gc(e),4&r){try{nc(3,e,e.return),rc(3,e)}catch(v){kl(e,e.return,v)}try{nc(5,e,e.return)}catch(v){kl(e,e.return,v)}}break;case 1:hc(t,e),gc(e),512&r&&null!==n&&Js(n,n.return);break;case 5:if(hc(t,e),gc(e),512&r&&null!==n&&Js(n,n.return),32&e.flags){var o=e.stateNode;try{de(o,"")}catch(v){kl(e,e.return,v)}}if(4&r&&null!=(o=e.stateNode)){var i=e.memoizedProps,s=null!==n?n.memoizedProps:i,c=e.type,l=e.updateQueue;if(e.updateQueue=null,null!==l)try{"input"===c&&"radio"===i.type&&null!=i.name&&Z(o,i),ye(c,s);var u=ye(c,i);for(s=0;s<l.length;s+=2){var p=l[s],d=l[s+1];"style"===p?ve(o,d):"dangerouslySetInnerHTML"===p?pe(o,d):"children"===p?de(o,d):y(o,p,d,u)}switch(c){case"input":X(o,i);break;case"textarea":ae(o,i);break;case"select":var f=o._wrapperState.wasMultiple;o._wrapperState.wasMultiple=!!i.multiple;var m=i.value;null!=m?ne(o,!!i.multiple,m,!1):f!==!!i.multiple&&(null!=i.defaultValue?ne(o,!!i.multiple,i.defaultValue,!0):ne(o,!!i.multiple,i.multiple?[]:"",!1))}o[mo]=i}catch(v){kl(e,e.return,v)}}break;case 6:if(hc(t,e),gc(e),4&r){if(null===e.stateNode)throw Error(a(162));o=e.stateNode,i=e.memoizedProps;try{o.nodeValue=i}catch(v){kl(e,e.return,v)}}break;case 3:if(hc(t,e),gc(e),4&r&&null!==n&&n.memoizedState.isDehydrated)try{Ut(t.containerInfo)}catch(v){kl(e,e.return,v)}break;case 4:default:hc(t,e),gc(e);break;case 13:hc(t,e),gc(e),8192&(o=e.child).flags&&(i=null!==o.memoizedState,o.stateNode.isHidden=i,!i||null!==o.alternate&&null!==o.alternate.memoizedState||($c=Ze())),4&r&&mc(e);break;case 22:if(p=null!==n&&null!==n.memoizedState,1&e.mode?(Ys=(u=Ys)||p,hc(t,e),Ys=u):hc(t,e),gc(e),8192&r){if(u=null!==e.memoizedState,(e.stateNode.isHidden=u)&&!p&&1&e.mode)for(Xs=e,p=e.child;null!==p;){for(d=Xs=p;null!==Xs;){switch(m=(f=Xs).child,f.tag){case 0:case 11:case 14:case 15:nc(4,f,f.return);break;case 1:Js(f,f.return);var h=f.stateNode;if("function"==typeof h.componentWillUnmount){r=f,n=f.return;try{t=r,h.props=t.memoizedProps,h.state=t.memoizedState,h.componentWillUnmount()}catch(v){kl(r,n,v)}}break;case 5:Js(f,f.return);break;case 22:if(null!==f.memoizedState){_c(d);continue}}null!==m?(m.return=f,Xs=m):_c(d)}p=p.sibling}e:for(p=null,d=e;;){if(5===d.tag){if(null===p){p=d;try{o=d.stateNode,u?"function"==typeof(i=o.style).setProperty?i.setProperty("display","none","important"):i.display="none":(c=d.stateNode,s=null!=(l=d.memoizedProps.style)&&l.hasOwnProperty("display")?l.display:null,c.style.display=he("display",s))}catch(v){kl(e,e.return,v)}}}else if(6===d.tag){if(null===p)try{d.stateNode.nodeValue=u?"":d.memoizedProps}catch(v){kl(e,e.return,v)}}else if((22!==d.tag&&23!==d.tag||null===d.memoizedState||d===e)&&null!==d.child){d.child.return=d,d=d.child;continue}if(d===e)break e;for(;null===d.sibling;){if(null===d.return||d.return===e)break e;p===d&&(p=null),d=d.return}p===d&&(p=null),d.sibling.return=d.return,d=d.sibling}}break;case 19:hc(t,e),gc(e),4&r&&mc(e);case 21:}}function gc(e){var t=e.flags;if(2&t){try{e:{for(var n=e.return;null!==n;){if(ic(n)){var r=n;break e}n=n.return}throw Error(a(160))}switch(r.tag){case 5:var o=r.stateNode;32&r.flags&&(de(o,""),r.flags&=-33),lc(e,sc(e),o);break;case 3:case 4:var i=r.stateNode.containerInfo;cc(e,sc(e),i);break;default:throw Error(a(161))}}catch(s){kl(e,e.return,s)}e.flags&=-3}4096&t&&(e.flags&=-4097)}function bc(e,t,n){Xs=e,yc(e,t,n)}function yc(e,t,n){for(var r=!!(1&e.mode);null!==Xs;){var o=Xs,a=o.child;if(22===o.tag&&r){var i=null!==o.memoizedState||Ks;if(!i){var s=o.alternate,c=null!==s&&null!==s.memoizedState||Ys;s=Ks;var l=Ys;if(Ks=i,(Ys=c)&&!l)for(Xs=o;null!==Xs;)c=(i=Xs).child,22===i.tag&&null!==i.memoizedState?xc(o):null!==c?(c.return=i,Xs=c):xc(o);for(;null!==a;)Xs=a,yc(a,t,n),a=a.sibling;Xs=o,Ks=s,Ys=l}wc(e)}else 8772&o.subtreeFlags&&null!==a?(a.return=o,Xs=a):wc(e)}}function wc(e){for(;null!==Xs;){var t=Xs;if(8772&t.flags){var n=t.alternate;try{if(8772&t.flags)switch(t.tag){case 0:case 11:case 15:Ys||rc(5,t);break;case 1:var r=t.stateNode;if(4&t.flags&&!Ys)if(null===n)r.componentDidMount();else{var o=t.elementType===t.type?n.memoizedProps:ns(t.type,n.memoizedProps);r.componentDidUpdate(o,n.memoizedState,r.__reactInternalSnapshotBeforeUpdate)}var i=t.updateQueue;null!==i&&Va(t,i,r);break;case 3:var s=t.updateQueue;if(null!==s){if(n=null,null!==t.child)switch(t.child.tag){case 5:case 1:n=t.child.stateNode}Va(t,s,n)}break;case 5:var c=t.stateNode;if(null===n&&4&t.flags){n=c;var l=t.memoizedProps;switch(t.type){case"button":case"input":case"select":case"textarea":l.autoFocus&&n.focus();break;case"img":l.src&&(n.src=l.src)}}break;case 6:case 4:case 12:case 19:case 17:case 21:case 22:case 23:case 25:break;case 13:if(null===t.memoizedState){var u=t.alternate;if(null!==u){var p=u.memoizedState;if(null!==p){var d=p.dehydrated;null!==d&&Ut(d)}}}break;default:throw Error(a(163))}Ys||512&t.flags&&oc(t)}catch(f){kl(t,t.return,f)}}if(t===e){Xs=null;break}if(null!==(n=t.sibling)){n.return=t.return,Xs=n;break}Xs=t.return}}function _c(e){for(;null!==Xs;){var t=Xs;if(t===e){Xs=null;break}var n=t.sibling;if(null!==n){n.return=t.return,Xs=n;break}Xs=t.return}}function xc(e){for(;null!==Xs;){var t=Xs;try{switch(t.tag){case 0:case 11:case 15:var n=t.return;try{rc(4,t)}catch(c){kl(t,n,c)}break;case 1:var r=t.stateNode;if("function"==typeof r.componentDidMount){var o=t.return;try{r.componentDidMount()}catch(c){kl(t,o,c)}}var a=t.return;try{oc(t)}catch(c){kl(t,a,c)}break;case 5:var i=t.return;try{oc(t)}catch(c){kl(t,i,c)}}}catch(c){kl(t,t.return,c)}if(t===e){Xs=null;break}var s=t.sibling;if(null!==s){s.return=t.return,Xs=s;break}Xs=t.return}}var Sc,kc=Math.ceil,Ec=w.ReactCurrentDispatcher,Oc=w.ReactCurrentOwner,jc=w.ReactCurrentBatchConfig,Pc=0,Cc=null,Ac=null,Tc=0,Ic=0,Nc=Eo(0),Lc=0,Rc=null,Dc=0,Fc=0,Mc=0,Bc=null,zc=null,$c=0,Uc=1/0,Hc=null,Vc=!1,Wc=null,Qc=null,qc=!1,Gc=null,Kc=0,Yc=0,Zc=null,Xc=-1,Jc=0;function el(){return 6&Pc?Ze():-1!==Xc?Xc:Xc=Ze()}function tl(e){return 1&e.mode?2&Pc&&0!==Tc?Tc&-Tc:null!==va.transition?(0===Jc&&(Jc=ht()),Jc):0!==(e=yt)?e:e=void 0===(e=window.event)?16:Yt(e.type):1}function nl(e,t,n,r){if(50<Yc)throw Yc=0,Zc=null,Error(a(185));gt(e,n,r),2&Pc&&e===Cc||(e===Cc&&(!(2&Pc)&&(Fc|=n),4===Lc&&sl(e,Tc)),rl(e,r),1===n&&0===Pc&&!(1&t.mode)&&(Uc=Ze()+500,zo&&Ho()))}function rl(e,t){var n=e.callbackNode;!function(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,o=e.expirationTimes,a=e.pendingLanes;0<a;){var i=31-it(a),s=1<<i,c=o[i];-1===c?s&n&&!(s&r)||(o[i]=ft(s,t)):c<=t&&(e.expiredLanes|=s),a&=~s}}(e,t);var r=dt(e,e===Cc?Tc:0);if(0===r)null!==n&&Ge(n),e.callbackNode=null,e.callbackPriority=0;else if(t=r&-r,e.callbackPriority!==t){if(null!=n&&Ge(n),1===t)0===e.tag?function(e){zo=!0,Uo(e)}(cl.bind(null,e)):Uo(cl.bind(null,e)),io((function(){!(6&Pc)&&Ho()})),n=null;else{switch(wt(r)){case 1:n=Je;break;case 4:n=et;break;case 16:default:n=tt;break;case 536870912:n=rt}n=Cl(n,ol.bind(null,e))}e.callbackPriority=t,e.callbackNode=n}}function ol(e,t){if(Xc=-1,Jc=0,6&Pc)throw Error(a(327));var n=e.callbackNode;if(xl()&&e.callbackNode!==n)return null;var r=dt(e,e===Cc?Tc:0);if(0===r)return null;if(30&r||r&e.expiredLanes||t)t=vl(e,r);else{t=r;var o=Pc;Pc|=2;var i=ml();for(Cc===e&&Tc===t||(Hc=null,Uc=Ze()+500,dl(e,t));;)try{bl();break}catch(c){fl(e,c)}ja(),Ec.current=i,Pc=o,null!==Ac?t=0:(Cc=null,Tc=0,t=Lc)}if(0!==t){if(2===t&&(0!==(o=mt(e))&&(r=o,t=al(e,o))),1===t)throw n=Rc,dl(e,0),sl(e,r),rl(e,Ze()),n;if(6===t)sl(e,r);else{if(o=e.current.alternate,!(30&r||function(e){for(var t=e;;){if(16384&t.flags){var n=t.updateQueue;if(null!==n&&null!==(n=n.stores))for(var r=0;r<n.length;r++){var o=n[r],a=o.getSnapshot;o=o.value;try{if(!sr(a(),o))return!1}catch(s){return!1}}}if(n=t.child,16384&t.subtreeFlags&&null!==n)n.return=t,t=n;else{if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return!0;t=t.return}t.sibling.return=t.return,t=t.sibling}}return!0}(o)||(t=vl(e,r),2===t&&(i=mt(e),0!==i&&(r=i,t=al(e,i))),1!==t)))throw n=Rc,dl(e,0),sl(e,r),rl(e,Ze()),n;switch(e.finishedWork=o,e.finishedLanes=r,t){case 0:case 1:throw Error(a(345));case 2:case 5:_l(e,zc,Hc);break;case 3:if(sl(e,r),(130023424&r)===r&&10<(t=$c+500-Ze())){if(0!==dt(e,0))break;if(((o=e.suspendedLanes)&r)!==r){el(),e.pingedLanes|=e.suspendedLanes&o;break}e.timeoutHandle=ro(_l.bind(null,e,zc,Hc),t);break}_l(e,zc,Hc);break;case 4:if(sl(e,r),(4194240&r)===r)break;for(t=e.eventTimes,o=-1;0<r;){var s=31-it(r);i=1<<s,(s=t[s])>o&&(o=s),r&=~i}if(r=o,10<(r=(120>(r=Ze()-r)?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*kc(r/1960))-r)){e.timeoutHandle=ro(_l.bind(null,e,zc,Hc),r);break}_l(e,zc,Hc);break;default:throw Error(a(329))}}}return rl(e,Ze()),e.callbackNode===n?ol.bind(null,e):null}function al(e,t){var n=Bc;return e.current.memoizedState.isDehydrated&&(dl(e,t).flags|=256),2!==(e=vl(e,t))&&(t=zc,zc=n,null!==t&&il(t)),e}function il(e){null===zc?zc=e:zc.push.apply(zc,e)}function sl(e,t){for(t&=~Mc,t&=~Fc,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-it(t),r=1<<n;e[n]=-1,t&=~r}}function cl(e){if(6&Pc)throw Error(a(327));xl();var t=dt(e,0);if(!(1&t))return rl(e,Ze()),null;var n=vl(e,t);if(0!==e.tag&&2===n){var r=mt(e);0!==r&&(t=r,n=al(e,r))}if(1===n)throw n=Rc,dl(e,0),sl(e,t),rl(e,Ze()),n;if(6===n)throw Error(a(345));return e.finishedWork=e.current.alternate,e.finishedLanes=t,_l(e,zc,Hc),rl(e,Ze()),null}function ll(e,t){var n=Pc;Pc|=1;try{return e(t)}finally{0===(Pc=n)&&(Uc=Ze()+500,zo&&Ho())}}function ul(e){null!==Gc&&0===Gc.tag&&!(6&Pc)&&xl();var t=Pc;Pc|=1;var n=jc.transition,r=yt;try{if(jc.transition=null,yt=1,e)return e()}finally{yt=r,jc.transition=n,!(6&(Pc=t))&&Ho()}}function pl(){Ic=Nc.current,Oo(Nc)}function dl(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,oo(n)),null!==Ac)for(n=Ac.return;null!==n;){var r=n;switch(na(r),r.tag){case 1:null!=(r=r.type.childContextTypes)&&Lo();break;case 3:Za(),Oo(Ao),Oo(Co),ri();break;case 5:Ja(r);break;case 4:Za();break;case 13:case 19:Oo(ei);break;case 10:Pa(r.type._context);break;case 22:case 23:pl()}n=n.return}if(Cc=e,Ac=e=Nl(e.current,null),Tc=Ic=t,Lc=0,Rc=null,Mc=Fc=Dc=0,zc=Bc=null,null!==Ia){for(t=0;t<Ia.length;t++)if(null!==(r=(n=Ia[t]).interleaved)){n.interleaved=null;var o=r.next,a=n.pending;if(null!==a){var i=a.next;a.next=o,r.next=i}n.pending=r}Ia=null}return e}function fl(e,t){for(;;){var n=Ac;try{if(ja(),oi.current=Xi,ui){for(var r=si.memoizedState;null!==r;){var o=r.queue;null!==o&&(o.pending=null),r=r.next}ui=!1}if(ii=0,li=ci=si=null,pi=!1,di=0,Oc.current=null,null===n||null===n.return){Lc=1,Rc=t,Ac=null;break}e:{var i=e,s=n.return,c=n,l=t;if(t=Tc,c.flags|=32768,null!==l&&"object"==typeof l&&"function"==typeof l.then){var u=l,p=c,d=p.tag;if(!(1&p.mode||0!==d&&11!==d&&15!==d)){var f=p.alternate;f?(p.updateQueue=f.updateQueue,p.memoizedState=f.memoizedState,p.lanes=f.lanes):(p.updateQueue=null,p.memoizedState=null)}var m=vs(s);if(null!==m){m.flags&=-257,gs(m,s,c,0,t),1&m.mode&&hs(i,u,t),l=u;var h=(t=m).updateQueue;if(null===h){var v=new Set;v.add(l),t.updateQueue=v}else h.add(l);break e}if(!(1&t)){hs(i,u,t),hl();break e}l=Error(a(426))}else if(aa&&1&c.mode){var g=vs(s);if(null!==g){!(65536&g.flags)&&(g.flags|=256),gs(g,s,c,0,t),ha(ls(l,c));break e}}i=l=ls(l,c),4!==Lc&&(Lc=2),null===Bc?Bc=[i]:Bc.push(i),i=s;do{switch(i.tag){case 3:i.flags|=65536,t&=-t,i.lanes|=t,Ua(i,fs(0,l,t));break e;case 1:c=l;var b=i.type,y=i.stateNode;if(!(128&i.flags||"function"!=typeof b.getDerivedStateFromError&&(null===y||"function"!=typeof y.componentDidCatch||null!==Qc&&Qc.has(y)))){i.flags|=65536,t&=-t,i.lanes|=t,Ua(i,ms(i,c,t));break e}}i=i.return}while(null!==i)}wl(n)}catch(w){t=w,Ac===n&&null!==n&&(Ac=n=n.return);continue}break}}function ml(){var e=Ec.current;return Ec.current=Xi,null===e?Xi:e}function hl(){0!==Lc&&3!==Lc&&2!==Lc||(Lc=4),null===Cc||!(268435455&Dc)&&!(268435455&Fc)||sl(Cc,Tc)}function vl(e,t){var n=Pc;Pc|=2;var r=ml();for(Cc===e&&Tc===t||(Hc=null,dl(e,t));;)try{gl();break}catch(o){fl(e,o)}if(ja(),Pc=n,Ec.current=r,null!==Ac)throw Error(a(261));return Cc=null,Tc=0,Lc}function gl(){for(;null!==Ac;)yl(Ac)}function bl(){for(;null!==Ac&&!Ke();)yl(Ac)}function yl(e){var t=Sc(e.alternate,e,Ic);e.memoizedProps=e.pendingProps,null===t?wl(e):Ac=t,Oc.current=null}function wl(e){var t=e;do{var n=t.alternate;if(e=t.return,32768&t.flags){if(null!==(n=Gs(n,t)))return n.flags&=32767,void(Ac=n);if(null===e)return Lc=6,void(Ac=null);e.flags|=32768,e.subtreeFlags=0,e.deletions=null}else if(null!==(n=qs(n,t,Ic)))return void(Ac=n);if(null!==(t=t.sibling))return void(Ac=t);Ac=t=e}while(null!==t);0===Lc&&(Lc=5)}function _l(e,t,n){var r=yt,o=jc.transition;try{jc.transition=null,yt=1,function(e,t,n,r){do{xl()}while(null!==Gc);if(6&Pc)throw Error(a(327));n=e.finishedWork;var o=e.finishedLanes;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(a(177));e.callbackNode=null,e.callbackPriority=0;var i=n.lanes|n.childLanes;if(function(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0<n;){var o=31-it(n),a=1<<o;t[o]=0,r[o]=-1,e[o]=-1,n&=~a}}(e,i),e===Cc&&(Ac=Cc=null,Tc=0),!(2064&n.subtreeFlags)&&!(2064&n.flags)||qc||(qc=!0,Cl(tt,(function(){return xl(),null}))),i=!!(15990&n.flags),!!(15990&n.subtreeFlags)||i){i=jc.transition,jc.transition=null;var s=yt;yt=1;var c=Pc;Pc|=4,Oc.current=null,function(e,t){if(eo=Vt,fr(e=dr())){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{var r=(n=(n=e.ownerDocument)&&n.defaultView||window).getSelection&&n.getSelection();if(r&&0!==r.rangeCount){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch(_){n=null;break e}var s=0,c=-1,l=-1,u=0,p=0,d=e,f=null;t:for(;;){for(var m;d!==n||0!==o&&3!==d.nodeType||(c=s+o),d!==i||0!==r&&3!==d.nodeType||(l=s+r),3===d.nodeType&&(s+=d.nodeValue.length),null!==(m=d.firstChild);)f=d,d=m;for(;;){if(d===e)break t;if(f===n&&++u===o&&(c=s),f===i&&++p===r&&(l=s),null!==(m=d.nextSibling))break;f=(d=f).parentNode}d=m}n=-1===c||-1===l?null:{start:c,end:l}}else n=null}n=n||{start:0,end:0}}else n=null;for(to={focusedElem:e,selectionRange:n},Vt=!1,Xs=t;null!==Xs;)if(e=(t=Xs).child,1028&t.subtreeFlags&&null!==e)e.return=t,Xs=e;else for(;null!==Xs;){t=Xs;try{var h=t.alternate;if(1024&t.flags)switch(t.tag){case 0:case 11:case 15:case 5:case 6:case 4:case 17:break;case 1:if(null!==h){var v=h.memoizedProps,g=h.memoizedState,b=t.stateNode,y=b.getSnapshotBeforeUpdate(t.elementType===t.type?v:ns(t.type,v),g);b.__reactInternalSnapshotBeforeUpdate=y}break;case 3:var w=t.stateNode.containerInfo;1===w.nodeType?w.textContent="":9===w.nodeType&&w.documentElement&&w.removeChild(w.documentElement);break;default:throw Error(a(163))}}catch(_){kl(t,t.return,_)}if(null!==(e=t.sibling)){e.return=t.return,Xs=e;break}Xs=t.return}h=tc,tc=!1}(e,n),vc(n,e),mr(to),Vt=!!eo,to=eo=null,e.current=n,bc(n,e,o),Ye(),Pc=c,yt=s,jc.transition=i}else e.current=n;if(qc&&(qc=!1,Gc=e,Kc=o),i=e.pendingLanes,0===i&&(Qc=null),function(e){if(at&&"function"==typeof at.onCommitFiberRoot)try{at.onCommitFiberRoot(ot,e,void 0,!(128&~e.current.flags))}catch(t){}}(n.stateNode),rl(e,Ze()),null!==t)for(r=e.onRecoverableError,n=0;n<t.length;n++)o=t[n],r(o.value,{componentStack:o.stack,digest:o.digest});if(Vc)throw Vc=!1,e=Wc,Wc=null,e;!!(1&Kc)&&0!==e.tag&&xl(),i=e.pendingLanes,1&i?e===Zc?Yc++:(Yc=0,Zc=e):Yc=0,Ho()}(e,t,n,r)}finally{jc.transition=o,yt=r}return null}function xl(){if(null!==Gc){var e=wt(Kc),t=jc.transition,n=yt;try{if(jc.transition=null,yt=16>e?16:e,null===Gc)var r=!1;else{if(e=Gc,Gc=null,Kc=0,6&Pc)throw Error(a(331));var o=Pc;for(Pc|=4,Xs=e.current;null!==Xs;){var i=Xs,s=i.child;if(16&Xs.flags){var c=i.deletions;if(null!==c){for(var l=0;l<c.length;l++){var u=c[l];for(Xs=u;null!==Xs;){var p=Xs;switch(p.tag){case 0:case 11:case 15:nc(8,p,i)}var d=p.child;if(null!==d)d.return=p,Xs=d;else for(;null!==Xs;){var f=(p=Xs).sibling,m=p.return;if(ac(p),p===u){Xs=null;break}if(null!==f){f.return=m,Xs=f;break}Xs=m}}}var h=i.alternate;if(null!==h){var v=h.child;if(null!==v){h.child=null;do{var g=v.sibling;v.sibling=null,v=g}while(null!==v)}}Xs=i}}if(2064&i.subtreeFlags&&null!==s)s.return=i,Xs=s;else e:for(;null!==Xs;){if(2048&(i=Xs).flags)switch(i.tag){case 0:case 11:case 15:nc(9,i,i.return)}var b=i.sibling;if(null!==b){b.return=i.return,Xs=b;break e}Xs=i.return}}var y=e.current;for(Xs=y;null!==Xs;){var w=(s=Xs).child;if(2064&s.subtreeFlags&&null!==w)w.return=s,Xs=w;else e:for(s=y;null!==Xs;){if(2048&(c=Xs).flags)try{switch(c.tag){case 0:case 11:case 15:rc(9,c)}}catch(x){kl(c,c.return,x)}if(c===s){Xs=null;break e}var _=c.sibling;if(null!==_){_.return=c.return,Xs=_;break e}Xs=c.return}}if(Pc=o,Ho(),at&&"function"==typeof at.onPostCommitFiberRoot)try{at.onPostCommitFiberRoot(ot,e)}catch(x){}r=!0}return r}finally{yt=n,jc.transition=t}}return!1}function Sl(e,t,n){e=za(e,t=fs(0,t=ls(n,t),1),1),t=el(),null!==e&&(gt(e,1,t),rl(e,t))}function kl(e,t,n){if(3===e.tag)Sl(e,e,n);else for(;null!==t;){if(3===t.tag){Sl(t,e,n);break}if(1===t.tag){var r=t.stateNode;if("function"==typeof t.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Qc||!Qc.has(r))){t=za(t,e=ms(t,e=ls(n,e),1),1),e=el(),null!==t&&(gt(t,1,e),rl(t,e));break}}t=t.return}}function El(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=el(),e.pingedLanes|=e.suspendedLanes&n,Cc===e&&(Tc&n)===n&&(4===Lc||3===Lc&&(130023424&Tc)===Tc&&500>Ze()-$c?dl(e,0):Mc|=n),rl(e,t)}function Ol(e,t){0===t&&(1&e.mode?(t=ut,!(130023424&(ut<<=1))&&(ut=4194304)):t=1);var n=el();null!==(e=Ra(e,t))&&(gt(e,t,n),rl(e,n))}function jl(e){var t=e.memoizedState,n=0;null!==t&&(n=t.retryLane),Ol(e,n)}function Pl(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;null!==o&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(a(314))}null!==r&&r.delete(t),Ol(e,n)}function Cl(e,t){return qe(e,t)}function Al(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Tl(e,t,n,r){return new Al(e,t,n,r)}function Il(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Nl(e,t){var n=e.alternate;return null===n?((n=Tl(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=14680064&e.flags,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ll(e,t,n,r,o,i){var s=2;if(r=e,"function"==typeof e)Il(e)&&(s=1);else if("string"==typeof e)s=5;else e:switch(e){case S:return Rl(n.children,o,i,t);case k:s=8,o|=8;break;case E:return(e=Tl(12,n,t,2|o)).elementType=E,e.lanes=i,e;case C:return(e=Tl(13,n,t,o)).elementType=C,e.lanes=i,e;case A:return(e=Tl(19,n,t,o)).elementType=A,e.lanes=i,e;case N:return Dl(n,o,i,t);default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case O:s=10;break e;case j:s=9;break e;case P:s=11;break e;case T:s=14;break e;case I:s=16,r=null;break e}throw Error(a(130,null==e?e:typeof e,""))}return(t=Tl(s,n,t,o)).elementType=e,t.type=r,t.lanes=i,t}function Rl(e,t,n,r){return(e=Tl(7,e,r,t)).lanes=n,e}function Dl(e,t,n,r){return(e=Tl(22,e,r,t)).elementType=N,e.lanes=n,e.stateNode={isHidden:!1},e}function Fl(e,t,n){return(e=Tl(6,e,null,t)).lanes=n,e}function Ml(e,t,n){return(t=Tl(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Bl(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=vt(0),this.expirationTimes=vt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=vt(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function zl(e,t,n,r,o,a,i,s,c){return e=new Bl(e,t,n,s,c),1===t?(t=1,!0===a&&(t|=8)):t=0,a=Tl(3,null,null,t),e.current=a,a.stateNode=e,a.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Fa(a),e}function $l(e){if(!e)return Po;e:{if(Ue(e=e._reactInternals)!==e||1!==e.tag)throw Error(a(170));var t=e;do{switch(t.tag){case 3:t=t.stateNode.context;break e;case 1:if(No(t.type)){t=t.stateNode.__reactInternalMemoizedMergedChildContext;break e}}t=t.return}while(null!==t);throw Error(a(171))}if(1===e.tag){var n=e.type;if(No(n))return Do(e,n,t)}return t}function Ul(e,t,n,r,o,a,i,s,c){return(e=zl(n,r,!0,e,0,a,0,s,c)).context=$l(null),n=e.current,(a=Ba(r=el(),o=tl(n))).callback=null!=t?t:null,za(n,a,o),e.current.lanes=o,gt(e,o,r),rl(e,r),e}function Hl(e,t,n,r){var o=t.current,a=el(),i=tl(o);return n=$l(n),null===t.context?t.context=n:t.pendingContext=n,(t=Ba(a,i)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),null!==(e=za(o,t,i))&&(nl(e,o,i,a),$a(e,o,i)),i}function Vl(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function Wl(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function Ql(e,t){Wl(e,t),(e=e.alternate)&&Wl(e,t)}Sc=function(e,t,n){if(null!==e)if(e.memoizedProps!==t.pendingProps||Ao.current)ys=!0;else{if(!(e.lanes&n||128&t.flags))return ys=!1,function(e,t,n){switch(t.tag){case 3:Cs(t),ma();break;case 5:Xa(t);break;case 1:No(t.type)&&Fo(t);break;case 4:Ya(t,t.stateNode.containerInfo);break;case 10:var r=t.type._context,o=t.memoizedProps.value;jo(Sa,r._currentValue),r._currentValue=o;break;case 13:if(null!==(r=t.memoizedState))return null!==r.dehydrated?(jo(ei,1&ei.current),t.flags|=128,null):n&t.child.childLanes?Fs(e,t,n):(jo(ei,1&ei.current),null!==(e=Vs(e,t,n))?e.sibling:null);jo(ei,1&ei.current);break;case 19:if(r=!!(n&t.childLanes),128&e.flags){if(r)return Us(e,t,n);t.flags|=128}if(null!==(o=t.memoizedState)&&(o.rendering=null,o.tail=null,o.lastEffect=null),jo(ei,ei.current),r)break;return null;case 22:case 23:return t.lanes=0,ks(e,t,n)}return Vs(e,t,n)}(e,t,n);ys=!!(131072&e.flags)}else ys=!1,aa&&1048576&t.flags&&ea(t,qo,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Hs(e,t),e=t.pendingProps;var o=Io(t,Co.current);Aa(t,n),o=vi(null,t,r,e,o,n);var i=gi();return t.flags|=1,"object"==typeof o&&null!==o&&"function"==typeof o.render&&void 0===o.$$typeof?(t.tag=1,t.memoizedState=null,t.updateQueue=null,No(r)?(i=!0,Fo(t)):i=!1,t.memoizedState=null!==o.state&&void 0!==o.state?o.state:null,Fa(t),o.updater=os,t.stateNode=o,o._reactInternals=t,cs(t,r,e,n),t=Ps(null,t,r,!0,i,n)):(t.tag=0,aa&&i&&ta(t),ws(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Hs(e,t),e=t.pendingProps,r=(o=r._init)(r._payload),t.type=r,o=t.tag=function(e){if("function"==typeof e)return Il(e)?1:0;if(null!=e){if((e=e.$$typeof)===P)return 11;if(e===T)return 14}return 2}(r),e=ns(r,e),o){case 0:t=Os(null,t,r,e,n);break e;case 1:t=js(null,t,r,e,n);break e;case 11:t=_s(null,t,r,e,n);break e;case 14:t=xs(null,t,r,ns(r.type,e),n);break e}throw Error(a(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,Os(e,t,r,o=t.elementType===r?o:ns(r,o),n);case 1:return r=t.type,o=t.pendingProps,js(e,t,r,o=t.elementType===r?o:ns(r,o),n);case 3:e:{if(Cs(t),null===e)throw Error(a(387));r=t.pendingProps,o=(i=t.memoizedState).element,Ma(e,t),Ha(t,r,null,n);var s=t.memoizedState;if(r=s.element,i.isDehydrated){if(i={element:r,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=i,t.memoizedState=i,256&t.flags){t=As(e,t,r,n,o=ls(Error(a(423)),t));break e}if(r!==o){t=As(e,t,r,n,o=ls(Error(a(424)),t));break e}for(oa=lo(t.stateNode.containerInfo.firstChild),ra=t,aa=!0,ia=null,n=xa(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|4096,n=n.sibling}else{if(ma(),r===o){t=Vs(e,t,n);break e}ws(e,t,r,n)}t=t.child}return t;case 5:return Xa(t),null===e&&ua(t),r=t.type,o=t.pendingProps,i=null!==e?e.memoizedProps:null,s=o.children,no(r,o)?s=null:null!==i&&no(r,i)&&(t.flags|=32),Es(e,t),ws(e,t,s,n),t.child;case 6:return null===e&&ua(t),null;case 13:return Fs(e,t,n);case 4:return Ya(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=_a(t,null,r,n):ws(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,_s(e,t,r,o=t.elementType===r?o:ns(r,o),n);case 7:return ws(e,t,t.pendingProps,n),t.child;case 8:case 12:return ws(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,s=o.value,jo(Sa,r._currentValue),r._currentValue=s,null!==i)if(sr(i.value,s)){if(i.children===o.children&&!Ao.current){t=Vs(e,t,n);break e}}else for(null!==(i=t.child)&&(i.return=t);null!==i;){var c=i.dependencies;if(null!==c){s=i.child;for(var l=c.firstContext;null!==l;){if(l.context===r){if(1===i.tag){(l=Ba(-1,n&-n)).tag=2;var u=i.updateQueue;if(null!==u){var p=(u=u.shared).pending;null===p?l.next=l:(l.next=p.next,p.next=l),u.pending=l}}i.lanes|=n,null!==(l=i.alternate)&&(l.lanes|=n),Ca(i.return,n,t),c.lanes|=n;break}l=l.next}}else if(10===i.tag)s=i.type===t.type?null:i.child;else if(18===i.tag){if(null===(s=i.return))throw Error(a(341));s.lanes|=n,null!==(c=s.alternate)&&(c.lanes|=n),Ca(s,n,t),s=i.sibling}else s=i.child;if(null!==s)s.return=i;else for(s=i;null!==s;){if(s===t){s=null;break}if(null!==(i=s.sibling)){i.return=s.return,s=i;break}s=s.return}i=s}ws(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,Aa(t,n),r=r(o=Ta(o)),t.flags|=1,ws(e,t,r,n),t.child;case 14:return o=ns(r=t.type,t.pendingProps),xs(e,t,r,o=ns(r.type,o),n);case 15:return Ss(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:ns(r,o),Hs(e,t),t.tag=1,No(r)?(e=!0,Fo(t)):e=!1,Aa(t,n),is(t,r,o),cs(t,r,o,n),Ps(null,t,r,!0,e,n);case 19:return Us(e,t,n);case 22:return ks(e,t,n)}throw Error(a(156,t.tag))};var ql="function"==typeof reportError?reportError:function(e){console.error(e)};function Gl(e){this._internalRoot=e}function Kl(e){this._internalRoot=e}function Yl(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType)}function Zl(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function Xl(){}function Jl(e,t,n,r,o){var a=n._reactRootContainer;if(a){var i=a;if("function"==typeof o){var s=o;o=function(){var e=Vl(i);s.call(e)}}Hl(t,i,e,o)}else i=function(e,t,n,r,o){if(o){if("function"==typeof r){var a=r;r=function(){var e=Vl(i);a.call(e)}}var i=Ul(t,r,e,0,null,!1,0,"",Xl);return e._reactRootContainer=i,e[ho]=i.current,Ur(8===e.nodeType?e.parentNode:e),ul(),i}for(;o=e.lastChild;)e.removeChild(o);if("function"==typeof r){var s=r;r=function(){var e=Vl(c);s.call(e)}}var c=zl(e,0,!1,null,0,!1,0,"",Xl);return e._reactRootContainer=c,e[ho]=c.current,Ur(8===e.nodeType?e.parentNode:e),ul((function(){Hl(t,c,n,r)})),c}(n,t,e,o,r);return Vl(i)}Kl.prototype.render=Gl.prototype.render=function(e){var t=this._internalRoot;if(null===t)throw Error(a(409));Hl(e,t,null,null)},Kl.prototype.unmount=Gl.prototype.unmount=function(){var e=this._internalRoot;if(null!==e){this._internalRoot=null;var t=e.containerInfo;ul((function(){Hl(null,e,null,null)})),t[ho]=null}},Kl.prototype.unstable_scheduleHydration=function(e){if(e){var t=kt();e={blockedOn:null,target:e,priority:t};for(var n=0;n<Nt.length&&0!==t&&t<Nt[n].priority;n++);Nt.splice(n,0,e),0===n&&Ft(e)}},_t=function(e){switch(e.tag){case 3:var t=e.stateNode;if(t.current.memoizedState.isDehydrated){var n=pt(t.pendingLanes);0!==n&&(bt(t,1|n),rl(t,Ze()),!(6&Pc)&&(Uc=Ze()+500,Ho()))}break;case 13:ul((function(){var t=Ra(e,1);if(null!==t){var n=el();nl(t,e,1,n)}})),Ql(e,1)}},xt=function(e){if(13===e.tag){var t=Ra(e,134217728);if(null!==t)nl(t,e,134217728,el());Ql(e,134217728)}},St=function(e){if(13===e.tag){var t=tl(e),n=Ra(e,t);if(null!==n)nl(n,e,t,el());Ql(e,t)}},kt=function(){return yt},Et=function(e,t){var n=yt;try{return yt=e,t()}finally{yt=n}},xe=function(e,t,n){switch(t){case"input":if(X(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var o=xo(r);if(!o)throw Error(a(90));q(r),X(r,o)}}}break;case"textarea":ae(e,n);break;case"select":null!=(t=n.value)&&ne(e,!!n.multiple,t,!1)}},Pe=ll,Ce=ul;var eu={usingClientEntryPoint:!1,Events:[wo,_o,xo,Oe,je,ll]},tu={findFiberByHostInstance:yo,bundleType:0,version:"18.3.1",rendererPackageName:"react-dom"},nu={bundleType:tu.bundleType,version:tu.version,rendererPackageName:tu.rendererPackageName,rendererConfig:tu.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setErrorHandler:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:w.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=We(e))?null:e.stateNode},findFiberByHostInstance:tu.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null,reconcilerVersion:"18.3.1-next-f1338f8080-20240426"};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var ru=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!ru.isDisabled&&ru.supportsFiber)try{ot=ru.inject(nu),at=ru}catch(ue){}}t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=eu,t.createPortal=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Yl(t))throw Error(a(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:x,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)},t.createRoot=function(e,t){if(!Yl(e))throw Error(a(299));var n=!1,r="",o=ql;return null!=t&&(!0===t.unstable_strictMode&&(n=!0),void 0!==t.identifierPrefix&&(r=t.identifierPrefix),void 0!==t.onRecoverableError&&(o=t.onRecoverableError)),t=zl(e,1,!1,null,0,n,0,r,o),e[ho]=t.current,Ur(8===e.nodeType?e.parentNode:e),new Gl(t)},t.findDOMNode=function(e){if(null==e)return null;if(1===e.nodeType)return e;var t=e._reactInternals;if(void 0===t){if("function"==typeof e.render)throw Error(a(188));throw e=Object.keys(e).join(","),Error(a(268,e))}return e=null===(e=We(t))?null:e.stateNode},t.flushSync=function(e){return ul(e)},t.hydrate=function(e,t,n){if(!Zl(t))throw Error(a(200));return Jl(null,e,t,!0,n)},t.hydrateRoot=function(e,t,n){if(!Yl(e))throw Error(a(405));var r=null!=n&&n.hydratedSources||null,o=!1,i="",s=ql;if(null!=n&&(!0===n.unstable_strictMode&&(o=!0),void 0!==n.identifierPrefix&&(i=n.identifierPrefix),void 0!==n.onRecoverableError&&(s=n.onRecoverableError)),t=Ul(t,null,e,1,null!=n?n:null,o,0,i,s),e[ho]=t.current,Ur(e),r)for(e=0;e<r.length;e++)o=(o=(n=r[e])._getVersion)(n._source),null==t.mutableSourceEagerHydrationData?t.mutableSourceEagerHydrationData=[n,o]:t.mutableSourceEagerHydrationData.push(n,o);return new Kl(t)},t.render=function(e,t,n){if(!Zl(t))throw Error(a(200));return Jl(null,e,t,!1,n)},t.unmountComponentAtNode=function(e){if(!Zl(e))throw Error(a(40));return!!e._reactRootContainer&&(ul((function(){Jl(null,null,e,!1,(function(){e._reactRootContainer=null,e[ho]=null}))})),!0)},t.unstable_batchedUpdates=ll,t.unstable_renderSubtreeIntoContainer=function(e,t,n,r){if(!Zl(n))throw Error(a(200));if(null==e||void 0===e._reactInternals)throw Error(a(38));return Jl(e,t,n,!1,r)},t.version="18.3.1-next-f1338f8080-20240426"},5338:(e,t,n)=>{"use strict";var r=n(40961);t.createRoot=r.createRoot,t.hydrateRoot=r.hydrateRoot},40961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(22551)},30115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,o="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function a(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var s,c,l,u;if(Array.isArray(e)){if((s=e.length)!=i.length)return!1;for(c=s;0!=c--;)if(!a(e[c],i[c]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(u=e.entries();!(c=u.next()).done;)if(!i.has(c.value[0]))return!1;for(u=e.entries();!(c=u.next()).done;)if(!a(c.value[1],i.get(c.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(u=e.entries();!(c=u.next()).done;)if(!i.has(c.value[0]))return!1;return!0}if(o&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((s=e.length)!=i.length)return!1;for(c=s;0!=c--;)if(e[c]!==i[c])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((s=(l=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(c=s;0!=c--;)if(!Object.prototype.hasOwnProperty.call(i,l[c]))return!1;if(t&&e instanceof Element)return!1;for(c=s;0!=c--;)if(("_owner"!==l[c]&&"__v"!==l[c]&&"__o"!==l[c]||!e.$$typeof)&&!a(e[l[c]],i[l[c]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return a(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},80545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>W});var r=n(96540),o=n(5556),a=n.n(o),i=n(30115),s=n.n(i),c=n(20311),l=n.n(c),u=n(2833),p=n.n(u);function d(){return d=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},d.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t.indexOf(n=a[r])>=0||(o[n]=e[n]);return o}var v={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},g={rel:["amphtml","canonical","alternate"]},b={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(v).map((function(e){return v[e]})),_={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},x=Object.keys(_).reduce((function(e,t){return e[_[t]]=t,e}),{}),S=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},k=function(e){var t=S(e,v.TITLE),n=S(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=S(e,"defaultTitle");return t||r||void 0},E=function(e){return S(e,"onChangeClientState")||function(){}},O=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return d({},e,t)}),{})},j=function(e,t){return t.filter((function(e){return void 0!==e[v.BASE]})).map((function(e){return e[v.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),o=0;o<r.length;o+=1){var a=r[o].toLowerCase();if(-1!==e.indexOf(a)&&n[a])return t.concat(n)}return t}),[])},P=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var o={};n.filter((function(e){for(var n,a=Object.keys(e),i=0;i<a.length;i+=1){var s=a[i],c=s.toLowerCase();-1===t.indexOf(c)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===c&&"stylesheet"===e[c].toLowerCase()||(n=c),-1===t.indexOf(s)||"innerHTML"!==s&&"cssText"!==s&&"itemprop"!==s||(n=s)}if(!n||!e[n])return!1;var l=e[n].toLowerCase();return r[n]||(r[n]={}),o[n]||(o[n]={}),!r[n][l]&&(o[n][l]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var a=Object.keys(o),i=0;i<a.length;i+=1){var s=a[i],c=d({},r[s],o[s]);r[s]=c}return e}),[]).reverse()},C=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},A=function(e){return Array.isArray(e)?e.join(""):e},T=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},I=function(e,t){var n;return d({},e,((n={})[t]=void 0,n))},N=[v.NOSCRIPT,v.SCRIPT,v.STYLE],L=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},R=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},D=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[_[n]||n]=e[n],t}),t)},F=function(e,t){return t.map((function(t,n){var o,a=((o={key:n})["data-rh"]=!0,o);return Object.keys(t).forEach((function(e){var n=_[e]||e;"innerHTML"===n||"cssText"===n?a.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:a[n]=t[e]})),r.createElement(e,a)}))},M=function(e,t,n){switch(e){case v.TITLE:return{toComponent:function(){return n=t.titleAttributes,(o={key:e=t.title})["data-rh"]=!0,a=D(n,o),[r.createElement(v.TITLE,a,e)];var e,n,o,a},toString:function(){return function(e,t,n,r){var o=R(n),a=A(t);return o?"<"+e+' data-rh="true" '+o+">"+L(a,r)+"</"+e+">":"<"+e+' data-rh="true">'+L(a,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return D(t)},toString:function(){return R(t)}};default:return{toComponent:function(){return F(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var o=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var o=void 0===r[t]?t:t+'="'+L(r[t],n)+'"';return e?e+" "+o:o}),""),a=r.innerHTML||r.cssText||"",i=-1===N.indexOf(e);return t+"<"+e+' data-rh="true" '+o+(i?"/>":">"+a+"</"+e+">")}),"")}(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,o=e.htmlAttributes,a=e.noscriptTags,i=e.styleTags,s=e.title,c=void 0===s?"":s,l=e.titleAttributes,u=e.linkTags,p=e.metaTags,d=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,o=T(e.metaTags,y),a=T(t,g),i=T(n,b);return{priorityMethods:{toComponent:function(){return[].concat(F(v.META,o.priority),F(v.LINK,a.priority),F(v.SCRIPT,i.priority))},toString:function(){return M(v.META,o.priority,r)+" "+M(v.LINK,a.priority,r)+" "+M(v.SCRIPT,i.priority,r)}},metaTags:o.default,linkTags:a.default,scriptTags:i.default}}(e);f=m.priorityMethods,u=m.linkTags,p=m.metaTags,d=m.scriptTags}return{priority:f,base:M(v.BASE,t,r),bodyAttributes:M("bodyAttributes",n,r),htmlAttributes:M("htmlAttributes",o,r),link:M(v.LINK,u,r),meta:M(v.META,p,r),noscript:M(v.NOSCRIPT,a,r),script:M(v.SCRIPT,d,r),style:M(v.STYLE,i,r),title:M(v.TITLE,{title:c,titleAttributes:l},r)}},z=[],$=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?z:n.instances},add:function(e){(n.canUseDOM?z:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?z:n.instances).indexOf(e);(n.canUseDOM?z:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=B({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},U=r.createContext({}),H=a().shape({setHelmet:a().func,helmetInstances:a().shape({get:a().func,add:a().func,remove:a().func})}),V="undefined"!=typeof document,W=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new $(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement(U.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);W.canUseDOM=V,W.propTypes={context:a().shape({helmet:a().shape()}),children:a().node.isRequired},W.defaultProps={context:{}},W.displayName="HelmetProvider";var Q=function(e,t){var n,r=document.head||document.querySelector(v.HEAD),o=r.querySelectorAll(e+"[data-rh]"),a=[].slice.call(o),i=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&("innerHTML"===o?r.innerHTML=t.innerHTML:"cssText"===o?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(o,void 0===t[o]?"":t[o]));r.setAttribute("data-rh","true"),a.some((function(e,t){return n=t,r.isEqualNode(e)}))?a.splice(n,1):i.push(r)})),a.forEach((function(e){return e.parentNode.removeChild(e)})),i.forEach((function(e){return r.appendChild(e)})),{oldTags:a,newTags:i}},q=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),o=r?r.split(","):[],a=[].concat(o),i=Object.keys(t),s=0;s<i.length;s+=1){var c=i[s],l=t[c]||"";n.getAttribute(c)!==l&&n.setAttribute(c,l),-1===o.indexOf(c)&&o.push(c);var u=a.indexOf(c);-1!==u&&a.splice(u,1)}for(var p=a.length-1;p>=0;p-=1)n.removeAttribute(a[p]);o.length===a.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},G=function(e,t){var n=e.baseTag,r=e.htmlAttributes,o=e.linkTags,a=e.metaTags,i=e.noscriptTags,s=e.onChangeClientState,c=e.scriptTags,l=e.styleTags,u=e.title,p=e.titleAttributes;q(v.BODY,e.bodyAttributes),q(v.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=A(e)),q(v.TITLE,t)}(u,p);var d={baseTag:Q(v.BASE,n),linkTags:Q(v.LINK,o),metaTags:Q(v.META,a),noscriptTags:Q(v.NOSCRIPT,i),scriptTags:Q(v.SCRIPT,c),styleTags:Q(v.STYLE,l)},f={},m={};Object.keys(d).forEach((function(e){var t=d[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(m[e]=d[e].oldTags)})),t&&t(),s(e,f,m)},K=null,Y=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!p()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,o=null,a=(e=n.helmetInstances.get().map((function(e){var t=d({},e.props);return delete t.context,t})),{baseTag:j(["href"],e),bodyAttributes:O("bodyAttributes",e),defer:S(e,"defer"),encode:S(e,"encodeSpecialCharacters"),htmlAttributes:O("htmlAttributes",e),linkTags:P(v.LINK,["rel","href"],e),metaTags:P(v.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:P(v.NOSCRIPT,["innerHTML"],e),onChangeClientState:E(e),scriptTags:P(v.SCRIPT,["src","innerHTML"],e),styleTags:P(v.STYLE,["cssText"],e),title:k(e),titleAttributes:O("titleAttributes",e),prioritizeSeoTags:C(e,"prioritizeSeoTags")});W.canUseDOM?(t=a,K&&cancelAnimationFrame(K),t.defer?K=requestAnimationFrame((function(){G(t,(function(){K=null}))})):(G(t),K=null)):B&&(o=B(a)),r(o)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);Y.propTypes={context:H.isRequired},Y.displayName="HelmetDispatcher";var Z=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!s()(I(this.props,"helmetData"),I(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case v.SCRIPT:case v.NOSCRIPT:return{innerHTML:t};case v.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return d({},r,((t={})[n.type]=[].concat(r[n.type]||[],[d({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,o=e.newProps,a=e.newChildProps,i=e.nestedChildren;switch(r.type){case v.TITLE:return d({},o,((t={})[r.type]=i,t.titleAttributes=d({},a),t));case v.BODY:return d({},o,{bodyAttributes:d({},a)});case v.HTML:return d({},o,{htmlAttributes:d({},a)});default:return d({},o,((n={})[r.type]=d({},a),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=d({},t);return Object.keys(e).forEach((function(t){var r;n=d({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return l()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),l()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,o={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,a=r.children,i=h(r,Z),s=Object.keys(i).reduce((function(e,t){return e[x[t]||t]=i[t],e}),{}),c=e.type;switch("symbol"==typeof c?c=c.toString():n.warnOnInvalidChildren(e,a),c){case v.FRAGMENT:t=n.mapChildrenToProps(a,t);break;case v.LINK:case v.META:case v.NOSCRIPT:case v.SCRIPT:case v.STYLE:o=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:o,newChildProps:s,nestedChildren:a});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:s,nestedChildren:a})}}})),this.mapArrayTypeChildrenToProps(o,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,X),o=d({},n),a=n.helmetData;return t&&(o=this.mapChildrenToProps(t,o)),!a||a instanceof $||(a=new $(a.context,a.instances)),a?r.createElement(Y,d({},o,{context:a.value,helmetData:void 0})):r.createElement(U.Consumer,null,(function(e){return r.createElement(Y,d({},o,{context:e}))}))},t}(r.Component);J.propTypes={base:a().object,bodyAttributes:a().object,children:a().oneOfType([a().arrayOf(a().node),a().node]),defaultTitle:a().string,defer:a().bool,encodeSpecialCharacters:a().bool,htmlAttributes:a().object,link:a().arrayOf(a().object),meta:a().arrayOf(a().object),noscript:a().arrayOf(a().object),onChangeClientState:a().func,script:a().arrayOf(a().object),style:a().arrayOf(a().object),title:a().string,titleAttributes:a().object,titleTemplate:a().string,prioritizeSeoTags:a().bool,helmetData:a().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},22799:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,o=n?Symbol.for("react.portal"):60106,a=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,s=n?Symbol.for("react.profiler"):60114,c=n?Symbol.for("react.provider"):60109,l=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,p=n?Symbol.for("react.concurrent_mode"):60111,d=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,v=n?Symbol.for("react.lazy"):60116,g=n?Symbol.for("react.block"):60121,b=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function _(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case p:case a:case s:case i:case f:return e;default:switch(e=e&&e.$$typeof){case l:case d:case v:case h:case c:return e;default:return t}}case o:return t}}}function x(e){return _(e)===p}t.AsyncMode=u,t.ConcurrentMode=p,t.ContextConsumer=l,t.ContextProvider=c,t.Element=r,t.ForwardRef=d,t.Fragment=a,t.Lazy=v,t.Memo=h,t.Portal=o,t.Profiler=s,t.StrictMode=i,t.Suspense=f,t.isAsyncMode=function(e){return x(e)||_(e)===u},t.isConcurrentMode=x,t.isContextConsumer=function(e){return _(e)===l},t.isContextProvider=function(e){return _(e)===c},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return _(e)===d},t.isFragment=function(e){return _(e)===a},t.isLazy=function(e){return _(e)===v},t.isMemo=function(e){return _(e)===h},t.isPortal=function(e){return _(e)===o},t.isProfiler=function(e){return _(e)===s},t.isStrictMode=function(e){return _(e)===i},t.isSuspense=function(e){return _(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===p||e===s||e===i||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===v||e.$$typeof===h||e.$$typeof===c||e.$$typeof===l||e.$$typeof===d||e.$$typeof===b||e.$$typeof===y||e.$$typeof===w||e.$$typeof===g)},t.typeOf=_},44363:(e,t,n)=>{"use strict";e.exports=n(22799)},53259:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function o(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}var s=n(96540),c=[],l=[];var u=s.createContext(null);function p(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function d(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var o=p(e[r]);o.loading?t.loading=!0:(t.loaded[r]=o.loaded,t.error=o.error),n.push(o.promise),o.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return s.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var p,d;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=i({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),h=null;function v(){return h||(h=e(m.loader)),h.promise}return c.push(v),"function"==typeof m.webpack&&l.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return v()})),d=p=function(t){function n(n){var r;return a(o(o(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),r._loadModule()})),v(),r.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},r}r(n,t),n.preload=function(){return v()};var i=n.prototype;return i.UNSAFE_componentWillMount=function(){this._loadModule()},i.componentDidMount=function(){this._mounted=!0},i._loadModule=function(){var e=this;if(this.context&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},i.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},i._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},i.render=function(){return this.state.loading||this.state.error?s.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(s.Component),a(p,"contextType",u),d}function h(e){return m(p,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(d,e)};var v=function(e){function t(){return e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(){return s.createElement(u.Provider,{value:{report:this.props.report}},s.Children.only(this.props.children))},t}(s.Component);function g(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return g(e)}))}h.Capture=v,h.preloadAll=function(){return new Promise((function(e,t){g(c).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){g(l).then(e,e)}))},e.exports=h},22831:(e,t,n)=>{"use strict";n.d(t,{u:()=>i,v:()=>s});var r=n(56347),o=n(58168),a=n(96540);function i(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var o=e.path?(0,r.B6)(t,e):n.length?n[n.length-1].match:r.Ix.computeRootMatch(t);return o&&(n.push({route:e,match:o}),e.routes&&i(e.routes,t,n)),o})),n}function s(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?a.createElement(r.dO,n,e.map((function(e,n){return a.createElement(r.qh,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,o.A)({},n,{},t,{route:e})):a.createElement(e.component,(0,o.A)({},n,t,{route:e}))}})}))):null}},54625:(e,t,n)=>{"use strict";n.d(t,{I9:()=>p,Kd:()=>u,N_:()=>g,k2:()=>w});var r=n(56347),o=n(42892),a=n(96540),i=n(31513),s=n(58168),c=n(98587),l=n(11561),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.zR)(t.props),t}return(0,o.A)(t,e),t.prototype.render=function(){return a.createElement(r.Ix,{history:this.history,children:this.props.children})},t}(a.Component);var p=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.TM)(t.props),t}return(0,o.A)(t,e),t.prototype.render=function(){return a.createElement(r.Ix,{history:this.history,children:this.props.children})},t}(a.Component);var d=function(e,t){return"function"==typeof e?e(t):e},f=function(e,t){return"string"==typeof e?(0,i.yJ)(e,null,null,t):e},m=function(e){return e},h=a.forwardRef;void 0===h&&(h=m);var v=h((function(e,t){var n=e.innerRef,r=e.navigate,o=e.onClick,i=(0,c.A)(e,["innerRef","navigate","onClick"]),l=i.target,u=(0,s.A)({},i,{onClick:function(e){try{o&&o(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||l&&"_self"!==l||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=m!==h&&t||n,a.createElement("a",u)}));var g=h((function(e,t){var n=e.component,o=void 0===n?v:n,u=e.replace,p=e.to,g=e.innerRef,b=(0,c.A)(e,["component","replace","to","innerRef"]);return a.createElement(r.XZ.Consumer,null,(function(e){e||(0,l.A)(!1);var n=e.history,r=f(d(p,e.location),e.location),c=r?n.createHref(r):"",v=(0,s.A)({},b,{href:c,navigate:function(){var t=d(p,e.location),r=(0,i.AO)(e.location)===(0,i.AO)(f(t));(u||r?n.replace:n.push)(t)}});return m!==h?v.ref=t||g:v.innerRef=g,a.createElement(o,v)}))})),b=function(e){return e},y=a.forwardRef;void 0===y&&(y=b);var w=y((function(e,t){var n=e["aria-current"],o=void 0===n?"page":n,i=e.activeClassName,u=void 0===i?"active":i,p=e.activeStyle,m=e.className,h=e.exact,v=e.isActive,w=e.location,_=e.sensitive,x=e.strict,S=e.style,k=e.to,E=e.innerRef,O=(0,c.A)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return a.createElement(r.XZ.Consumer,null,(function(e){e||(0,l.A)(!1);var n=w||e.location,i=f(d(k,n),n),c=i.pathname,j=c&&c.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),P=j?(0,r.B6)(n.pathname,{path:j,exact:h,sensitive:_,strict:x}):null,C=!!(v?v(P,n):P),A="function"==typeof m?m(C):m,T="function"==typeof S?S(C):S;C&&(A=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(A,u),T=(0,s.A)({},T,p));var I=(0,s.A)({"aria-current":C&&o||null,className:A,style:T,to:i},O);return b!==y?I.ref=t||E:I.innerRef=E,a.createElement(g,I)}))}))},56347:(e,t,n)=>{"use strict";n.d(t,{B6:()=>S,Ix:()=>y,W6:()=>I,XZ:()=>b,dO:()=>A,qh:()=>k,zy:()=>N});var r=n(42892),o=n(96540),a=n(5556),i=n.n(a),s=n(31513),c=n(11561),l=n(58168),u=n(8505),p=n.n(u),d=(n(44363),n(98587)),f=(n(4146),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=o.createContext||function(e,t){var n,a,s="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",c=function(e){function n(){for(var t,n,r,o=arguments.length,a=new Array(o),i=0;i<o;i++)a[i]=arguments[i];return(t=e.call.apply(e,[this].concat(a))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.A)(n,e);var o=n.prototype;return o.getChildContext=function(){var e;return(e={})[s]=this.emitter,e},o.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,o=e.value;((a=r)===(i=o)?0!==a||1/a==1/i:a!=a&&i!=i)?n=0:(n="function"==typeof t?t(r,o):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var a,i},o.render=function(){return this.props.children},n}(o.Component);c.childContextTypes=((n={})[s]=i().object.isRequired,n);var l=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){(0|e.observedBits)&n&&e.setState({value:e.getValue()})},e}(0,r.A)(n,t);var o=n.prototype;return o.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},o.componentDidMount=function(){this.context[s]&&this.context[s].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},o.componentWillUnmount=function(){this.context[s]&&this.context[s].off(this.onUpdate)},o.getValue=function(){return this.context[s]?this.context[s].get():e},o.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(o.Component);return l.contextTypes=((a={})[s]=i().object,a),{Provider:c,Consumer:l}},v=function(e){var t=h();return t.displayName=e,t},g=v("Router-History"),b=v("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.A)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return o.createElement(b.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},o.createElement(g.Provider,{children:this.props.children||null,value:this.props.history}))},t}(o.Component);o.Component;o.Component;var w={},_=1e4,x=0;function S(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,o=n.exact,a=void 0!==o&&o,i=n.strict,s=void 0!==i&&i,c=n.sensitive,l=void 0!==c&&c;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var o=[],a={regexp:p()(e,o,t),keys:o};return x<_&&(r[e]=a,x++),a}(n,{end:a,strict:s,sensitive:l}),o=r.regexp,i=r.keys,c=o.exec(e);if(!c)return null;var u=c[0],d=c.slice(1),f=e===u;return a&&!f?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:f,params:i.reduce((function(e,t,n){return e[t.name]=d[n],e}),{})}}),null)}var k=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.A)(t,e),t.prototype.render=function(){var e=this;return o.createElement(b.Consumer,null,(function(t){t||(0,c.A)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?S(n.pathname,e.props):t.match,a=(0,l.A)({},t,{location:n,match:r}),i=e.props,s=i.children,u=i.component,p=i.render;return Array.isArray(s)&&function(e){return 0===o.Children.count(e)}(s)&&(s=null),o.createElement(b.Provider,{value:a},a.match?s?"function"==typeof s?s(a):s:u?o.createElement(u,a):p?p(a):null:"function"==typeof s?s(a):null)}))},t}(o.Component);function E(e){return"/"===e.charAt(0)?e:"/"+e}function O(e,t){if(!e)return t;var n=E(e);return 0!==t.pathname.indexOf(n)?t:(0,l.A)({},t,{pathname:t.pathname.substr(n.length)})}function j(e){return"string"==typeof e?e:(0,s.AO)(e)}function P(e){return function(){(0,c.A)(!1)}}function C(){}o.Component;var A=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.A)(t,e),t.prototype.render=function(){var e=this;return o.createElement(b.Consumer,null,(function(t){t||(0,c.A)(!1);var n,r,a=e.props.location||t.location;return o.Children.forEach(e.props.children,(function(e){if(null==r&&o.isValidElement(e)){n=e;var i=e.props.path||e.props.from;r=i?S(a.pathname,(0,l.A)({},e.props,{path:i})):t.match}})),r?o.cloneElement(n,{location:a,computedMatch:r}):null}))},t}(o.Component);var T=o.useContext;function I(){return T(g)}function N(){return T(b).location}},8505:(e,t,n)=>{var r=n(64634);e.exports=m,e.exports.parse=a,e.exports.compile=function(e,t){return c(a(e,t),t)},e.exports.tokensToFunction=c,e.exports.tokensToRegExp=f;var o=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function a(e,t){for(var n,r=[],a=0,s=0,c="",l=t&&t.delimiter||"/";null!=(n=o.exec(e));){var p=n[0],d=n[1],f=n.index;if(c+=e.slice(s,f),s=f+p.length,d)c+=d[1];else{var m=e[s],h=n[2],v=n[3],g=n[4],b=n[5],y=n[6],w=n[7];c&&(r.push(c),c="");var _=null!=h&&null!=m&&m!==h,x="+"===y||"*"===y,S="?"===y||"*"===y,k=h||l,E=g||b,O=h||("string"==typeof r[r.length-1]?r[r.length-1]:"");r.push({name:v||a++,prefix:h||"",delimiter:k,optional:S,repeat:x,partial:_,asterisk:!!w,pattern:E?u(E):w?".*":i(k,O)})}}return s<e.length&&(c+=e.substr(s)),c&&r.push(c),r}function i(e,t){return!t||t.indexOf(e)>-1?"[^"+l(e)+"]+?":l(t)+"|(?:(?!"+l(t)+")[^"+l(e)+"])+?"}function s(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function c(e,t){for(var n=new Array(e.length),o=0;o<e.length;o++)"object"==typeof e[o]&&(n[o]=new RegExp("^(?:"+e[o].pattern+")$",d(t)));return function(t,o){for(var a="",i=t||{},c=(o||{}).pretty?s:encodeURIComponent,l=0;l<e.length;l++){var u=e[l];if("string"!=typeof u){var p,d=i[u.name];if(null==d){if(u.optional){u.partial&&(a+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(d)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(d)+"`");if(0===d.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<d.length;f++){if(p=c(d[f]),!n[l].test(p))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(p)+"`");a+=(0===f?u.prefix:u.delimiter)+p}}else{if(p=u.asterisk?encodeURI(d).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):c(d),!n[l].test(p))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+p+'"');a+=u.prefix+p}}else a+=u}return a}}function l(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function u(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function p(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function f(e,t,n){r(t)||(n=t||n,t=[]);for(var o=(n=n||{}).strict,a=!1!==n.end,i="",s=0;s<e.length;s++){var c=e[s];if("string"==typeof c)i+=l(c);else{var u=l(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+u+f+")*"),i+=f=c.optional?c.partial?u+"("+f+")?":"(?:"+u+"("+f+"))?":u+"("+f+")"}}var m=l(n.delimiter||"/"),h=i.slice(-m.length)===m;return o||(i=(h?i.slice(0,-m.length):i)+"(?:"+m+"(?=$))?"),i+=a?"$":o&&h?"":"(?="+m+"|$)",p(new RegExp("^"+i,d(n)),t)}function m(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return p(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],o=0;o<e.length;o++)r.push(m(e[o],t,n).source);return p(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return f(a(e,n),t,n)}(e,t,n)}},21020:(e,t,n)=>{"use strict";var r=n(96540),o=Symbol.for("react.element"),a=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,s=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,c={key:!0,ref:!0,__self:!0,__source:!0};function l(e,t,n){var r,a={},l=null,u=null;for(r in void 0!==n&&(l=""+n),void 0!==t.key&&(l=""+t.key),void 0!==t.ref&&(u=t.ref),t)i.call(t,r)&&!c.hasOwnProperty(r)&&(a[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===a[r]&&(a[r]=t[r]);return{$$typeof:o,type:e,key:l,ref:u,props:a,_owner:s.current}}t.Fragment=a,t.jsx=l,t.jsxs=l},15287:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),a=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),s=Symbol.for("react.provider"),c=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),u=Symbol.for("react.suspense"),p=Symbol.for("react.memo"),d=Symbol.for("react.lazy"),f=Symbol.iterator;var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,v={};function g(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||m}function b(){}function y(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=g.prototype;var w=y.prototype=new b;w.constructor=y,h(w,g.prototype),w.isPureReactComponent=!0;var _=Array.isArray,x=Object.prototype.hasOwnProperty,S={current:null},k={key:!0,ref:!0,__self:!0,__source:!0};function E(e,t,r){var o,a={},i=null,s=null;if(null!=t)for(o in void 0!==t.ref&&(s=t.ref),void 0!==t.key&&(i=""+t.key),t)x.call(t,o)&&!k.hasOwnProperty(o)&&(a[o]=t[o]);var c=arguments.length-2;if(1===c)a.children=r;else if(1<c){for(var l=Array(c),u=0;u<c;u++)l[u]=arguments[u+2];a.children=l}if(e&&e.defaultProps)for(o in c=e.defaultProps)void 0===a[o]&&(a[o]=c[o]);return{$$typeof:n,type:e,key:i,ref:s,props:a,_owner:S.current}}function O(e){return"object"==typeof e&&null!==e&&e.$$typeof===n}var j=/\/+/g;function P(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function C(e,t,o,a,i){var s=typeof e;"undefined"!==s&&"boolean"!==s||(e=null);var c=!1;if(null===e)c=!0;else switch(s){case"string":case"number":c=!0;break;case"object":switch(e.$$typeof){case n:case r:c=!0}}if(c)return i=i(c=e),e=""===a?"."+P(c,0):a,_(i)?(o="",null!=e&&(o=e.replace(j,"$&/")+"/"),C(i,t,o,"",(function(e){return e}))):null!=i&&(O(i)&&(i=function(e,t){return{$$typeof:n,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(i,o+(!i.key||c&&c.key===i.key?"":(""+i.key).replace(j,"$&/")+"/")+e)),t.push(i)),1;if(c=0,a=""===a?".":a+":",_(e))for(var l=0;l<e.length;l++){var u=a+P(s=e[l],l);c+=C(s,t,o,u,i)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=f&&e[f]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),l=0;!(s=e.next()).done;)c+=C(s=s.value,t,o,u=a+P(s,l++),i);else if("object"===s)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return c}function A(e,t,n){if(null==e)return e;var r=[],o=0;return C(e,r,"","",(function(e){return t.call(n,e,o++)})),r}function T(e){if(-1===e._status){var t=e._result;(t=t()).then((function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)}),(function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)})),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var I={current:null},N={transition:null},L={ReactCurrentDispatcher:I,ReactCurrentBatchConfig:N,ReactCurrentOwner:S};function R(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:A,forEach:function(e,t,n){A(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return A(e,(function(){t++})),t},toArray:function(e){return A(e,(function(e){return e}))||[]},only:function(e){if(!O(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=g,t.Fragment=o,t.Profiler=i,t.PureComponent=y,t.StrictMode=a,t.Suspense=u,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=L,t.act=R,t.cloneElement=function(e,t,r){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var o=h({},e.props),a=e.key,i=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(i=t.ref,s=S.current),void 0!==t.key&&(a=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(l in t)x.call(t,l)&&!k.hasOwnProperty(l)&&(o[l]=void 0===t[l]&&void 0!==c?c[l]:t[l])}var l=arguments.length-2;if(1===l)o.children=r;else if(1<l){c=Array(l);for(var u=0;u<l;u++)c[u]=arguments[u+2];o.children=c}return{$$typeof:n,type:e.type,key:a,ref:i,props:o,_owner:s}},t.createContext=function(e){return(e={$$typeof:c,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:s,_context:e},e.Consumer=e},t.createElement=E,t.createFactory=function(e){var t=E.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:l,render:e}},t.isValidElement=O,t.lazy=function(e){return{$$typeof:d,_payload:{_status:-1,_result:e},_init:T}},t.memo=function(e,t){return{$$typeof:p,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=N.transition;N.transition={};try{e()}finally{N.transition=t}},t.unstable_act=R,t.useCallback=function(e,t){return I.current.useCallback(e,t)},t.useContext=function(e){return I.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return I.current.useDeferredValue(e)},t.useEffect=function(e,t){return I.current.useEffect(e,t)},t.useId=function(){return I.current.useId()},t.useImperativeHandle=function(e,t,n){return I.current.useImperativeHandle(e,t,n)},t.useInsertionEffect=function(e,t){return I.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return I.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return I.current.useMemo(e,t)},t.useReducer=function(e,t,n){return I.current.useReducer(e,t,n)},t.useRef=function(e){return I.current.useRef(e)},t.useState=function(e){return I.current.useState(e)},t.useSyncExternalStore=function(e,t,n){return I.current.useSyncExternalStore(e,t,n)},t.useTransition=function(){return I.current.useTransition()},t.version="18.3.1"},96540:(e,t,n)=>{"use strict";e.exports=n(15287)},74848:(e,t,n)=>{"use strict";e.exports=n(21020)},7463:(e,t)=>{"use strict";function n(e,t){var n=e.length;e.push(t);e:for(;0<n;){var r=n-1>>>1,o=e[r];if(!(0<a(o,t)))break e;e[r]=t,e[n]=o,n=r}}function r(e){return 0===e.length?null:e[0]}function o(e){if(0===e.length)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,o=e.length,i=o>>>1;r<i;){var s=2*(r+1)-1,c=e[s],l=s+1,u=e[l];if(0>a(c,n))l<o&&0>a(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else{if(!(l<o&&0>a(u,n)))break e;e[r]=u,e[l]=n,r=l}}}return t}function a(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;t.unstable_now=function(){return i.now()}}else{var s=Date,c=s.now();t.unstable_now=function(){return s.now()-c}}var l=[],u=[],p=1,d=null,f=3,m=!1,h=!1,v=!1,g="function"==typeof setTimeout?setTimeout:null,b="function"==typeof clearTimeout?clearTimeout:null,y="undefined"!=typeof setImmediate?setImmediate:null;function w(e){for(var t=r(u);null!==t;){if(null===t.callback)o(u);else{if(!(t.startTime<=e))break;o(u),t.sortIndex=t.expirationTime,n(l,t)}t=r(u)}}function _(e){if(v=!1,w(e),!h)if(null!==r(l))h=!0,N(x);else{var t=r(u);null!==t&&L(_,t.startTime-e)}}function x(e,n){h=!1,v&&(v=!1,b(O),O=-1),m=!0;var a=f;try{for(w(n),d=r(l);null!==d&&(!(d.expirationTime>n)||e&&!C());){var i=d.callback;if("function"==typeof i){d.callback=null,f=d.priorityLevel;var s=i(d.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?d.callback=s:d===r(l)&&o(l),w(n)}else o(l);d=r(l)}if(null!==d)var c=!0;else{var p=r(u);null!==p&&L(_,p.startTime-n),c=!1}return c}finally{d=null,f=a,m=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var S,k=!1,E=null,O=-1,j=5,P=-1;function C(){return!(t.unstable_now()-P<j)}function A(){if(null!==E){var e=t.unstable_now();P=e;var n=!0;try{n=E(!0,e)}finally{n?S():(k=!1,E=null)}}else k=!1}if("function"==typeof y)S=function(){y(A)};else if("undefined"!=typeof MessageChannel){var T=new MessageChannel,I=T.port2;T.port1.onmessage=A,S=function(){I.postMessage(null)}}else S=function(){g(A,0)};function N(e){E=e,k||(k=!0,S())}function L(e,n){O=g((function(){e(t.unstable_now())}),n)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){h||m||(h=!0,N(x))},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):j=0<e?Math.floor(1e3/e):5},t.unstable_getCurrentPriorityLevel=function(){return f},t.unstable_getFirstCallbackNode=function(){return r(l)},t.unstable_next=function(e){switch(f){case 1:case 2:case 3:var t=3;break;default:t=f}var n=f;f=t;try{return e()}finally{f=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=function(){},t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=f;f=e;try{return t()}finally{f=n}},t.unstable_scheduleCallback=function(e,o,a){var i=t.unstable_now();switch("object"==typeof a&&null!==a?a="number"==typeof(a=a.delay)&&0<a?i+a:i:a=i,e){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return e={id:p++,callback:o,priorityLevel:e,startTime:a,expirationTime:s=a+s,sortIndex:-1},a>i?(e.sortIndex=a,n(u,e),null===r(l)&&e===r(u)&&(v?(b(O),O=-1):v=!0,L(_,a-i))):(e.sortIndex=s,n(l,e),h||m||(h=!0,N(x))),e},t.unstable_shouldYield=C,t.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}},69982:(e,t,n)=>{"use strict";e.exports=n(7463)},2833:e=>{e.exports=function(e,t,n,r){var o=n?n.call(r,e,t):void 0;if(void 0!==o)return!!o;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var a=Object.keys(e),i=Object.keys(t);if(a.length!==i.length)return!1;for(var s=Object.prototype.hasOwnProperty.bind(t),c=0;c<a.length;c++){var l=a[c];if(!s(l))return!1;var u=e[l],p=t[l];if(!1===(o=n?n.call(r,u,p,l):void 0)||void 0===o&&u!==p)return!1}return!0}},4784:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const r={title:"Contrast",tagline:"Contrast: Confidential Containers at scale",url:"https://docs.edgeless.systems",baseUrl:"/contrast/pr-preview/pr-1071/",trailingSlash:!1,onBrokenLinks:"throw",onBrokenMarkdownLinks:"throw",onBrokenAnchors:"throw",favicon:"img/favicon.ico",organizationName:"edgelesssys",projectName:"contrast",deploymentBranch:"gh-pages",scripts:[{src:"/contrast/gtagman.js",async:!0,"data-cookieconsent":"ignore"}],i18n:{defaultLocale:"en",locales:["en"],path:"i18n",localeConfigs:{}},markdown:{mermaid:!0,format:"mdx",mdx1Compat:{comments:!0,admonitions:!0,headingIds:!0},anchors:{maintainCase:!1}},themes:["@docusaurus/theme-mermaid"],presets:[["classic",{docs:{sidebarPath:"/build/docs/sidebars.js",editUrl:"https://github.com/edgelesssys/contrast/edit/main/docs",routeBasePath:"/"},blog:!1,theme:{customCss:"/build/docs/src/css/custom.css"}}]],themeConfig:{navbar:{hideOnScroll:!1,logo:{alt:"Contrast Logo",src:"img/logos/contrast_icon.svg"},items:[{type:"docsVersionDropdown",position:"right",dropdownItemsBefore:[],dropdownItemsAfter:[]},{href:"https://github.com/edgelesssys/contrast",position:"right",className:"header-github-link"}]},colorMode:{defaultMode:"light",disableSwitch:!0,respectPrefersColorScheme:!1},announcementBar:{content:'Contrast is now open source! Check it out on <a target="_blank" rel="noopener noreferrer" href="https://github.com/edgelesssys/contrast">GitHub</a> and leave us a \u2b50\ufe0f if you like it!',backgroundColor:"#E7E6E6",id:"announcement-bar",isCloseable:!0},footer:{style:"dark",links:[{title:"Community",items:[{label:"Newsletter",href:"https://www.edgeless.systems/#footer-id"}]},{title:"Social",items:[{label:"Blog",href:"https://www.edgeless.systems/blog/"},{label:"Twitter",href:"https://twitter.com/EdgelessSystems"},{label:"LinkedIn",href:"https://www.linkedin.com/company/edgeless-systems/"},{label:"Youtube",href:"https://www.youtube.com/channel/UCOOInN0sCv6icUesisYIDeA"}]},{title:"Company",items:[{label:"Imprint",href:"https://www.edgeless.systems/imprint/"},{label:"Privacy Policy",href:"https://www.edgeless.systems/privacy/"},{html:'<a href="javascript: Cookiebot.renew()" class="footer__link-item">Cookie Settings</a>'},{label:"Contact Us",href:"https://www.edgeless.systems/contact-us/"}]}],copyright:"Copyright \xa9 2024 Edgeless Systems"},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:["shell-session","bash","json","diff"],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},mermaid:{theme:{light:"base",dark:"base"},options:{themeVariables:{fontFamily:'"Open Sans", sans-serif',primaryColor:"#90FF99",primaryTextColor:"#000000",secondaryColor:"#A5A5A5",secondaryTextColor:"#000000",tertiaryColor:"#E7E6E6",tertiaryTextColor:"#000000",clusterBorder:"#A5A5A5",clusterBkg:"#ffffff",edgeLabelBackground:"#ffffff",activationBorderColor:"#000000",actorBorder:"#A5A5A5",actorFontFamily:'"Open Sans", sans-serif',noteBkgColor:"#8B04DD",noteTextColor:"#ffffff"},startOnLoad:!0}},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},blog:{sidebar:{groupByYear:!0}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},plugins:[["/build/docs/node_modules/@cmfcmf/docusaurus-search-local/lib/server/index.js",{indexDocs:!0,indexDocSidebarParentCategories:0,indexBlog:!1,indexPages:!1,language:"en",maxSearchResults:8,lunr:{tokenizerSeparator:{},b:.75,k1:1.2,titleBoost:5,contentBoost:1,tagsBoost:3,parentCategoriesBoost:2}}]],baseUrlIssueBanner:!0,future:{experimental_faster:{swcJsLoader:!1,swcJsMinimizer:!1,swcHtmlMinimizer:!1,lightningCssMinimizer:!1,mdxCrossCompilerCache:!1,rspackBundler:!1},experimental_storage:{type:"localStorage",namespace:!1},experimental_router:"browser"},onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1}},58168:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(null,arguments)}n.d(t,{A:()=>r})},42892:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function o(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{A:()=>o})},98587:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}n.d(t,{A:()=>r})},34164:(e,t,n)=>{"use strict";function r(e){var t,n,o="";if("string"==typeof e||"number"==typeof e)o+=e;else if("object"==typeof e)if(Array.isArray(e)){var a=e.length;for(t=0;t<a;t++)e[t]&&(n=r(e[t]))&&(o&&(o+=" "),o+=n)}else for(n in e)e[n]&&(o&&(o+=" "),o+=n);return o}n.d(t,{A:()=>o});const o=function(){for(var e,t,n=0,o="",a=arguments.length;n<a;n++)(e=arguments[n])&&(t=r(e))&&(o&&(o+=" "),o+=t);return o}},71765:(e,t,n)=>{"use strict";n.d(t,{My:()=>j,f4:()=>ne});var r,o,a,i,s,c,l,u=n(96540),p=n(34164),d=Object.create,f=Object.defineProperty,m=Object.defineProperties,h=Object.getOwnPropertyDescriptor,v=Object.getOwnPropertyDescriptors,g=Object.getOwnPropertyNames,b=Object.getOwnPropertySymbols,y=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty,_=Object.prototype.propertyIsEnumerable,x=(e,t,n)=>t in e?f(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,S=(e,t)=>{for(var n in t||(t={}))w.call(t,n)&&x(e,n,t[n]);if(b)for(var n of b(t))_.call(t,n)&&x(e,n,t[n]);return e},k=(e,t)=>m(e,v(t)),E=(e,t)=>{var n={};for(var r in e)w.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&b)for(var r of b(e))t.indexOf(r)<0&&_.call(e,r)&&(n[r]=e[r]);return n},O=(r={"../../node_modules/.pnpm/prismjs@1.29.0_patch_hash=vrxx3pzkik6jpmgpayxfjunetu/node_modules/prismjs/prism.js"(e,t){var n=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof o?new o(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var o,a;switch(n=n||{},r.util.type(t)){case"Object":if(a=r.util.objId(t),n[a])return n[a];for(var i in o={},n[a]=o,t)t.hasOwnProperty(i)&&(o[i]=e(t[i],n));return o;case"Array":return a=r.util.objId(t),n[a]?n[a]:(o=[],n[a]=o,t.forEach((function(t,r){o[r]=e(t,n)})),o);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var o=e.classList;if(o.contains(t))return!0;if(o.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var o in t)n[o]=t[o];return n},insertBefore:function(e,t,n,o){var a=(o=o||r.languages)[e],i={};for(var s in a)if(a.hasOwnProperty(s)){if(s==t)for(var c in n)n.hasOwnProperty(c)&&(i[c]=n[c]);n.hasOwnProperty(s)||(i[s]=a[s])}var l=o[e];return o[e]=i,r.languages.DFS(r.languages,(function(t,n){n===l&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,o,a){a=a||{};var i=r.util.objId;for(var s in t)if(t.hasOwnProperty(s)){n.call(t,s,t[s],o||s);var c=t[s],l=r.util.type(c);"Object"!==l||a[i(c)]?"Array"!==l||a[i(c)]||(a[i(c)]=!0,e(c,n,s,a)):(a[i(c)]=!0,e(c,n,null,a))}}},plugins:{},highlight:function(e,t,n){var a={code:e,grammar:t,language:n};if(r.hooks.run("before-tokenize",a),!a.grammar)throw new Error('The language "'+a.language+'" has no grammar.');return a.tokens=r.tokenize(a.code,a.grammar),r.hooks.run("after-tokenize",a),o.stringify(r.util.encode(a.tokens),a.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var o=new s;return c(o,o.head,e),i(e,o,t,o.head,0),function(e){for(var t=[],n=e.head.next;n!==e.tail;)t.push(n.value),n=n.next;return t}(o)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var o,a=0;o=n[a++];)o(t)}},Token:o};function o(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function a(e,t,n,r){e.lastIndex=t;var o=e.exec(n);if(o&&r&&o[1]){var a=o[1].length;o.index+=a,o[0]=o[0].slice(a)}return o}function i(e,t,n,s,u,p){for(var d in n)if(n.hasOwnProperty(d)&&n[d]){var f=n[d];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(p&&p.cause==d+","+m)return;var h=f[m],v=h.inside,g=!!h.lookbehind,b=!!h.greedy,y=h.alias;if(b&&!h.pattern.global){var w=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,w+"g")}for(var _=h.pattern||h,x=s.next,S=u;x!==t.tail&&!(p&&S>=p.reach);S+=x.value.length,x=x.next){var k=x.value;if(t.length>e.length)return;if(!(k instanceof o)){var E,O=1;if(b){if(!(E=a(_,S,e,g))||E.index>=e.length)break;var j=E.index,P=E.index+E[0].length,C=S;for(C+=x.value.length;j>=C;)C+=(x=x.next).value.length;if(S=C-=x.value.length,x.value instanceof o)continue;for(var A=x;A!==t.tail&&(C<P||"string"==typeof A.value);A=A.next)O++,C+=A.value.length;O--,k=e.slice(S,C),E.index-=S}else if(!(E=a(_,0,k,g)))continue;j=E.index;var T=E[0],I=k.slice(0,j),N=k.slice(j+T.length),L=S+k.length;p&&L>p.reach&&(p.reach=L);var R=x.prev;if(I&&(R=c(t,R,I),S+=I.length),l(t,R,O),x=c(t,R,new o(d,v?r.tokenize(T,v):T,y,T)),N&&c(t,x,N),O>1){var D={cause:d+","+m,reach:L};i(e,t,n,x.prev,S,D),p&&D.reach>p.reach&&(p.reach=D.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function c(e,t,n){var r=t.next,o={value:n,prev:t,next:r};return t.next=o,r.prev=o,e.length++,o}function l(e,t,n){for(var r=t.next,o=0;o<n&&r!==e.tail;o++)r=r.next;t.next=r,r.prev=t,e.length-=o}return o.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var o="";return t.forEach((function(t){o+=e(t,n)})),o}var a={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(a.classes,i):a.classes.push(i)),r.hooks.run("wrap",a);var s="";for(var c in a.attributes)s+=" "+c+'="'+(a.attributes[c]||"").replace(/"/g,""")+'"';return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+s+">"+a.content+"</"+a.tag+">"},r}();t.exports=n,n.default=n}},function(){return o||(0,r[g(r)[0]])((o={exports:{}}).exports,o),o.exports}),j=((e,t,n)=>(n=null!=e?d(y(e)):{},((e,t,n,r)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let o of g(t))w.call(e,o)||o===n||f(e,o,{get:()=>t[o],enumerable:!(r=h(t,o))||r.enumerable});return e})(!t&&e&&e.__esModule?n:f(n,"default",{value:e,enumerable:!0}),e)))(O());j.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},j.languages.markup.tag.inside["attr-value"].inside.entity=j.languages.markup.entity,j.languages.markup.doctype.inside["internal-subset"].inside=j.languages.markup,j.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(j.languages.markup.tag,"addInlined",{value:function(e,t){var n;(t=((n=((n={})["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:j.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i,{"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}}))["language-"+t]={pattern:/[\s\S]+/,inside:j.languages[t]},{}))[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:n},j.languages.insertBefore("markup","cdata",t)}}),Object.defineProperty(j.languages.markup.tag,"addAttribute",{value:function(e,t){j.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:j.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),j.languages.html=j.languages.markup,j.languages.mathml=j.languages.markup,j.languages.svg=j.languages.markup,j.languages.xml=j.languages.extend("markup",{}),j.languages.ssml=j.languages.xml,j.languages.atom=j.languages.xml,j.languages.rss=j.languages.xml,a=j,i={pattern:/\\[\\(){}[\]^$+*?|.]/,alias:"escape"},c="(?:[^\\\\-]|"+(s=/\\(?:x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]+\}|0[0-7]{0,2}|[123][0-7]{2}|c[a-zA-Z]|.)/).source+")",c=RegExp(c+"-"+c),l={pattern:/(<|')[^<>']+(?=[>']$)/,lookbehind:!0,alias:"variable"},a.languages.regex={"char-class":{pattern:/((?:^|[^\\])(?:\\\\)*)\[(?:[^\\\]]|\\[\s\S])*\]/,lookbehind:!0,inside:{"char-class-negation":{pattern:/(^\[)\^/,lookbehind:!0,alias:"operator"},"char-class-punctuation":{pattern:/^\[|\]$/,alias:"punctuation"},range:{pattern:c,inside:{escape:s,"range-punctuation":{pattern:/-/,alias:"operator"}}},"special-escape":i,"char-set":{pattern:/\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},escape:s}},"special-escape":i,"char-set":{pattern:/\.|\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},backreference:[{pattern:/\\(?![123][0-7]{2})[1-9]/,alias:"keyword"},{pattern:/\\k<[^<>']+>/,alias:"keyword",inside:{"group-name":l}}],anchor:{pattern:/[$^]|\\[ABbGZz]/,alias:"function"},escape:s,group:[{pattern:/\((?:\?(?:<[^<>']+>|'[^<>']+'|[>:]|<?[=!]|[idmnsuxU]+(?:-[idmnsuxU]+)?:?))?/,alias:"punctuation",inside:{"group-name":l}},{pattern:/\)/,alias:"punctuation"}],quantifier:{pattern:/(?:[+*?]|\{\d+(?:,\d*)?\})[?+]?/,alias:"number"},alternation:{pattern:/\|/,alias:"keyword"}},j.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},j.languages.javascript=j.languages.extend("clike",{"class-name":[j.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),j.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,j.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:j.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:j.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:j.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:j.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:j.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),j.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:j.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),j.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),j.languages.markup&&(j.languages.markup.tag.addInlined("script","javascript"),j.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),j.languages.js=j.languages.javascript,j.languages.actionscript=j.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|dynamic|each|else|extends|final|finally|for|function|get|if|implements|import|in|include|instanceof|interface|internal|is|namespace|native|new|null|override|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|use|var|void|while|with)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/}),j.languages.actionscript["class-name"].alias="function",delete j.languages.actionscript.parameter,delete j.languages.actionscript["literal-property"],j.languages.markup&&j.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:j.languages.markup}}),function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(j),function(e){var t=e.languages.javadoclike={parameter:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*@(?:arg|arguments|param)\s+)\w+/m,lookbehind:!0},keyword:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*|\{)@[a-z][a-zA-Z-]+\b/m,lookbehind:!0},punctuation:/[{}]/};Object.defineProperty(t,"addSupport",{value:function(t,n){(t="string"==typeof t?[t]:t).forEach((function(t){var r=function(e){e.inside||(e.inside={}),e.inside.rest=n},o="doc-comment";if(a=e.languages[t]){var a,i=a[o];if((i=i||(a=e.languages.insertBefore(t,"comment",{"doc-comment":{pattern:/(^|[^\\])\/\*\*[^/][\s\S]*?(?:\*\/|$)/,lookbehind:!0,alias:"comment"}}))[o])instanceof RegExp&&(i=a[o]={pattern:i}),Array.isArray(i))for(var s=0,c=i.length;s<c;s++)i[s]instanceof RegExp&&(i[s]={pattern:i[s]}),r(i[s]);else r(i)}}))}}),t.addSupport(["java","javascript","php"],t)}(j),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;(t=(e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css,e.languages.markup))&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(j),function(e){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,n=(t=(e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+t.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[t,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}}),{pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0}),{pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0});e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|RebeccaPurple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,number:n})}(j),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",o=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+o+"|"+a+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(a),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(j),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,o=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),a=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source,i=(e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+o+a+"(?:"+o+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+o+a+")(?:"+o+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+o+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+o+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var o,a=t[n];"code"!==a.type?e(a.content):(o=a.content[1],a=a.content[3],o&&a&&"code-language"===o.type&&"code-block"===a.type&&"string"==typeof o.content&&(o=o.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),o="language-"+(o=(/[a-z][\w-]*/i.exec(o)||[""])[0].toLowerCase()),a.alias?"string"==typeof a.alias?a.alias=[a.alias,o]:a.alias.push(o):a.alias=[o]))}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,o=t.classes.length;r<o;r++){var a=t.classes[r];if(a=/language-(.+)/.exec(a)){n=a[1];break}}var l,u=e.languages[n];u?t.content=e.highlight(t.content.replace(i,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;return"#"===(t=t.toLowerCase())[0]?(n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),c(n)):s[t]||e})),u,n):n&&"none"!==n&&e.plugins.autoloader&&(l="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random()),t.attributes.id=l,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(l);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))})))}})),RegExp(e.languages.markup.tag.pattern.source,"gi")),s={amp:"&",lt:"<",gt:">",quot:'"'},c=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(j),j.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:j.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},j.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var o=[];if(p(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var a=d(/^\($/,/^\)$/);if(-1===a)continue;for(;n<a;n++){var i=u(0);"variable"===i.type&&(f(i,"variable-input"),o.push(i.content))}n=a+1}if(p(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),0<o.length)){var s=d(/^\{$/,/^\}$/);if(-1!==s)for(var c=n;c<s;c++){var l=t[c];"variable"===l.type&&0<=o.indexOf(l.content)&&f(l,"variable-input")}}}}function u(e){return t[n+e]}function p(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return}return 1}function d(e,r){for(var o=1,a=n;a<t.length;a++){var i=t[a],s=i.content;if("punctuation"===i.type&&"string"==typeof s)if(e.test(s))o++;else if(r.test(s)&&0==--o)return a}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),j.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,o=r.inside["interpolation-punctuation"],a=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function s(t,n,r){return t={code:t,grammar:n,language:r},e.hooks.run("before-tokenize",t),t.tokens=e.tokenize(t.code,t.grammar),e.hooks.run("after-tokenize",t),t.tokens}function c(t,n,i){var c=e.tokenize(t,{interpolation:{pattern:RegExp(a),lookbehind:!0}}),l=0,u={},p=(c=s(c.map((function(e){if("string"==typeof e)return e;var n,r;for(e=e.content;-1!==t.indexOf((r=l++,n="___"+i.toUpperCase()+"_"+r+"___")););return u[n]=e,n})).join(""),n,i),Object.keys(u));return l=0,function t(n){for(var a=0;a<n.length;a++){if(l>=p.length)return;var i,c,d,f,m,h,v,g=n[a];"string"==typeof g||"string"==typeof g.content?(i=p[l],-1!==(v=(h="string"==typeof g?g:g.content).indexOf(i))&&(++l,c=h.substring(0,v),m=u[i],d=void 0,(f={})["interpolation-punctuation"]=o,3===(f=e.tokenize(m,f)).length&&((d=[1,1]).push.apply(d,s(f[1],e.languages.javascript,"javascript")),f.splice.apply(f,d)),d=new e.Token("interpolation",f,r.alias,m),f=h.substring(v+i.length),m=[],c&&m.push(c),m.push(d),f&&(t(h=[f]),m.push.apply(m,h)),"string"==typeof g?(n.splice.apply(n,[a,1].concat(m)),a+=m.length-1):g.content=m)):(v=g.content,Array.isArray(v)?t(v):t([v]))}}(c),new e.Token(i,c,"language-"+i,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var l={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function u(e){return"string"==typeof e?e:Array.isArray(e)?e.map(u).join(""):u(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in l&&function t(n){for(var r=0,o=n.length;r<o;r++){var a,i,s,l=n[r];"string"!=typeof l&&(a=l.content,Array.isArray(a)?"template-string"===l.type?(l=a[1],3===a.length&&"string"!=typeof l&&"embedded-code"===l.type&&(i=u(l),l=l.alias,l=Array.isArray(l)?l[0]:l,s=e.languages[l])&&(a[1]=c(i,s,l))):t(a):"string"!=typeof a&&t([a]))}}(t.tokens)}))}(j),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(j),function(e){var t=e.languages.javascript,n=/\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})+\}/.source,r="(@(?:arg|argument|param|property)\\s+(?:"+n+"\\s+)?)";e.languages.jsdoc=e.languages.extend("javadoclike",{parameter:{pattern:RegExp(r+/(?:(?!\s)[$\w\xA0-\uFFFF.])+(?=\s|$)/.source),lookbehind:!0,inside:{punctuation:/\./}}}),e.languages.insertBefore("jsdoc","keyword",{"optional-parameter":{pattern:RegExp(r+/\[(?:(?!\s)[$\w\xA0-\uFFFF.])+(?:=[^[\]]+)?\](?=\s|$)/.source),lookbehind:!0,inside:{parameter:{pattern:/(^\[)[$\w\xA0-\uFFFF\.]+/,lookbehind:!0,inside:{punctuation:/\./}},code:{pattern:/(=)[\s\S]*(?=\]$)/,lookbehind:!0,inside:t,alias:"language-javascript"},punctuation:/[=[\]]/}},"class-name":[{pattern:RegExp(/(@(?:augments|class|extends|interface|memberof!?|template|this|typedef)\s+(?:<TYPE>\s+)?)[A-Z]\w*(?:\.[A-Z]\w*)*/.source.replace(/<TYPE>/g,(function(){return n}))),lookbehind:!0,inside:{punctuation:/\./}},{pattern:RegExp("(@[a-z]+\\s+)"+n),lookbehind:!0,inside:{string:t.string,number:t.number,boolean:t.boolean,keyword:e.languages.typescript.keyword,operator:/=>|\.\.\.|[&|?:*]/,punctuation:/[.,;=<>{}()[\]]/}}],example:{pattern:/(@example\s+(?!\s))(?:[^@\s]|\s+(?!\s))+?(?=\s*(?:\*\s*)?(?:@\w|\*\/))/,lookbehind:!0,inside:{code:{pattern:/^([\t ]*(?:\*\s*)?)\S.*$/m,lookbehind:!0,inside:t,alias:"language-javascript"}}}}),e.languages.javadoclike.addSupport("javascript",e.languages.jsdoc)}(j),function(e){e.languages.flow=e.languages.extend("javascript",{}),e.languages.insertBefore("flow","keyword",{type:[{pattern:/\b(?:[Bb]oolean|Function|[Nn]umber|[Ss]tring|[Ss]ymbol|any|mixed|null|void)\b/,alias:"class-name"}]}),e.languages.flow["function-variable"].pattern=/(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=\s*(?:function\b|(?:\([^()]*\)(?:\s*:\s*\w+)?|(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/i,delete e.languages.flow.parameter,e.languages.insertBefore("flow","operator",{"flow-punctuation":{pattern:/\{\||\|\}/,alias:"punctuation"}}),Array.isArray(e.languages.flow.keyword)||(e.languages.flow.keyword=[e.languages.flow.keyword]),e.languages.flow.keyword.unshift({pattern:/(^|[^$]\b)(?:Class|declare|opaque|type)\b(?!\$)/,lookbehind:!0},{pattern:/(^|[^$]\B)\$(?:Diff|Enum|Exact|Keys|ObjMap|PropertyType|Record|Shape|Subtype|Supertype|await)\b(?!\$)/,lookbehind:!0})}(j),j.languages.n4js=j.languages.extend("javascript",{keyword:/\b(?:Array|any|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/}),j.languages.insertBefore("n4js","constant",{annotation:{pattern:/@+\w+/,alias:"operator"}}),j.languages.n4jsd=j.languages.n4js,function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var o=n[r],a=e.languages.javascript[o];o=(a="RegExp"===e.util.type(a)?e.languages.javascript[o]={pattern:a}:a).inside||{};(a.inside=o)["maybe-class-name"]=/^[A-Z][\s\S]*/}}(j),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,o=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function a(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return o})),RegExp(e,t)}function i(t){for(var n=[],r=0;r<t.length;r++){var o=t[r],a=!1;"string"!=typeof o&&("tag"===o.type&&o.content[0]&&"tag"===o.content[0].type?"</"===o.content[0].content[0].content?0<n.length&&n[n.length-1].tagName===s(o.content[0].content[1])&&n.pop():"/>"!==o.content[o.content.length-1].content&&n.push({tagName:s(o.content[0].content[1]),openedBraces:0}):0<n.length&&"punctuation"===o.type&&"{"===o.content?n[n.length-1].openedBraces++:0<n.length&&0<n[n.length-1].openedBraces&&"punctuation"===o.type&&"}"===o.content?n[n.length-1].openedBraces--:a=!0),(a||"string"==typeof o)&&0<n.length&&0===n[n.length-1].openedBraces&&(a=s(o),r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(a+=s(t[r+1]),t.splice(r+1,1)),0<r&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(a=s(t[r-1])+a,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",a,null,a)),o.content&&"string"!=typeof o.content&&i(o.content)}}o=a(o).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=a(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:a(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:a(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var s=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(s).join(""):""};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||i(e.tokens)}))}(j),function(e){var t=e.util.clone(e.languages.typescript);(t=(e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"],e.languages.tsx.tag)).pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+t.pattern.source+")",t.pattern.flags),t.lookbehind=!0}(j),j.languages.swift={comment:{pattern:/(^|[^\\:])(?:\/\/.*|\/\*(?:[^/*]|\/(?!\*)|\*(?!\/)|\/\*(?:[^*]|\*(?!\/))*\*\/)*\*\/)/,lookbehind:!0,greedy:!0},"string-literal":[{pattern:RegExp(/(^|[^"#])/.source+"(?:"+/"(?:\\(?:\((?:[^()]|\([^()]*\))*\)|\r\n|[^(])|[^\\\r\n"])*"/.source+"|"+/"""(?:\\(?:\((?:[^()]|\([^()]*\))*\)|[^(])|[^\\"]|"(?!""))*"""/.source+")"+/(?!["#])/.source),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\\($/,alias:"punctuation"},punctuation:/\\(?=[\r\n])/,string:/[\s\S]+/}},{pattern:RegExp(/(^|[^"#])(#+)/.source+"(?:"+/"(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|\r\n|[^#])|[^\\\r\n])*?"/.source+"|"+/"""(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|[^#])|[^\\])*?"""/.source+")\\2"),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\#+\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\#+\($/,alias:"punctuation"},string:/[\s\S]+/}}],directive:{pattern:RegExp(/#/.source+"(?:"+/(?:elseif|if)\b/.source+"(?:[ \t]*"+/(?:![ \t]*)?(?:\b\w+\b(?:[ \t]*\((?:[^()]|\([^()]*\))*\))?|\((?:[^()]|\([^()]*\))*\))(?:[ \t]*(?:&&|\|\|))?/.source+")+|"+/(?:else|endif)\b/.source+")"),alias:"property",inside:{"directive-name":/^#\w+/,boolean:/\b(?:false|true)\b/,number:/\b\d+(?:\.\d+)*\b/,operator:/!|&&|\|\||[<>]=?/,punctuation:/[(),]/}},literal:{pattern:/#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\b/,alias:"constant"},"other-directive":{pattern:/#\w+\b/,alias:"property"},attribute:{pattern:/@\w+/,alias:"atrule"},"function-definition":{pattern:/(\bfunc\s+)\w+/,lookbehind:!0,alias:"function"},label:{pattern:/\b(break|continue)\s+\w+|\b[a-zA-Z_]\w*(?=\s*:\s*(?:for|repeat|while)\b)/,lookbehind:!0,alias:"important"},keyword:/\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\b/,boolean:/\b(?:false|true)\b/,nil:{pattern:/\bnil\b/,alias:"constant"},"short-argument":/\$\d+\b/,omit:{pattern:/\b_\b/,alias:"keyword"},number:/\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i,"class-name":/\b[A-Z](?:[A-Z_\d]*[a-z]\w*)?\b/,function:/\b[a-z_]\w*(?=\s*\()/i,constant:/\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/,operator:/[-+*/%=!<>&|^~?]+|\.[.\-+*/%=!<>&|^~?]+/,punctuation:/[{}[\]();,.:\\]/},j.languages.swift["string-literal"].forEach((function(e){e.inside.interpolation.inside=j.languages.swift})),function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(j),j.languages.c=j.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),j.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),j.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},j.languages.c.string],char:j.languages.c.char,comment:j.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:j.languages.c}}}}),j.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete j.languages.c.boolean,j.languages.objectivec=j.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete j.languages.objectivec["class-name"],j.languages.objc=j.languages.objectivec,j.languages.reason=j.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),j.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete j.languages.reason.function,function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source,n=0;n<2;n++)t=t.replace(/<self>/g,(function(){return t}));t=t.replace(/<self>/g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(j),j.languages.go=j.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),j.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete j.languages.go["class-name"],function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(j),j.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},j.languages.python["string-interpolation"].inside.interpolation.inside.rest=j.languages.python,j.languages.py=j.languages.python,j.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},j.languages.webmanifest=j.languages.json;((e,t)=>{for(var n in t)f(e,n,{get:t[n],enumerable:!0})})({},{dracula:()=>P,duotoneDark:()=>C,duotoneLight:()=>A,github:()=>T,gruvboxMaterialDark:()=>G,gruvboxMaterialLight:()=>K,jettwaveDark:()=>V,jettwaveLight:()=>W,nightOwl:()=>I,nightOwlLight:()=>N,oceanicNext:()=>D,okaidia:()=>F,oneDark:()=>Q,oneLight:()=>q,palenight:()=>M,shadesOfPurple:()=>B,synthwave84:()=>z,ultramin:()=>$,vsDark:()=>U,vsLight:()=>H});var P={plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},C={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},A={plain:{backgroundColor:"#faf8f5",color:"#728fcb"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#b6ad9a"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#063289"}},{types:["property","function"],style:{color:"#b29762"}},{types:["tag-id","selector","atrule-id"],style:{color:"#2d2006"}},{types:["attr-name"],style:{color:"#896724"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule"],style:{color:"#728fcb"}},{types:["placeholder","variable"],style:{color:"#93abdc"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#896724"}}]},T={plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},I={plain:{color:"#d6deeb",backgroundColor:"#011627"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(99, 119, 119)",fontStyle:"italic"}},{types:["string","url"],style:{color:"rgb(173, 219, 103)"}},{types:["variable"],style:{color:"rgb(214, 222, 235)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation"],style:{color:"rgb(199, 146, 234)"}},{types:["selector","doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(255, 203, 139)"}},{types:["tag","operator","keyword"],style:{color:"rgb(127, 219, 202)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["property"],style:{color:"rgb(128, 203, 196)"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}}]},N={plain:{color:"#403f53",backgroundColor:"#FBFBFB"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(72, 118, 214)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(152, 159, 177)",fontStyle:"italic"}},{types:["string","builtin","char","constant","url"],style:{color:"rgb(72, 118, 214)"}},{types:["variable"],style:{color:"rgb(201, 103, 101)"}},{types:["number"],style:{color:"rgb(170, 9, 130)"}},{types:["punctuation"],style:{color:"rgb(153, 76, 195)"}},{types:["function","selector","doctype"],style:{color:"rgb(153, 76, 195)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(17, 17, 17)"}},{types:["tag"],style:{color:"rgb(153, 76, 195)"}},{types:["operator","property","keyword","namespace"],style:{color:"rgb(12, 150, 155)"}},{types:["boolean"],style:{color:"rgb(188, 84, 84)"}}]},L="#c5a5c5",R="#8dc891",D={plain:{backgroundColor:"#282c34",color:"#ffffff"},styles:[{types:["attr-name"],style:{color:L}},{types:["attr-value"],style:{color:R}},{types:["comment","block-comment","prolog","doctype","cdata","shebang"],style:{color:"#999999"}},{types:["property","number","function-name","constant","symbol","deleted"],style:{color:"#5a9bcf"}},{types:["boolean"],style:{color:"#ff8b50"}},{types:["tag"],style:{color:"#fc929e"}},{types:["string"],style:{color:R}},{types:["punctuation"],style:{color:R}},{types:["selector","char","builtin","inserted"],style:{color:"#D8DEE9"}},{types:["function"],style:{color:"#79b6f2"}},{types:["operator","entity","url","variable"],style:{color:"#d7deea"}},{types:["keyword"],style:{color:L}},{types:["atrule","class-name"],style:{color:"#FAC863"}},{types:["important"],style:{fontWeight:"400"}},{types:["bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}}]},F={plain:{color:"#f8f8f2",backgroundColor:"#272822"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"#f92672",fontStyle:"italic"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"#8292a2",fontStyle:"italic"}},{types:["string","url"],style:{color:"#a6e22e"}},{types:["variable"],style:{color:"#f8f8f2"}},{types:["number"],style:{color:"#ae81ff"}},{types:["builtin","char","constant","function","class-name"],style:{color:"#e6db74"}},{types:["punctuation"],style:{color:"#f8f8f2"}},{types:["selector","doctype"],style:{color:"#a6e22e",fontStyle:"italic"}},{types:["tag","operator","keyword"],style:{color:"#66d9ef"}},{types:["boolean"],style:{color:"#ae81ff"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)",opacity:.7}},{types:["tag","property"],style:{color:"#f92672"}},{types:["attr-name"],style:{color:"#a6e22e !important"}},{types:["doctype"],style:{color:"#8292a2"}},{types:["rule"],style:{color:"#e6db74"}}]},M={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},B={plain:{color:"#9EFEFF",backgroundColor:"#2D2A55"},styles:[{types:["changed"],style:{color:"rgb(255, 238, 128)"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)"}},{types:["comment"],style:{color:"rgb(179, 98, 255)",fontStyle:"italic"}},{types:["punctuation"],style:{color:"rgb(255, 255, 255)"}},{types:["constant"],style:{color:"rgb(255, 98, 140)"}},{types:["string","url"],style:{color:"rgb(165, 255, 144)"}},{types:["variable"],style:{color:"rgb(255, 238, 128)"}},{types:["number","boolean"],style:{color:"rgb(255, 98, 140)"}},{types:["attr-name"],style:{color:"rgb(255, 180, 84)"}},{types:["keyword","operator","property","namespace","tag","selector","doctype"],style:{color:"rgb(255, 157, 0)"}},{types:["builtin","char","constant","function","class-name"],style:{color:"rgb(250, 208, 0)"}}]},z={plain:{backgroundColor:"linear-gradient(to bottom, #2a2139 75%, #34294f)",backgroundImage:"#34294f",color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"},styles:[{types:["comment","block-comment","prolog","doctype","cdata"],style:{color:"#495495",fontStyle:"italic"}},{types:["punctuation"],style:{color:"#ccc"}},{types:["tag","attr-name","namespace","number","unit","hexcode","deleted"],style:{color:"#e2777a"}},{types:["property","selector"],style:{color:"#72f1b8",textShadow:"0 0 2px #100c0f, 0 0 10px #257c5575, 0 0 35px #21272475"}},{types:["function-name"],style:{color:"#6196cc"}},{types:["boolean","selector-id","function"],style:{color:"#fdfdfd",textShadow:"0 0 2px #001716, 0 0 3px #03edf975, 0 0 5px #03edf975, 0 0 8px #03edf975"}},{types:["class-name","maybe-class-name","builtin"],style:{color:"#fff5f6",textShadow:"0 0 2px #000, 0 0 10px #fc1f2c75, 0 0 5px #fc1f2c75, 0 0 25px #fc1f2c75"}},{types:["constant","symbol"],style:{color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"}},{types:["important","atrule","keyword","selector-class"],style:{color:"#f4eee4",textShadow:"0 0 2px #393a33, 0 0 8px #f39f0575, 0 0 2px #f39f0575"}},{types:["string","char","attr-value","regex","variable"],style:{color:"#f87c32"}},{types:["parameter"],style:{fontStyle:"italic"}},{types:["entity","url"],style:{color:"#67cdcc"}},{types:["operator"],style:{color:"ffffffee"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["entity"],style:{cursor:"help"}},{types:["inserted"],style:{color:"green"}}]},$={plain:{color:"#282a2e",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(197, 200, 198)"}},{types:["string","number","builtin","variable"],style:{color:"rgb(150, 152, 150)"}},{types:["class-name","function","tag","attr-name"],style:{color:"rgb(40, 42, 46)"}}]},U={plain:{color:"#9CDCFE",backgroundColor:"#1E1E1E"},styles:[{types:["prolog"],style:{color:"rgb(0, 0, 128)"}},{types:["comment"],style:{color:"rgb(106, 153, 85)"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"rgb(86, 156, 214)"}},{types:["number","inserted"],style:{color:"rgb(181, 206, 168)"}},{types:["constant"],style:{color:"rgb(100, 102, 149)"}},{types:["attr-name","variable"],style:{color:"rgb(156, 220, 254)"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"rgb(206, 145, 120)"}},{types:["selector"],style:{color:"rgb(215, 186, 125)"}},{types:["tag"],style:{color:"rgb(78, 201, 176)"}},{types:["tag"],languages:["markup"],style:{color:"rgb(86, 156, 214)"}},{types:["punctuation","operator"],style:{color:"rgb(212, 212, 212)"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"rgb(220, 220, 170)"}},{types:["class-name"],style:{color:"rgb(78, 201, 176)"}},{types:["char"],style:{color:"rgb(209, 105, 105)"}}]},H={plain:{color:"#000000",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(0, 128, 0)"}},{types:["builtin"],style:{color:"rgb(0, 112, 193)"}},{types:["number","variable","inserted"],style:{color:"rgb(9, 134, 88)"}},{types:["operator"],style:{color:"rgb(0, 0, 0)"}},{types:["constant","char"],style:{color:"rgb(129, 31, 63)"}},{types:["tag"],style:{color:"rgb(128, 0, 0)"}},{types:["attr-name"],style:{color:"rgb(255, 0, 0)"}},{types:["deleted","string"],style:{color:"rgb(163, 21, 21)"}},{types:["changed","punctuation"],style:{color:"rgb(4, 81, 165)"}},{types:["function","keyword"],style:{color:"rgb(0, 0, 255)"}},{types:["class-name"],style:{color:"rgb(38, 127, 153)"}}]},V={plain:{color:"#f8fafc",backgroundColor:"#011627"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#569CD6"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#f8fafc"}},{types:["attr-name","variable"],style:{color:"#9CDCFE"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#cbd5e1"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#D4D4D4"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#7dd3fc"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},W={plain:{color:"#0f172a",backgroundColor:"#f1f5f9"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#0c4a6e"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#0f172a"}},{types:["attr-name","variable"],style:{color:"#0c4a6e"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#64748b"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#475569"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#0e7490"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},Q={plain:{backgroundColor:"hsl(220, 13%, 18%)",color:"hsl(220, 14%, 71%)",textShadow:"0 1px rgba(0, 0, 0, 0.3)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(220, 10%, 40%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(220, 14%, 71%)"}},{types:["attr-name","class-name","maybe-class-name","boolean","constant","number","atrule"],style:{color:"hsl(29, 54%, 61%)"}},{types:["keyword"],style:{color:"hsl(286, 60%, 67%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(355, 65%, 65%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value"],style:{color:"hsl(95, 38%, 62%)"}},{types:["variable","operator","function"],style:{color:"hsl(207, 82%, 66%)"}},{types:["url"],style:{color:"hsl(187, 47%, 55%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(220, 14%, 71%)"}}]},q={plain:{backgroundColor:"hsl(230, 1%, 98%)",color:"hsl(230, 8%, 24%)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(230, 4%, 64%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(230, 8%, 24%)"}},{types:["attr-name","class-name","boolean","constant","number","atrule"],style:{color:"hsl(35, 99%, 36%)"}},{types:["keyword"],style:{color:"hsl(301, 63%, 40%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(5, 74%, 59%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value","punctuation"],style:{color:"hsl(119, 34%, 47%)"}},{types:["variable","operator","function"],style:{color:"hsl(221, 87%, 60%)"}},{types:["url"],style:{color:"hsl(198, 99%, 37%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(230, 8%, 24%)"}}]},G={plain:{color:"#ebdbb2",backgroundColor:"#292828"},styles:[{types:["imports","class-name","maybe-class-name","constant","doctype","builtin","function"],style:{color:"#d8a657"}},{types:["property-access"],style:{color:"#7daea3"}},{types:["tag"],style:{color:"#e78a4e"}},{types:["attr-name","char","url","regex"],style:{color:"#a9b665"}},{types:["attr-value","string"],style:{color:"#89b482"}},{types:["comment","prolog","cdata","operator","inserted"],style:{color:"#a89984"}},{types:["delimiter","boolean","keyword","selector","important","atrule","property","variable","deleted"],style:{color:"#ea6962"}},{types:["entity","number","symbol"],style:{color:"#d3869b"}}]},K={plain:{color:"#654735",backgroundColor:"#f9f5d7"},styles:[{types:["delimiter","boolean","keyword","selector","important","atrule","property","variable","deleted"],style:{color:"#af2528"}},{types:["imports","class-name","maybe-class-name","constant","doctype","builtin"],style:{color:"#b4730e"}},{types:["string","attr-value"],style:{color:"#477a5b"}},{types:["property-access"],style:{color:"#266b79"}},{types:["function","attr-name","char","url"],style:{color:"#72761e"}},{types:["tag"],style:{color:"#b94c07"}},{types:["comment","prolog","cdata","operator","inserted"],style:{color:"#a89984"}},{types:["entity","number","symbol"],style:{color:"#924f79"}}]},Y=(e,t)=>{const{plain:n}=e,r=e.styles.reduce(((e,n)=>{const{languages:r,style:o}=n;return r&&!r.includes(t)||n.types.forEach((t=>{const n=S(S({},e[t]),o);e[t]=n})),e}),{});return r.root=n,r.plain=k(S({},n),{backgroundColor:void 0}),r},Z=/\r\n|\r|\n/,X=e=>{0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},J=(e,t)=>{const n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)},ee=e=>{const t=[[]],n=[e],r=[0],o=[e.length];let a=0,i=0,s=[];const c=[s];for(;i>-1;){for(;(a=r[i]++)<o[i];){let e,l=t[i];const u=n[i][a];if("string"==typeof u?(l=i>0?l:["plain"],e=u):(l=J(l,u.type),u.alias&&(l=J(l,u.alias)),e=u.content),"string"!=typeof e){i++,t.push(l),n.push(e),r.push(0),o.push(e.length);continue}const p=e.split(Z),d=p.length;s.push({types:l,content:p[0]});for(let t=1;t<d;t++)X(s),c.push(s=[]),s.push({types:l,content:p[t]})}i--,t.pop(),n.pop(),r.pop(),o.pop()}return X(s),c},te=({children:e,language:t,code:n,theme:r,prism:o})=>{const a=t.toLowerCase(),i=((e,t)=>{const[n,r]=(0,u.useState)(Y(t,e)),o=(0,u.useRef)(),a=(0,u.useRef)();return(0,u.useEffect)((()=>{t===o.current&&e===a.current||(o.current=t,a.current=e,r(Y(t,e)))}),[e,t]),n})(a,r),s=(e=>(0,u.useCallback)((t=>{var n=t,{className:r,style:o,line:a}=n,i=E(n,["className","style","line"]);const s=k(S({},i),{className:(0,p.A)("token-line",r)});return"object"==typeof e&&"plain"in e&&(s.style=e.plain),"object"==typeof o&&(s.style=S(S({},s.style||{}),o)),s}),[e]))(i),c=(e=>{const t=(0,u.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,u.useCallback)((e=>{var n=e,{token:r,className:o,style:a}=n,i=E(n,["token","className","style"]);const s=k(S({},i),{className:(0,p.A)("token",...r.types,o),children:r.content,style:t(r)});return null!=a&&(s.style=S(S({},s.style||{}),a)),s}),[t])})(i),l=(({prism:e,code:t,grammar:n,language:r})=>{const o=(0,u.useRef)(e);return(0,u.useMemo)((()=>{if(null==n)return ee([t]);const e={code:t,grammar:n,language:r,tokens:[]};return o.current.hooks.run("before-tokenize",e),e.tokens=o.current.tokenize(t,n),o.current.hooks.run("after-tokenize",e),ee(e.tokens)}),[t,n,r])})({prism:o,language:a,code:n,grammar:o.languages[a]});return e({tokens:l,className:`prism-code language-${a}`,style:null!=i?i.root:{},getLineProps:s,getTokenProps:c})},ne=e=>(0,u.createElement)(te,k(S({},e),{prism:e.prism||j,theme:e.theme||U,code:e.code,language:e.language}))},11561:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=!0,o="Invariant failed";function a(e,t){if(!e){if(r)throw new Error(o);var n="function"==typeof t?t():t,a=n?"".concat(o,": ").concat(n):o;throw new Error(a)}}},31635:(e,t,n)=>{"use strict";n.r(t),n.d(t,{__addDisposableResource:()=>R,__assign:()=>a,__asyncDelegator:()=>E,__asyncGenerator:()=>k,__asyncValues:()=>O,__await:()=>S,__awaiter:()=>m,__classPrivateFieldGet:()=>I,__classPrivateFieldIn:()=>L,__classPrivateFieldSet:()=>N,__createBinding:()=>v,__decorate:()=>s,__disposeResources:()=>F,__esDecorate:()=>l,__exportStar:()=>g,__extends:()=>o,__generator:()=>h,__importDefault:()=>T,__importStar:()=>A,__makeTemplateObject:()=>j,__metadata:()=>f,__param:()=>c,__propKey:()=>p,__read:()=>y,__rest:()=>i,__rewriteRelativeImportExtension:()=>M,__runInitializers:()=>u,__setFunctionName:()=>d,__spread:()=>w,__spreadArray:()=>x,__spreadArrays:()=>_,__values:()=>b,default:()=>B});var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},r(e,t)};function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return a=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var o in t=arguments[n])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e},a.apply(this,arguments)};function i(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(r=Object.getOwnPropertySymbols(e);o<r.length;o++)t.indexOf(r[o])<0&&Object.prototype.propertyIsEnumerable.call(e,r[o])&&(n[r[o]]=e[r[o]])}return n}function s(e,t,n,r){var o,a=arguments.length,i=a<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(i=(a<3?o(i):a>3?o(t,n,i):o(t,n))||i);return a>3&&i&&Object.defineProperty(t,n,i),i}function c(e,t){return function(n,r){t(n,r,e)}}function l(e,t,n,r,o,a){function i(e){if(void 0!==e&&"function"!=typeof e)throw new TypeError("Function expected");return e}for(var s,c=r.kind,l="getter"===c?"get":"setter"===c?"set":"value",u=!t&&e?r.static?e:e.prototype:null,p=t||(u?Object.getOwnPropertyDescriptor(u,r.name):{}),d=!1,f=n.length-1;f>=0;f--){var m={};for(var h in r)m[h]="access"===h?{}:r[h];for(var h in r.access)m.access[h]=r.access[h];m.addInitializer=function(e){if(d)throw new TypeError("Cannot add initializers after decoration has completed");a.push(i(e||null))};var v=(0,n[f])("accessor"===c?{get:p.get,set:p.set}:p[l],m);if("accessor"===c){if(void 0===v)continue;if(null===v||"object"!=typeof v)throw new TypeError("Object expected");(s=i(v.get))&&(p.get=s),(s=i(v.set))&&(p.set=s),(s=i(v.init))&&o.unshift(s)}else(s=i(v))&&("field"===c?o.unshift(s):p[l]=s)}u&&Object.defineProperty(u,r.name,p),d=!0}function u(e,t,n){for(var r=arguments.length>2,o=0;o<t.length;o++)n=r?t[o].call(e,n):t[o].call(e);return r?n:void 0}function p(e){return"symbol"==typeof e?e:"".concat(e)}function d(e,t,n){return"symbol"==typeof t&&(t=t.description?"[".concat(t.description,"]"):""),Object.defineProperty(e,"name",{configurable:!0,value:n?"".concat(n," ",t):t})}function f(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function m(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{c(r.next(e))}catch(t){a(t)}}function s(e){try{c(r.throw(e))}catch(t){a(t)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,s)}c((r=r.apply(e,t||[])).next())}))}function h(e,t){var n,r,o,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return i.next=s(0),i.throw=s(1),i.return=s(2),"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(s){return function(c){return function(s){if(n)throw new TypeError("Generator is already executing.");for(;i&&(i=0,s[0]&&(a=0)),a;)try{if(n=1,r&&(o=2&s[0]?r.return:s[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,s[1])).done)return o;switch(r=0,o&&(s=[2&s[0],o.value]),s[0]){case 0:case 1:o=s;break;case 4:return a.label++,{value:s[1],done:!1};case 5:a.label++,r=s[1],s=[0];continue;case 7:s=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==s[0]&&2!==s[0])){a=0;continue}if(3===s[0]&&(!o||s[1]>o[0]&&s[1]<o[3])){a.label=s[1];break}if(6===s[0]&&a.label<o[1]){a.label=o[1],o=s;break}if(o&&a.label<o[2]){a.label=o[2],a.ops.push(s);break}o[2]&&a.ops.pop(),a.trys.pop();continue}s=t.call(e,a)}catch(c){s=[6,c],r=0}finally{n=o=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([s,c])}}}var v=Object.create?function(e,t,n,r){void 0===r&&(r=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,o)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]};function g(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||v(t,e,n)}function b(e){var t="function"==typeof Symbol&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function y(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,a=n.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(r=a.next()).done;)i.push(r.value)}catch(s){o={error:s}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}return i}function w(){for(var e=[],t=0;t<arguments.length;t++)e=e.concat(y(arguments[t]));return e}function _(){for(var e=0,t=0,n=arguments.length;t<n;t++)e+=arguments[t].length;var r=Array(e),o=0;for(t=0;t<n;t++)for(var a=arguments[t],i=0,s=a.length;i<s;i++,o++)r[o]=a[i];return r}function x(e,t,n){if(n||2===arguments.length)for(var r,o=0,a=t.length;o<a;o++)!r&&o in t||(r||(r=Array.prototype.slice.call(t,0,o)),r[o]=t[o]);return e.concat(r||Array.prototype.slice.call(t))}function S(e){return this instanceof S?(this.v=e,this):new S(e)}function k(e,t,n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,o=n.apply(e,t||[]),a=[];return r=Object.create(("function"==typeof AsyncIterator?AsyncIterator:Object).prototype),i("next"),i("throw"),i("return",(function(e){return function(t){return Promise.resolve(t).then(e,l)}})),r[Symbol.asyncIterator]=function(){return this},r;function i(e,t){o[e]&&(r[e]=function(t){return new Promise((function(n,r){a.push([e,t,n,r])>1||s(e,t)}))},t&&(r[e]=t(r[e])))}function s(e,t){try{(n=o[e](t)).value instanceof S?Promise.resolve(n.value.v).then(c,l):u(a[0][2],n)}catch(r){u(a[0][3],r)}var n}function c(e){s("next",e)}function l(e){s("throw",e)}function u(e,t){e(t),a.shift(),a.length&&s(a[0][0],a[0][1])}}function E(e){var t,n;return t={},r("next"),r("throw",(function(e){throw e})),r("return"),t[Symbol.iterator]=function(){return this},t;function r(r,o){t[r]=e[r]?function(t){return(n=!n)?{value:S(e[r](t)),done:!1}:o?o(t):t}:o}}function O(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=b(e),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,o){(function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)})(r,o,(t=e[n](t)).done,t.value)}))}}}function j(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e}var P=Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t},C=function(e){return C=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},C(e)};function A(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=C(e),r=0;r<n.length;r++)"default"!==n[r]&&v(t,e,n[r]);return P(t,e),t}function T(e){return e&&e.__esModule?e:{default:e}}function I(e,t,n,r){if("a"===n&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?r:"a"===n?r.call(e):r?r.value:t.get(e)}function N(e,t,n,r,o){if("m"===r)throw new TypeError("Private method is not writable");if("a"===r&&!o)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===r?o.call(e,n):o?o.value=n:t.set(e,n),n}function L(e,t){if(null===t||"object"!=typeof t&&"function"!=typeof t)throw new TypeError("Cannot use 'in' operator on non-object");return"function"==typeof e?t===e:e.has(t)}function R(e,t,n){if(null!=t){if("object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object expected.");var r,o;if(n){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");r=t[Symbol.asyncDispose]}if(void 0===r){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");r=t[Symbol.dispose],n&&(o=r)}if("function"!=typeof r)throw new TypeError("Object not disposable.");o&&(r=function(){try{o.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:r,async:n})}else n&&e.stack.push({async:!0});return t}var D="function"==typeof SuppressedError?SuppressedError:function(e,t,n){var r=new Error(n);return r.name="SuppressedError",r.error=e,r.suppressed=t,r};function F(e){function t(t){e.error=e.hasError?new D(t,e.error,"An error was suppressed during disposal."):t,e.hasError=!0}var n,r=0;return function o(){for(;n=e.stack.pop();)try{if(!n.async&&1===r)return r=0,e.stack.push(n),Promise.resolve().then(o);if(n.dispose){var a=n.dispose.call(n.value);if(n.async)return r|=2,Promise.resolve(a).then(o,(function(e){return t(e),o()}))}else r|=1}catch(i){t(i)}if(1===r)return e.hasError?Promise.reject(e.error):Promise.resolve();if(e.hasError)throw e.error}()}function M(e,t){return"string"==typeof e&&/^\.\.?\//.test(e)?e.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i,(function(e,n,r,o,a){return n?t?".jsx":".js":!r||o&&a?r+o+"."+a.toLowerCase()+"js":e})):e}const B={__extends:o,__assign:a,__rest:i,__decorate:s,__param:c,__esDecorate:l,__runInitializers:u,__propKey:p,__setFunctionName:d,__metadata:f,__awaiter:m,__generator:h,__createBinding:v,__exportStar:g,__values:b,__read:y,__spread:w,__spreadArrays:_,__spreadArray:x,__await:S,__asyncGenerator:k,__asyncDelegator:E,__asyncValues:O,__makeTemplateObject:j,__importStar:A,__importDefault:T,__classPrivateFieldGet:I,__classPrivateFieldSet:N,__classPrivateFieldIn:L,__addDisposableResource:R,__disposeResources:F,__rewriteRelativeImportExtension:M}},22654:e=>{"use strict";e.exports=JSON.parse('{"cmfcmf/d-s-l.searchBar.placeholder":"Search...","cmfcmf/d-s-l.searchBar.noResults":"No results found.","cmfcmf/d-s-l.searchBar.clearButtonTitle":"Clear","cmfcmf/d-s-l.searchBar.detachedCancelButtonText":"Cancel","cmfcmf/d-s-l.searchBar.submitButtonTitle":"Submit"}')},84054:e=>{"use strict";e.exports=JSON.parse('{"/contrast/pr-preview/pr-1071/-b32":{"__comp":"5e95c892","__context":{"plugin":"aba21aa0"}},"/contrast/pr-preview/pr-1071/0.5-207":{"__comp":"a7bd4aaa","__props":"2d1295a3"},"/contrast/pr-preview/pr-1071/0.5-b4d":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/0.5-f85":{"__comp":"17896441","content":"f47dd6e5"},"/contrast/pr-preview/pr-1071/0.5/architecture-921":{"__comp":"17896441","content":"9d9e06f4"},"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator-f7c":{"__comp":"17896441","content":"64d58a39"},"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware-eda":{"__comp":"17896441","content":"04102e85"},"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest-0e1":{"__comp":"17896441","content":"9397123b"},"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm-705":{"__comp":"17896441","content":"4f453872"},"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies-2e5":{"__comp":"17896441","content":"20382dd7"},"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki-471":{"__comp":"17896441","content":"3e02a241"},"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli-7b3":{"__comp":"17896441","content":"966b9f47"},"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator-9a4":{"__comp":"17896441","content":"e446d98f"},"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container-f12":{"__comp":"17896441","content":"d580a1fd"},"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers-43c":{"__comp":"17896441","content":"15b9bf06"},"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys-1bc":{"__comp":"17896441","content":"d2630e76"},"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar-cab":{"__comp":"17896441","content":"b3916dd3"},"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers-747":{"__comp":"17896441","content":"8dca39c2"},"/contrast/pr-preview/pr-1071/0.5/basics/features-b08":{"__comp":"17896441","content":"6903d0da"},"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits-a41":{"__comp":"17896441","content":"ee8b52db"},"/contrast/pr-preview/pr-1071/0.5/category/attestation-aba":{"__comp":"14eb3368","__props":"9c6eeb97"},"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities-1a6":{"__comp":"14eb3368","__props":"5f62f97d"},"/contrast/pr-preview/pr-1071/0.5/category/components-4d0":{"__comp":"14eb3368","__props":"2cdf8d95"},"/contrast/pr-preview/pr-1071/0.5/category/network-encryption-166":{"__comp":"14eb3368","__props":"200ecf61"},"/contrast/pr-preview/pr-1071/0.5/deployment-fbd":{"__comp":"17896441","content":"69ec948c"},"/contrast/pr-preview/pr-1071/0.5/examples-98d":{"__comp":"17896441","content":"018595b3"},"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto-ed2":{"__comp":"17896441","content":"3d9be0cc"},"/contrast/pr-preview/pr-1071/0.5/getting-started-5bc":{"__comp":"17896441","content":"baef5027"},"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup-16e":{"__comp":"17896441","content":"3a77bb3e"},"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps-989":{"__comp":"17896441","content":"327db732"},"/contrast/pr-preview/pr-1071/0.5/getting-started/install-6d3":{"__comp":"17896441","content":"a161c24f"},"/contrast/pr-preview/pr-1071/0.6-576":{"__comp":"a7bd4aaa","__props":"c3f66d9e"},"/contrast/pr-preview/pr-1071/0.6-f94":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/0.6-84d":{"__comp":"17896441","content":"f593d43a"},"/contrast/pr-preview/pr-1071/0.6/about-6f7":{"__comp":"17896441","content":"207bb774"},"/contrast/pr-preview/pr-1071/0.6/about/telemetry-e96":{"__comp":"17896441","content":"27d05faa"},"/contrast/pr-preview/pr-1071/0.6/architecture-75a":{"__comp":"17896441","content":"75100f0d"},"/contrast/pr-preview/pr-1071/0.6/architecture/attestation-b31":{"__comp":"17896441","content":"e1e441c9"},"/contrast/pr-preview/pr-1071/0.6/architecture/certificates-fb2":{"__comp":"17896441","content":"c09e49b9"},"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers-71e":{"__comp":"17896441","content":"50474e10"},"/contrast/pr-preview/pr-1071/0.6/basics/features-360":{"__comp":"17896441","content":"dfd9c366"},"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits-044":{"__comp":"17896441","content":"0c24bc66"},"/contrast/pr-preview/pr-1071/0.6/components-d3d":{"__comp":"17896441","content":"45c98560"},"/contrast/pr-preview/pr-1071/0.6/components/policies-0f5":{"__comp":"17896441","content":"567e04ee"},"/contrast/pr-preview/pr-1071/0.6/components/runtime-6ac":{"__comp":"17896441","content":"90af0d0d"},"/contrast/pr-preview/pr-1071/0.6/components/service-mesh-831":{"__comp":"17896441","content":"54c6367b"},"/contrast/pr-preview/pr-1071/0.6/deployment-9df":{"__comp":"17896441","content":"75d659e1"},"/contrast/pr-preview/pr-1071/0.6/examples-694":{"__comp":"17896441","content":"cdb2b1a5"},"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto-b43":{"__comp":"17896441","content":"21d7c4d4"},"/contrast/pr-preview/pr-1071/0.6/getting-started-745":{"__comp":"17896441","content":"c1fac065"},"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup-e61":{"__comp":"17896441","content":"fbad2ec0"},"/contrast/pr-preview/pr-1071/0.6/getting-started/install-57e":{"__comp":"17896441","content":"1c9b88ee"},"/contrast/pr-preview/pr-1071/0.6/known-limitations-bc4":{"__comp":"17896441","content":"6478b99f"},"/contrast/pr-preview/pr-1071/0.7-6ea":{"__comp":"a7bd4aaa","__props":"84cf2b87"},"/contrast/pr-preview/pr-1071/0.7-5f7":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/0.7-1e7":{"__comp":"17896441","content":"9a99019d"},"/contrast/pr-preview/pr-1071/0.7/about-c2b":{"__comp":"17896441","content":"39db4684"},"/contrast/pr-preview/pr-1071/0.7/about/telemetry-cb9":{"__comp":"17896441","content":"f31967d8"},"/contrast/pr-preview/pr-1071/0.7/architecture-439":{"__comp":"17896441","content":"aa0f7abf"},"/contrast/pr-preview/pr-1071/0.7/architecture/attestation-f94":{"__comp":"17896441","content":"ab09c42c"},"/contrast/pr-preview/pr-1071/0.7/architecture/certificates-f88":{"__comp":"17896441","content":"e277c26a"},"/contrast/pr-preview/pr-1071/0.7/architecture/observability-329":{"__comp":"17896441","content":"7edb0f0d"},"/contrast/pr-preview/pr-1071/0.7/basics/confidential-containers-7b6":{"__comp":"17896441","content":"20e0cfa9"},"/contrast/pr-preview/pr-1071/0.7/basics/features-de3":{"__comp":"17896441","content":"173fd1a8"},"/contrast/pr-preview/pr-1071/0.7/basics/security-benefits-dd3":{"__comp":"17896441","content":"bced0f3c"},"/contrast/pr-preview/pr-1071/0.7/components-2e0":{"__comp":"17896441","content":"abfbdc79"},"/contrast/pr-preview/pr-1071/0.7/components/policies-bcf":{"__comp":"17896441","content":"06eada7a"},"/contrast/pr-preview/pr-1071/0.7/components/runtime-dff":{"__comp":"17896441","content":"8c9a8791"},"/contrast/pr-preview/pr-1071/0.7/components/service-mesh-3b8":{"__comp":"17896441","content":"2dbe31cc"},"/contrast/pr-preview/pr-1071/0.7/deployment-3f6":{"__comp":"17896441","content":"de615ffd"},"/contrast/pr-preview/pr-1071/0.7/examples-69d":{"__comp":"17896441","content":"896da145"},"/contrast/pr-preview/pr-1071/0.7/examples/emojivoto-f59":{"__comp":"17896441","content":"7680d80e"},"/contrast/pr-preview/pr-1071/0.7/features-limitations-56e":{"__comp":"17896441","content":"e2b3b970"},"/contrast/pr-preview/pr-1071/0.7/getting-started-25a":{"__comp":"17896441","content":"5eab7755"},"/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setup-437":{"__comp":"17896441","content":"8132774f"},"/contrast/pr-preview/pr-1071/0.7/getting-started/install-308":{"__comp":"17896441","content":"bf823012"},"/contrast/pr-preview/pr-1071/0.8-763":{"__comp":"a7bd4aaa","__props":"1de90583"},"/contrast/pr-preview/pr-1071/0.8-f5d":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/0.8-c01":{"__comp":"17896441","content":"098bf236"},"/contrast/pr-preview/pr-1071/0.8/about/telemetry-273":{"__comp":"17896441","content":"ac3e6feb"},"/contrast/pr-preview/pr-1071/0.8/architecture/attestation-e5c":{"__comp":"17896441","content":"14a9ce33"},"/contrast/pr-preview/pr-1071/0.8/architecture/certificates-5be":{"__comp":"17896441","content":"aafa6b90"},"/contrast/pr-preview/pr-1071/0.8/architecture/observability-e76":{"__comp":"17896441","content":"6a46f748"},"/contrast/pr-preview/pr-1071/0.8/architecture/secrets-00c":{"__comp":"17896441","content":"a71cbd8f"},"/contrast/pr-preview/pr-1071/0.8/basics/confidential-containers-7ad":{"__comp":"17896441","content":"0a7a212e"},"/contrast/pr-preview/pr-1071/0.8/basics/features-bd0":{"__comp":"17896441","content":"7d1602ac"},"/contrast/pr-preview/pr-1071/0.8/basics/security-benefits-3e5":{"__comp":"17896441","content":"98367cce"},"/contrast/pr-preview/pr-1071/0.8/components/overview-087":{"__comp":"17896441","content":"9ce1fd56"},"/contrast/pr-preview/pr-1071/0.8/components/policies-798":{"__comp":"17896441","content":"ae6c0c68"},"/contrast/pr-preview/pr-1071/0.8/components/runtime-a8e":{"__comp":"17896441","content":"9ccb1fc6"},"/contrast/pr-preview/pr-1071/0.8/components/service-mesh-225":{"__comp":"17896441","content":"790f17e8"},"/contrast/pr-preview/pr-1071/0.8/deployment-c4d":{"__comp":"17896441","content":"a66d714b"},"/contrast/pr-preview/pr-1071/0.8/examples/emojivoto-141":{"__comp":"17896441","content":"a0a4ec6e"},"/contrast/pr-preview/pr-1071/0.8/features-limitations-355":{"__comp":"17896441","content":"d1a11e04"},"/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setup-cd2":{"__comp":"17896441","content":"ba2406d8"},"/contrast/pr-preview/pr-1071/0.8/getting-started/install-7bf":{"__comp":"17896441","content":"6fc50b39"},"/contrast/pr-preview/pr-1071/0.8/troubleshooting-094":{"__comp":"17896441","content":"250ffcdd"},"/contrast/pr-preview/pr-1071/0.9-a1e":{"__comp":"a7bd4aaa","__props":"9230b32a"},"/contrast/pr-preview/pr-1071/0.9-4d3":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/0.9-172":{"__comp":"17896441","content":"44b49990"},"/contrast/pr-preview/pr-1071/0.9/about/telemetry-bee":{"__comp":"17896441","content":"7f3f1ff7"},"/contrast/pr-preview/pr-1071/0.9/architecture/attestation-3df":{"__comp":"17896441","content":"2e82b444"},"/contrast/pr-preview/pr-1071/0.9/architecture/certificates-b26":{"__comp":"17896441","content":"fbcf0d59"},"/contrast/pr-preview/pr-1071/0.9/architecture/observability-6b0":{"__comp":"17896441","content":"078f57bf"},"/contrast/pr-preview/pr-1071/0.9/architecture/secrets-7ca":{"__comp":"17896441","content":"26742c3b"},"/contrast/pr-preview/pr-1071/0.9/basics/confidential-containers-5b0":{"__comp":"17896441","content":"e55aefba"},"/contrast/pr-preview/pr-1071/0.9/basics/features-345":{"__comp":"17896441","content":"6100b425"},"/contrast/pr-preview/pr-1071/0.9/basics/security-benefits-f8f":{"__comp":"17896441","content":"327e592d"},"/contrast/pr-preview/pr-1071/0.9/components/overview-e5b":{"__comp":"17896441","content":"06354bbe"},"/contrast/pr-preview/pr-1071/0.9/components/policies-630":{"__comp":"17896441","content":"c7462af2"},"/contrast/pr-preview/pr-1071/0.9/components/runtime-242":{"__comp":"17896441","content":"6009a9aa"},"/contrast/pr-preview/pr-1071/0.9/components/service-mesh-02e":{"__comp":"17896441","content":"c3a9f66a"},"/contrast/pr-preview/pr-1071/0.9/deployment-002":{"__comp":"17896441","content":"3683601e"},"/contrast/pr-preview/pr-1071/0.9/examples/emojivoto-103":{"__comp":"17896441","content":"9a28f5c4"},"/contrast/pr-preview/pr-1071/0.9/features-limitations-896":{"__comp":"17896441","content":"0ba7602a"},"/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setup-011":{"__comp":"17896441","content":"f36abd57"},"/contrast/pr-preview/pr-1071/0.9/getting-started/install-e1a":{"__comp":"17896441","content":"dacf14a0"},"/contrast/pr-preview/pr-1071/0.9/troubleshooting-537":{"__comp":"17896441","content":"41b31679"},"/contrast/pr-preview/pr-1071/1.0-2d1":{"__comp":"a7bd4aaa","__props":"46157656"},"/contrast/pr-preview/pr-1071/1.0-d58":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/1.0-186":{"__comp":"17896441","content":"7bd8db71"},"/contrast/pr-preview/pr-1071/1.0/about/telemetry-99b":{"__comp":"17896441","content":"4ce6baab"},"/contrast/pr-preview/pr-1071/1.0/architecture/attestation-a02":{"__comp":"17896441","content":"bd625abb"},"/contrast/pr-preview/pr-1071/1.0/architecture/certificates-81a":{"__comp":"17896441","content":"e8480491"},"/contrast/pr-preview/pr-1071/1.0/architecture/observability-732":{"__comp":"17896441","content":"51513a8d"},"/contrast/pr-preview/pr-1071/1.0/architecture/secrets-df7":{"__comp":"17896441","content":"fda633d9"},"/contrast/pr-preview/pr-1071/1.0/basics/confidential-containers-9f0":{"__comp":"17896441","content":"d77304ba"},"/contrast/pr-preview/pr-1071/1.0/basics/features-4f9":{"__comp":"17896441","content":"4cf3063f"},"/contrast/pr-preview/pr-1071/1.0/basics/security-benefits-1f5":{"__comp":"17896441","content":"9620adf5"},"/contrast/pr-preview/pr-1071/1.0/components/overview-bc2":{"__comp":"17896441","content":"1ab97833"},"/contrast/pr-preview/pr-1071/1.0/components/policies-13a":{"__comp":"17896441","content":"bd029836"},"/contrast/pr-preview/pr-1071/1.0/components/runtime-6c4":{"__comp":"17896441","content":"27a940ba"},"/contrast/pr-preview/pr-1071/1.0/components/service-mesh-7ba":{"__comp":"17896441","content":"270470f6"},"/contrast/pr-preview/pr-1071/1.0/deployment-97f":{"__comp":"17896441","content":"2df6ad32"},"/contrast/pr-preview/pr-1071/1.0/examples/emojivoto-4ea":{"__comp":"17896441","content":"9040bbc8"},"/contrast/pr-preview/pr-1071/1.0/features-limitations-e94":{"__comp":"17896441","content":"aaec90ae"},"/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setup-4d1":{"__comp":"17896441","content":"a2899f6e"},"/contrast/pr-preview/pr-1071/1.0/getting-started/install-2b0":{"__comp":"17896441","content":"fbad79f4"},"/contrast/pr-preview/pr-1071/1.0/troubleshooting-249":{"__comp":"17896441","content":"c2ce05d5"},"/contrast/pr-preview/pr-1071/1.1-5db":{"__comp":"a7bd4aaa","__props":"e8dd02b6"},"/contrast/pr-preview/pr-1071/1.1-24c":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/1.1-ac4":{"__comp":"17896441","content":"5f998a2f"},"/contrast/pr-preview/pr-1071/1.1/about/telemetry-237":{"__comp":"17896441","content":"a86a94ce"},"/contrast/pr-preview/pr-1071/1.1/architecture/attestation-af4":{"__comp":"17896441","content":"48f2f8ef"},"/contrast/pr-preview/pr-1071/1.1/architecture/certificates-6e2":{"__comp":"17896441","content":"5ecc20d3"},"/contrast/pr-preview/pr-1071/1.1/architecture/observability-220":{"__comp":"17896441","content":"68be920e"},"/contrast/pr-preview/pr-1071/1.1/architecture/secrets-dac":{"__comp":"17896441","content":"f2348f57"},"/contrast/pr-preview/pr-1071/1.1/architecture/security-considerations-354":{"__comp":"17896441","content":"6507182a"},"/contrast/pr-preview/pr-1071/1.1/basics/confidential-containers-fdd":{"__comp":"17896441","content":"1057c3b3"},"/contrast/pr-preview/pr-1071/1.1/basics/features-8ff":{"__comp":"17896441","content":"1e7c9753"},"/contrast/pr-preview/pr-1071/1.1/basics/security-benefits-5f9":{"__comp":"17896441","content":"10257d90"},"/contrast/pr-preview/pr-1071/1.1/components/overview-08b":{"__comp":"17896441","content":"edcfcef8"},"/contrast/pr-preview/pr-1071/1.1/components/policies-1fe":{"__comp":"17896441","content":"0b1c872d"},"/contrast/pr-preview/pr-1071/1.1/components/runtime-179":{"__comp":"17896441","content":"4eec459c"},"/contrast/pr-preview/pr-1071/1.1/components/service-mesh-aac":{"__comp":"17896441","content":"969019ea"},"/contrast/pr-preview/pr-1071/1.1/deployment-1f2":{"__comp":"17896441","content":"0a09f1f2"},"/contrast/pr-preview/pr-1071/1.1/examples/emojivoto-ec4":{"__comp":"17896441","content":"5c6fa5d3"},"/contrast/pr-preview/pr-1071/1.1/features-limitations-c73":{"__comp":"17896441","content":"27004ef7"},"/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metal-6ec":{"__comp":"17896441","content":"b451d7c3"},"/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setup-211":{"__comp":"17896441","content":"3d96af17"},"/contrast/pr-preview/pr-1071/1.1/getting-started/install-897":{"__comp":"17896441","content":"a0a1fd3b"},"/contrast/pr-preview/pr-1071/1.1/troubleshooting-a8a":{"__comp":"17896441","content":"e9dbdd13"},"/contrast/pr-preview/pr-1071/next-a49":{"__comp":"a7bd4aaa","__props":"21893f51"},"/contrast/pr-preview/pr-1071/next-d49":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/next-223":{"__comp":"17896441","content":"0e384e19"},"/contrast/pr-preview/pr-1071/next/about/telemetry-4d2":{"__comp":"17896441","content":"2496d21b"},"/contrast/pr-preview/pr-1071/next/architecture/attestation-876":{"__comp":"17896441","content":"642ed902"},"/contrast/pr-preview/pr-1071/next/architecture/certificates-898":{"__comp":"17896441","content":"4fb24623"},"/contrast/pr-preview/pr-1071/next/architecture/observability-47a":{"__comp":"17896441","content":"927cf76e"},"/contrast/pr-preview/pr-1071/next/architecture/secrets-991":{"__comp":"17896441","content":"014daffb"},"/contrast/pr-preview/pr-1071/next/architecture/security-considerations-72c":{"__comp":"17896441","content":"b0cb3eb4"},"/contrast/pr-preview/pr-1071/next/basics/confidential-containers-bc0":{"__comp":"17896441","content":"b27c3275"},"/contrast/pr-preview/pr-1071/next/basics/features-81d":{"__comp":"17896441","content":"89a4f0ca"},"/contrast/pr-preview/pr-1071/next/basics/security-benefits-952":{"__comp":"17896441","content":"640cb024"},"/contrast/pr-preview/pr-1071/next/components/overview-19b":{"__comp":"17896441","content":"89486910"},"/contrast/pr-preview/pr-1071/next/components/policies-2b1":{"__comp":"17896441","content":"989c6d03"},"/contrast/pr-preview/pr-1071/next/components/runtime-d46":{"__comp":"17896441","content":"c4b4ced0"},"/contrast/pr-preview/pr-1071/next/components/service-mesh-701":{"__comp":"17896441","content":"ca5b6702"},"/contrast/pr-preview/pr-1071/next/deployment-9ee":{"__comp":"17896441","content":"a3713279"},"/contrast/pr-preview/pr-1071/next/examples/emojivoto-a56":{"__comp":"17896441","content":"f65fea7a"},"/contrast/pr-preview/pr-1071/next/examples/mysql-d38":{"__comp":"17896441","content":"7bdde4a4"},"/contrast/pr-preview/pr-1071/next/features-limitations-f30":{"__comp":"17896441","content":"35dd9928"},"/contrast/pr-preview/pr-1071/next/getting-started/bare-metal-ae6":{"__comp":"17896441","content":"cf49aa2b"},"/contrast/pr-preview/pr-1071/next/getting-started/cluster-setup-4f0":{"__comp":"17896441","content":"9a06ae3d"},"/contrast/pr-preview/pr-1071/next/getting-started/install-fc0":{"__comp":"17896441","content":"2a2a0c40"},"/contrast/pr-preview/pr-1071/next/troubleshooting-3ab":{"__comp":"17896441","content":"9d9f8394"},"/contrast/pr-preview/pr-1071/-fe3":{"__comp":"a7bd4aaa","__props":"368b3075"},"/contrast/pr-preview/pr-1071/-f4c":{"__comp":"a94703ab"},"/contrast/pr-preview/pr-1071/about/telemetry-ce3":{"__comp":"17896441","content":"046575a6"},"/contrast/pr-preview/pr-1071/architecture/attestation-7cd":{"__comp":"17896441","content":"aaa7edc4"},"/contrast/pr-preview/pr-1071/architecture/certificates-d75":{"__comp":"17896441","content":"ccad6777"},"/contrast/pr-preview/pr-1071/architecture/observability-9f1":{"__comp":"17896441","content":"bedb5cc1"},"/contrast/pr-preview/pr-1071/architecture/secrets-4ce":{"__comp":"17896441","content":"808ec8ef"},"/contrast/pr-preview/pr-1071/architecture/security-considerations-c81":{"__comp":"17896441","content":"d28f01c4"},"/contrast/pr-preview/pr-1071/basics/confidential-containers-703":{"__comp":"17896441","content":"a92f10fb"},"/contrast/pr-preview/pr-1071/basics/features-046":{"__comp":"17896441","content":"91456bd6"},"/contrast/pr-preview/pr-1071/basics/security-benefits-43f":{"__comp":"17896441","content":"d43358e1"},"/contrast/pr-preview/pr-1071/components/overview-9ba":{"__comp":"17896441","content":"616c9a0e"},"/contrast/pr-preview/pr-1071/components/policies-447":{"__comp":"17896441","content":"16cd20a9"},"/contrast/pr-preview/pr-1071/components/runtime-c8a":{"__comp":"17896441","content":"d18a22d8"},"/contrast/pr-preview/pr-1071/components/service-mesh-8d0":{"__comp":"17896441","content":"46d228a0"},"/contrast/pr-preview/pr-1071/deployment-dcc":{"__comp":"17896441","content":"197c7105"},"/contrast/pr-preview/pr-1071/examples/emojivoto-a53":{"__comp":"17896441","content":"44f8de13"},"/contrast/pr-preview/pr-1071/examples/mysql-646":{"__comp":"17896441","content":"bfdb605f"},"/contrast/pr-preview/pr-1071/features-limitations-914":{"__comp":"17896441","content":"8ec58f4b"},"/contrast/pr-preview/pr-1071/getting-started/bare-metal-78b":{"__comp":"17896441","content":"3b29aa35"},"/contrast/pr-preview/pr-1071/getting-started/cluster-setup-4b6":{"__comp":"17896441","content":"cc4abb91"},"/contrast/pr-preview/pr-1071/getting-started/install-17a":{"__comp":"17896441","content":"8bfc695a"},"/contrast/pr-preview/pr-1071/troubleshooting-ad0":{"__comp":"17896441","content":"1fefe6de"},"/contrast/pr-preview/pr-1071/-d63":{"__comp":"17896441","content":"ecab07fd"}}')}},e=>{e.O(0,[1869],(()=>{return t=45022,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/pr-preview/pr-1071/assets/js/main.be0c3a62.js.LICENSE.txt b/pr-preview/pr-1071/assets/js/main.be0c3a62.js.LICENSE.txt deleted file mode 100644 index 3a6ccc5052..0000000000 --- a/pr-preview/pr-1071/assets/js/main.be0c3a62.js.LICENSE.txt +++ /dev/null @@ -1,133 +0,0 @@ -/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress - * @license MIT */ - -/*! - * lunr.Builder - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.Index - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.Pipeline - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.Set - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.TokenSet - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.Vector - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.stemmer - * Copyright (C) 2020 Oliver Nightingale - * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt - */ - -/*! - * lunr.stopWordFilter - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.tokenizer - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.trimmer - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! - * lunr.utils - * Copyright (C) 2020 Oliver Nightingale - */ - -/*! Bundled license information: - -prismjs/prism.js: - (** - * Prism: Lightweight, robust, elegant syntax highlighting - * - * @license MIT <https://opensource.org/licenses/MIT> - * @author Lea Verou <https://lea.verou.me> - * @namespace - * @public - *) -*/ - -/*!*************************************************** -* mark.js v8.11.1 -* https://markjs.io/ -* Copyright (c) 2014–2018, Julian Kühnel -* Released under the MIT license https://git.io/vwTVl -*****************************************************/ - -/** - * @license React - * react-dom.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @license React - * react-jsx-runtime.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @license React - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * @license React - * scheduler.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/** - * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 - * Copyright (C) 2020 Oliver Nightingale - * @license MIT - */ - -/** @license React v16.13.1 - * react-is.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ diff --git a/pr-preview/pr-1071/assets/js/runtime~main.0e320535.js b/pr-preview/pr-1071/assets/js/runtime~main.0e320535.js deleted file mode 100644 index 3f5779c346..0000000000 --- a/pr-preview/pr-1071/assets/js/runtime~main.0e320535.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{"use strict";var e,a,f,c,d,b={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var f=t[e]={exports:{}};return b[e].call(f.exports,f,f.exports,r),f.exports}r.m=b,e=[],r.O=(a,f,c,d)=>{if(!f){var b=1/0;for(i=0;i<e.length;i++){f=e[i][0],c=e[i][1],d=e[i][2];for(var t=!0,o=0;o<f.length;o++)(!1&d||b>=d)&&Object.keys(r.O).every((e=>r.O[e](f[o])))?f.splice(o--,1):(t=!1,d<b&&(b=d));if(t){e.splice(i--,1);var n=c();void 0!==n&&(a=n)}}return a}d=d||0;for(var i=e.length;i>0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[f,c,d]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var d=Object.create(null);r.r(d);var b={};a=a||[null,f({}),f([]),f(f)];for(var t=2&c&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,r.d(d,b),d},r.d=(e,a)=>{for(var f in a)r.o(a,f)&&!r.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,f)=>(r.f[f](e,a),a)),[])),r.u=e=>"assets/js/"+({13:"c3f66d9e",89:"b3916dd3",95:"35dd9928",101:"dacf14a0",133:"98367cce",212:"a86a94ce",221:"e446d98f",234:"b451d7c3",315:"aaa7edc4",388:"327e592d",390:"c09e49b9",426:"9ce1fd56",430:"207bb774",447:"d18a22d8",455:"4ce6baab",485:"969019ea",594:"6903d0da",722:"5c6fa5d3",782:"989c6d03",801:"9a99019d",827:"fda633d9",912:"9620adf5",941:"5f998a2f",985:"1ab97833",995:"2496d21b",1047:"bd029836",1112:"966b9f47",1158:"04102e85",1226:"927cf76e",1321:"de615ffd",1362:"e8480491",1514:"173fd1a8",1560:"1c9b88ee",1575:"a161c24f",1597:"2df6ad32",1606:"7bd8db71",1632:"e277c26a",1647:"e9dbdd13",1658:"fbad2ec0",1690:"078f57bf",1734:"d580a1fd",1739:"896da145",1751:"327db732",1841:"8132774f",1861:"a2899f6e",1889:"3a77bb3e",1954:"5ecc20d3",1955:"014daffb",1956:"f593d43a",2005:"64d58a39",2007:"16cd20a9",2020:"48f2f8ef",2045:"abfbdc79",2132:"b0cb3eb4",2154:"27004ef7",2285:"046575a6",2343:"250ffcdd",2453:"9040bbc8",2454:"dfd9c366",2472:"f65fea7a",2476:"ba2406d8",2506:"8ec58f4b",2540:"c7462af2",2550:"4fb24623",2564:"c4b4ced0",2590:"fbad79f4",2623:"e1e441c9",2639:"4eec459c",2700:"2dbe31cc",2729:"ae6c0c68",2756:"5f62f97d",2759:"d28f01c4",2772:"5eab7755",2841:"e2b3b970",2857:"46157656",2912:"9a06ae3d",2941:"9397123b",2987:"3683601e",3024:"d43358e1",3074:"ac3e6feb",3098:"bedb5cc1",3108:"26742c3b",3116:"8dca39c2",3129:"6100b425",3133:"edcfcef8",3188:"0b1c872d",3246:"46d228a0",3357:"20382dd7",3391:"1e7c9753",3423:"ecab07fd",3459:"39db4684",3477:"10257d90",3505:"9a28f5c4",3506:"6478b99f",3610:"bfdb605f",3641:"3b29aa35",3690:"b27c3275",3702:"0a7a212e",3712:"69ec948c",3752:"7bdde4a4",3859:"51513a8d",3876:"018595b3",3970:"fbcf0d59",3976:"0e384e19",4113:"e55aefba",4118:"2cdf8d95",4206:"c1fac065",4213:"6fc50b39",4233:"d77304ba",4304:"aaec90ae",4411:"84cf2b87",4415:"bd625abb",4506:"3d96af17",4670:"9d9e06f4",4687:"89a4f0ca",4703:"cf49aa2b",4714:"41b31679",4980:"a0a4ec6e",5003:"a71cbd8f",5016:"21893f51",5225:"bf823012",5231:"7edb0f0d",5242:"790f17e8",5279:"27a940ba",5310:"3d9be0cc",5316:"ee8b52db",5335:"8c9a8791",5374:"2d1295a3",5388:"15b9bf06",5390:"21d7c4d4",5541:"642ed902",5742:"aba21aa0",5806:"a92f10fb",5811:"1057c3b3",5829:"9230b32a",5919:"368b3075",5945:"ca5b6702",5999:"54c6367b",6069:"7d1602ac",6118:"808ec8ef",6200:"1de90583",6232:"2e82b444",6240:"6a46f748",6330:"e8dd02b6",6408:"f47dd6e5",6440:"567e04ee",6463:"1fefe6de",6470:"06eada7a",6623:"7f3f1ff7",6645:"aafa6b90",6711:"f36abd57",6733:"f31967d8",6739:"0c24bc66",6755:"a0a1fd3b",6969:"14eb3368",7e3:"0a09f1f2",7061:"50474e10",7086:"89486910",7098:"a7bd4aaa",7234:"cc4abb91",7261:"8bfc695a",7292:"2a2a0c40",7294:"68be920e",7368:"0ba7602a",7682:"640cb024",7697:"27d05faa",7742:"197c7105",7832:"c3a9f66a",7882:"75100f0d",7924:"14a9ce33",8001:"bced0f3c",8024:"c2ce05d5",8117:"3e02a241",8170:"4f453872",8204:"06354bbe",8212:"6009a9aa",8259:"098bf236",8295:"aa0f7abf",8364:"4cf3063f",8401:"17896441",8403:"20e0cfa9",8597:"75d659e1",8671:"270470f6",8683:"ab09c42c",8772:"f2348f57",8902:"d1a11e04",8904:"200ecf61",8921:"90af0d0d",8976:"44f8de13",9013:"9d9f8394",9025:"7680d80e",9033:"ccad6777",9048:"a94703ab",9079:"6507182a",9103:"baef5027",9119:"cdb2b1a5",9361:"45c98560",9366:"91456bd6",9377:"9c6eeb97",9562:"616c9a0e",9588:"a3713279",9634:"d2630e76",9647:"5e95c892",9652:"44b49990",9874:"9ccb1fc6",9974:"a66d714b"}[e]||e)+"."+{13:"f9b116f8",89:"db62ca4d",95:"5731d66f",101:"ff767a68",133:"a60fe698",165:"786b0b5b",212:"1fdc663f",221:"4ef79517",234:"21c2b095",315:"6002bcd0",388:"8189d855",390:"62585cb6",391:"11ead156",426:"a07cbd12",430:"937e3159",447:"846e7193",455:"ef6f63da",485:"13bd2248",545:"7563beb4",594:"63bafa91",722:"cb92794e",758:"b164c2b0",782:"9f3aeec7",801:"eb40f802",827:"061ed873",890:"8531ec8c",912:"19a314c4",941:"b65db294",985:"c3577891",995:"ee6432b9",1047:"fddf79c6",1112:"06142c29",1158:"9c299feb",1226:"29128aa9",1321:"5ba725be",1362:"662dbe18",1478:"f7519b53",1514:"3f03ca9c",1560:"c2b9b81d",1575:"b698442f",1597:"624fd64a",1606:"98254150",1632:"ea7b0cc6",1647:"6065280b",1658:"6f2e0862",1690:"102e2128",1734:"eecaa741",1739:"10df34fb",1751:"8b71bf7f",1825:"260fa3c3",1841:"838ec563",1861:"1e5e2cad",1889:"49b3f8ee",1954:"6c4d8685",1955:"aacfa15a",1956:"0672da79",2005:"313bf37c",2007:"e25b19d5",2020:"546ed612",2045:"c9cb51c7",2130:"a7c31b12",2132:"017aa338",2154:"d11dfe88",2285:"0f7f0430",2334:"a23ce334",2343:"ae6e76ac",2387:"7f9ca256",2453:"74221d60",2454:"ac551a18",2472:"8955c8e3",2476:"c3b0175b",2506:"4a23bd26",2540:"58bb49ad",2550:"b975bdd4",2560:"c3661469",2564:"b12602ed",2590:"c7fad30b",2623:"cfbd7c08",2639:"1d030701",2664:"509e3099",2700:"3c51b1f7",2729:"8cc47233",2756:"200d33a5",2759:"deb2a417",2772:"5b4faa8a",2841:"4d762215",2857:"b50ca5fc",2912:"46bdaeb7",2941:"8b60de82",2987:"4d7dd5e0",3024:"90202999",3056:"0ac094fe",3074:"7733ee05",3098:"f06c512b",3108:"ba01b343",3116:"4500e87f",3129:"7022e9ad",3133:"98b05483",3175:"969edfc2",3188:"46cf372e",3246:"f0474804",3357:"24536267",3391:"62495ac8",3423:"a02478a9",3459:"ca1f2305",3477:"4ab1db5d",3505:"4a20392f",3506:"02d4423b",3610:"8b4e7cf0",3624:"631ec2ee",3641:"0ba1db01",3690:"3ddae91c",3702:"cb47d607",3712:"cd29b28f",3752:"4a1da80b",3764:"c12c89cb",3859:"5cbac465",3876:"6fec9739",3970:"4fb6163a",3976:"68c56d44",4113:"ab15b078",4118:"c5542a37",4206:"b45a35ee",4213:"418b1af9",4233:"d5619a4f",4304:"8196ad9c",4411:"f72f7a7f",4415:"dca62902",4485:"60f44ca9",4492:"d9cafff9",4506:"379760d6",4632:"878c659d",4670:"f7d4f664",4687:"87c559a7",4697:"c7062f31",4703:"a24fb11d",4714:"79aad1d5",4980:"a242125e",5003:"85849cbe",5016:"041d36ea",5110:"759384b2",5225:"bbc65b50",5231:"3b9797a0",5242:"a523ad89",5279:"4bef4b04",5310:"722295e4",5316:"1127312e",5335:"b68218dc",5374:"1f87ff64",5388:"8dd25a08",5390:"70b063a4",5410:"e9c6eab1",5541:"b6b3e13d",5742:"0f4e95f1",5806:"7eb02298",5811:"c2e3952a",5829:"873d5e8d",5919:"b498094d",5945:"9ab781f2",5978:"63ed3047",5999:"1dffaa95",6069:"b79b6cd3",6118:"f0fe9369",6200:"1ca7e4e9",6232:"af66ab87",6237:"fb5352b8",6240:"77a9fc8b",6244:"e911fcbf",6330:"d8be576b",6355:"1ac98e17",6383:"bf218c56",6408:"fd0db7db",6440:"a3475875",6452:"9f5d0a8d",6463:"55a1a00a",6470:"2bde985a",6623:"c5b8c0ac",6645:"8ef6dd98",6711:"08938dac",6733:"78ed1777",6739:"c5075be6",6755:"c8af1d49",6969:"65875b1f",7e3:"8c4c401c",7061:"3d570577",7086:"949b861e",7098:"59fbdee5",7234:"ccd0339e",7261:"a2c52c3f",7292:"d49ea0e0",7294:"df678bfa",7306:"9fd39ca5",7354:"36d3c86d",7357:"32327aca",7368:"036d984e",7682:"1beeaa31",7691:"8b446dde",7697:"67774e09",7723:"83dacf97",7742:"a9227bd1",7832:"e329e9c2",7882:"03b0b3ff",7924:"ad4e3471",8001:"261c5a1b",8024:"e81b5ad2",8117:"748d4906",8170:"54000c58",8204:"69f65616",8212:"10bee6c5",8259:"7fb3130f",8295:"fbffcf0c",8364:"2196b4dd",8401:"642e26c0",8403:"efdde374",8413:"965072af",8540:"517c5c64",8597:"d94ce473",8671:"5faa0f56",8683:"cce7684d",8731:"9d83d3f0",8772:"f3c0d472",8902:"07257942",8904:"42b16ee7",8921:"9fc28b24",8976:"64a0e6ff",9013:"beb73e2b",9025:"65a732c6",9033:"80d23dee",9048:"5e2b26dd",9079:"4e32c5ba",9103:"689d327f",9119:"e36333bf",9361:"84e9a5be",9366:"f04512d4",9377:"6972f46b",9562:"67cbd3fc",9588:"46fb5390",9634:"f829190e",9647:"4198b464",9652:"bb5c3680",9720:"8e4604d2",9732:"545304f6",9874:"c7393c04",9974:"813b3c04"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},d="contrast-docs:",r.l=(e,a,f,b)=>{if(c[e])c[e].push(a);else{var t,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var u=n[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==d+f){t=u;break}}t||(o=!0,(t=document.createElement("script")).charset="utf-8",t.timeout=120,r.nc&&t.setAttribute("nonce",r.nc),t.setAttribute("data-webpack",d+f),t.src=e),c[e]=[a];var s=(a,f)=>{t.onerror=t.onload=null,clearTimeout(l);var d=c[e];if(delete c[e],t.parentNode&&t.parentNode.removeChild(t),d&&d.forEach((e=>e(f))),a)return a(f)},l=setTimeout(s.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=s.bind(null,t.onerror),t.onload=s.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/contrast/pr-preview/pr-1071/",r.gca=function(e){return e={17896441:"8401",46157656:"2857",89486910:"7086",c3f66d9e:"13",b3916dd3:"89","35dd9928":"95",dacf14a0:"101","98367cce":"133",a86a94ce:"212",e446d98f:"221",b451d7c3:"234",aaa7edc4:"315","327e592d":"388",c09e49b9:"390","9ce1fd56":"426","207bb774":"430",d18a22d8:"447","4ce6baab":"455","969019ea":"485","6903d0da":"594","5c6fa5d3":"722","989c6d03":"782","9a99019d":"801",fda633d9:"827","9620adf5":"912","5f998a2f":"941","1ab97833":"985","2496d21b":"995",bd029836:"1047","966b9f47":"1112","04102e85":"1158","927cf76e":"1226",de615ffd:"1321",e8480491:"1362","173fd1a8":"1514","1c9b88ee":"1560",a161c24f:"1575","2df6ad32":"1597","7bd8db71":"1606",e277c26a:"1632",e9dbdd13:"1647",fbad2ec0:"1658","078f57bf":"1690",d580a1fd:"1734","896da145":"1739","327db732":"1751","8132774f":"1841",a2899f6e:"1861","3a77bb3e":"1889","5ecc20d3":"1954","014daffb":"1955",f593d43a:"1956","64d58a39":"2005","16cd20a9":"2007","48f2f8ef":"2020",abfbdc79:"2045",b0cb3eb4:"2132","27004ef7":"2154","046575a6":"2285","250ffcdd":"2343","9040bbc8":"2453",dfd9c366:"2454",f65fea7a:"2472",ba2406d8:"2476","8ec58f4b":"2506",c7462af2:"2540","4fb24623":"2550",c4b4ced0:"2564",fbad79f4:"2590",e1e441c9:"2623","4eec459c":"2639","2dbe31cc":"2700",ae6c0c68:"2729","5f62f97d":"2756",d28f01c4:"2759","5eab7755":"2772",e2b3b970:"2841","9a06ae3d":"2912","9397123b":"2941","3683601e":"2987",d43358e1:"3024",ac3e6feb:"3074",bedb5cc1:"3098","26742c3b":"3108","8dca39c2":"3116","6100b425":"3129",edcfcef8:"3133","0b1c872d":"3188","46d228a0":"3246","20382dd7":"3357","1e7c9753":"3391",ecab07fd:"3423","39db4684":"3459","10257d90":"3477","9a28f5c4":"3505","6478b99f":"3506",bfdb605f:"3610","3b29aa35":"3641",b27c3275:"3690","0a7a212e":"3702","69ec948c":"3712","7bdde4a4":"3752","51513a8d":"3859","018595b3":"3876",fbcf0d59:"3970","0e384e19":"3976",e55aefba:"4113","2cdf8d95":"4118",c1fac065:"4206","6fc50b39":"4213",d77304ba:"4233",aaec90ae:"4304","84cf2b87":"4411",bd625abb:"4415","3d96af17":"4506","9d9e06f4":"4670","89a4f0ca":"4687",cf49aa2b:"4703","41b31679":"4714",a0a4ec6e:"4980",a71cbd8f:"5003","21893f51":"5016",bf823012:"5225","7edb0f0d":"5231","790f17e8":"5242","27a940ba":"5279","3d9be0cc":"5310",ee8b52db:"5316","8c9a8791":"5335","2d1295a3":"5374","15b9bf06":"5388","21d7c4d4":"5390","642ed902":"5541",aba21aa0:"5742",a92f10fb:"5806","1057c3b3":"5811","9230b32a":"5829","368b3075":"5919",ca5b6702:"5945","54c6367b":"5999","7d1602ac":"6069","808ec8ef":"6118","1de90583":"6200","2e82b444":"6232","6a46f748":"6240",e8dd02b6:"6330",f47dd6e5:"6408","567e04ee":"6440","1fefe6de":"6463","06eada7a":"6470","7f3f1ff7":"6623",aafa6b90:"6645",f36abd57:"6711",f31967d8:"6733","0c24bc66":"6739",a0a1fd3b:"6755","14eb3368":"6969","0a09f1f2":"7000","50474e10":"7061",a7bd4aaa:"7098",cc4abb91:"7234","8bfc695a":"7261","2a2a0c40":"7292","68be920e":"7294","0ba7602a":"7368","640cb024":"7682","27d05faa":"7697","197c7105":"7742",c3a9f66a:"7832","75100f0d":"7882","14a9ce33":"7924",bced0f3c:"8001",c2ce05d5:"8024","3e02a241":"8117","4f453872":"8170","06354bbe":"8204","6009a9aa":"8212","098bf236":"8259",aa0f7abf:"8295","4cf3063f":"8364","20e0cfa9":"8403","75d659e1":"8597","270470f6":"8671",ab09c42c:"8683",f2348f57:"8772",d1a11e04:"8902","200ecf61":"8904","90af0d0d":"8921","44f8de13":"8976","9d9f8394":"9013","7680d80e":"9025",ccad6777:"9033",a94703ab:"9048","6507182a":"9079",baef5027:"9103",cdb2b1a5:"9119","45c98560":"9361","91456bd6":"9366","9c6eeb97":"9377","616c9a0e":"9562",a3713279:"9588",d2630e76:"9634","5e95c892":"9647","44b49990":"9652","9ccb1fc6":"9874",a66d714b:"9974"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(a,f)=>{var c=r.o(e,a)?e[a]:void 0;if(0!==c)if(c)f.push(c[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var d=new Promise(((f,d)=>c=e[a]=[f,d]));f.push(c[2]=d);var b=r.p+r.u(a),t=new Error;r.l(b,(f=>{if(r.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var d=f&&("load"===f.type?"missing":f.type),b=f&&f.target&&f.target.src;t.message="Loading chunk "+a+" failed.\n("+d+": "+b+")",t.name="ChunkLoadError",t.type=d,t.request=b,c[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,f)=>{var c,d,b=f[0],t=f[1],o=f[2],n=0;if(b.some((a=>0!==e[a]))){for(c in t)r.o(t,c)&&(r.m[c]=t[c]);if(o)var i=o(r)}for(a&&a(f);n<b.length;n++)d=b[n],r.o(e,d)&&e[d]&&e[d][0](),e[d]=0;return r.O(i)},f=self.webpackChunkcontrast_docs=self.webpackChunkcontrast_docs||[];f.forEach(a.bind(null,0)),f.push=a.bind(null,f.push.bind(f))})()})(); \ No newline at end of file diff --git a/pr-preview/pr-1071/basics/confidential-containers.html b/pr-preview/pr-1071/basics/confidential-containers.html deleted file mode 100644 index 87014e1ddb..0000000000 --- a/pr-preview/pr-1071/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ -<!doctype html> -<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-1.2 docs-doc-page docs-doc-id-basics/confidential-containers" data-has-hydrated="false"> -<head> -<meta charset="UTF-8"> -<meta name="generator" content="Docusaurus v3.6.3"> -<title data-rh="true">Confidential Containers | Contrast - - - - -
Version: 1.2

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/basics/features.html b/pr-preview/pr-1071/basics/features.html deleted file mode 100644 index c2942d9173..0000000000 --- a/pr-preview/pr-1071/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Version: 1.2

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/basics/security-benefits.html b/pr-preview/pr-1071/basics/security-benefits.html deleted file mode 100644 index e7b977e191..0000000000 --- a/pr-preview/pr-1071/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Version: 1.2

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/components/overview.html b/pr-preview/pr-1071/components/overview.html deleted file mode 100644 index c749487807..0000000000 --- a/pr-preview/pr-1071/components/overview.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Version: 1.2

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/components/policies.html b/pr-preview/pr-1071/components/policies.html deleted file mode 100644 index 37a6469dce..0000000000 --- a/pr-preview/pr-1071/components/policies.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Version: 1.2

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA or TDX MRCONFIGID for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA or MRCONFIGID, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA/MRCONFIGID.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA/MRCONFIGID.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA/MRCONFIGID field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

-

Platform Differences

-

Contrast uses different rules and data sections for different platforms. -This results in different policy hashes for different platforms.

-

The generate command automatically derives the correct set of rules and data sections from the reference-values flag.

-

The verify, set, and recover commands need to know the coordinator's expected policy hash to verify its identity. -By default these commands assume that the coordinator is using the policy for the AKS-CLH-SNP platform. -If the coordinator is running on a different platform, the correct policy hash can be looked up in the coordinator-policy.hash file bundled with the Contrast release. -The coordinator policy hash can be overwritten using the --coordinator-policy-hash flag.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/components/runtime.html b/pr-preview/pr-1071/components/runtime.html deleted file mode 100644 index 6a8c235dcb..0000000000 --- a/pr-preview/pr-1071/components/runtime.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Version: 1.2

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled/TDX-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

Virtual machine manager (VMM)

-

The containerd shim uses a virtual machine monitor to create a confidential virtual machine for every pod. -On AKS, Contrast uses cloud-hypervisor. -On bare metal, Contrast uses QEMU. -The appropriate files are installed on every node by the node-installer.

-

Snapshotters

-

Contrast uses containerd snapshotters to provide container images to the pod-VM. -Each snapshotter consists of a host component that pulls container images and a guest component used to mount/pull container images.

-

On AKS, Contrast uses the tardev snapshotter to provide container images as block devices to the pod-VM. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

On bare metal, Contrast uses the nydus snapshotter to store metadata about the images. This metadata is communicated to the guest, so that it can pull the images itself.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor or QEMU as the virtual machine manager (VMM)
  • -
  • Install an IGVM file or separate firmware and kernel files for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/components/service-mesh.html b/pr-preview/pr-1071/components/service-mesh.html deleted file mode 100644 index 764ed0e7c1..0000000000 --- a/pr-preview/pr-1071/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Version: 1.2

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables CONTRAST_INGRESS_PROXY_CONFIG, -CONTRAST_EGRESS_PROXY_CONFIG and CONTRAST_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: CONTRAST_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:v1.2.0@sha256:756818aff3c61cc4852ef551a2fabfa90269d0b0a53d50c0e32fe448bac4d994"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-secrets
mountPath: /contrast
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/deployment.html b/pr-preview/pr-1071/deployment.html deleted file mode 100644 index 3ab827a884..0000000000 --- a/pr-preview/pr-1071/deployment.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Version: 1.2

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set up a cluster on AKS.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-aks-clh-snp.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

Security review

-

Contrast ensures integrity and confidentiality of the applications, but interactions with untrusted systems require the developers' attention. -Review the security considerations and the certificates section for writing secure Contrast application.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-secrets shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate --reference-values aks-clh-snp resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --reference-values aks-clh-snp --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-secrets volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:v1.2.0@sha256:942c019b751762540c45d827c1667e5e9f228ccf72c8cc44f11fc428610d196e"
name: contrast-initializer
volumeMounts:
- mountPath: /contrast
name: contrast-secrets
volumes:
- emptyDir: {}
name: contrast-secrets
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

This will use the reference values from the manifest file to attest the Coordinator. -After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the -service mesh root certificate and the history of manifests into the verify/ directory. In addition, the policies -referenced in the active manifest are also written to the directory. The verification will fail if the active -manifest at the Coordinator doesn't match the manifest passed to the CLI.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, attempting to connect with curl and the mesh CA certificate will throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Recover the Coordinator

-

If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material. -For demonstration purposes, you can simulate this scenario by deleting the Coordinator pod.

-
kubectl delete pod -l app.kubernetes.io/name=coordinator
-

Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet. -You can confirm this by running verify again, or you can restart a workload pod, which should stay in the initialization phase. -However, the secret seed in your working directory is sufficient to recover the coordinator.

-
contrast recover -c "${coordinator}:1313"
-

Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state. -You can now verify the Coordinator again, which should return the same manifest you set before.

-
warning

The recovery process invalidates the mesh CA certificate: -existing workloads won't be able to communicate with workloads newly spawned. -All workloads should be restarted after the recovery succeeded.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/examples/emojivoto.html b/pr-preview/pr-1071/examples/emojivoto.html deleted file mode 100644 index f9652a334c..0000000000 --- a/pr-preview/pr-1071/examples/emojivoto.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Version: 1.2

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voter's perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

Emojivoto can be seen as a lighthearted example of an app dealing with sensitive data. -Contrast protects emojivoto in two ways. First, it shields emojivoto as a whole from the infrastructure, for example, Azure. -Second, it can be configured to also prevent data access even from the administrator of the app. In the case of emojivoto, this gives assurance to users that their votes remain secret.

-

emojivoto components topology

-

Prerequisites

-
    -
  • Installed Contrast CLI
  • -
  • A running Kubernetes cluster with support for confidential containers, either on AKS or on bare metal.
  • -
-

Steps to deploy emojivoto with Contrast

-

Download the deployment files

-

The emojivoto deployment files are part of the Contrast release. You can download them by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.2.0/emojivoto-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass, -which needs to be installed to the cluster initially. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-aks-clh-snp.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Verifying the deployment as a user

-

In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before casting a vote. -With Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment. -Contrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future. -Successful verification of the Coordinator means that the user can be sure that the given manifest will be enforced.

-

Verifying the Coordinator

-

A user can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Auditing the manifest history and artifacts

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Connecting securely to the application

-

After ensuring the configuration of the Coordinator fits the expectation, the user can securely connect -to the application using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Updating the certificate SAN and the manifest (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configuring the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {
"SANs": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
"WorkloadSecretID": "web"
},
-

Updating the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/examples/mysql.html b/pr-preview/pr-1071/examples/mysql.html deleted file mode 100644 index de2afd439c..0000000000 --- a/pr-preview/pr-1071/examples/mysql.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Encrypted volume mount | Contrast - - - - -
Version: 1.2

Encrypted volume mount

-

This tutorial guides you through deploying a simple application with an -encrypted MySQL database using the Contrast workload -secret.

-

MySQL is an open-source database used to organize data into -tables and quickly retrieve information about its content. All of the data in a -MySQL database is stored in the /var/lib/mysql directory. In this example, we -use the workload secret to setup an encrypted LUKS mount for the -/var/lib/mysql directory to easily deploy an application with encrypted -persistent storage using Contrast.

-

The resources provided in this demo are designed for educational purposes and -shouldn't be used in a production environment without proper evaluation. When -working with persistent storage, regular backups are recommended in order to -prevent data loss. For confidential applications, please also refer to the -security considerations. Also be -aware of the differences in security implications of the workload secrets for -the data owner and the workload owner. For more details, see the Workload -Secrets documentation.

-

Prerequisites

-
    -
  • Installed Contrast CLI
  • -
  • A running Kubernetes cluster with support for confidential containers, either on AKS or on bare metal
  • -
-

Steps to deploy MySQL with Contrast

-

Download the deployment files

-

The MySQL deployment files are part of the Contrast release. You can download them by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/download/v1.2.0/mysql-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass, -which needs to be installed to the cluster initially. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/download/v1.2.0/coordinator-aks-clh-snp.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads. It will attest the pod to the Coordinator and fetch the workload certificates and the workload secret.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the MySQL server and client.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Deploy MySQL

-

Now that the coordinator has a manifest set, which defines the MySQL deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Persistent workload secrets

During the initialization process of the workload pod, the Contrast Initializer -sends an attestation report to the Coordinator and receives a workload secret -derived from the Coordinator's secret seed and the workload secret ID specified in the -manifest, and writes it to a secure in-memory volumeMount.

-

The MySQL deployment is declared as a StatefulSet with a mounted block device. -An init container running cryptsetup uses the workload secret at -/contrast/secrets/workload-secret-seed to generate a key and setup the block -device as a LUKS partition. Before starting the MySQL container, the init -container uses the generated key to open the LUKS device, which is then mounted -by the MySQL container. For the MySQL container, this process is completely -transparent and works like mounting any other volume. The cryptsetup container -will remain running to provide the necessary decryption context for the workload -container.

-

Verifying the deployment as a user

-

In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before connecting to the database. -With Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment. -Contrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future. -Successful verification of the Coordinator means that the user can be sure that the given manifest will be enforced.

-

Verifying the Coordinator

-

A user can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Auditing the manifest history and artifacts

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A user of the application should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Connecting to the application

-

Other confidential containers can securely connect to the MySQL server via the -Service Mesh. The configured mysql-client -deployment connects to the MySQL server and inserts test data into a table. To -view the logs of the mysql-client deployment, use the following commands:

-
kubectl logs -l app.kubernetes.io/name=mysql-client -c mysql-client
-

The Service Mesh ensures an mTLS connection between the MySQL client and server -using the mesh certificates. As a result, no other workload can connect to the -MySQL server unless explicitly allowed in the manifest.

-

Updating the deployment

-

Because the workload secret is derived from the WorkloadSecredID specified in -the manifest and not to an individual pod, once the pod restarts, the -cryptsetup init container can deterministically generate the same key again -and open the already partitioned LUKS device. -For more information on using the workload secret, see Workload -Secrets.

-

For example, after making changes to the deployment files, the runtime policies -need to be regenerated with contrast generate and the new manifest needs to be -set using contrast set.

-
contrast generate deployment/
contrast set -c "${coordinator}:1313" deployment/
-

The new deployment can then be applied by running:

-
kubectl rollout restart statefulset/mysql-backend
kubectl rollout restart deployment/mysql-client
-

The new MySQL backend pod will then start up the cryptsetup init container which -receives the same workload secret as before and can therefore generate the -correct key to open the LUKS device. All previously stored data in the MySQL -database is available in the newly created pod in an encrypted volume mount.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/features-limitations.html b/pr-preview/pr-1071/features-limitations.html deleted file mode 100644 index 185fabf17d..0000000000 --- a/pr-preview/pr-1071/features-limitations.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Version: 1.2

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes is available for AMD SEV-SNP and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Contrast only supports volumes with volumeMode: Block. These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: Integrity checks don't cover any volume mounts, such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container, affect the service mesh implementation of Contrast. -Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
-

Automatic recovery and high availability

-

The Contrast Coordinator is a singleton and can't be scaled to more than one instance. -When this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually. -In a future release, we plan to support distributed Coordinator instances that can recover automatically.

-

Overriding Kata configuration

-

Kata Containers supports overriding certain configuration values via Kubernetes annotations.

-

It needs to be noted that setting these values is unsupported, and doing so may lead to unexpected -behaviour, as Contrast isn't tested against all possible configuration combinations.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/getting-started/bare-metal.html b/pr-preview/pr-1071/getting-started/bare-metal.html deleted file mode 100644 index 270ae15219..0000000000 --- a/pr-preview/pr-1071/getting-started/bare-metal.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -Prepare a bare-metal instance | Contrast - - - - -
Version: 1.2

Prepare a bare-metal instance

-

Hardware and firmware setup

-
    -
  1. Update your BIOS to a version that supports AMD SEV-SNP. Updating to the latest available version is recommended as newer versions will likely contain security patches for AMD SEV-SNP.
  2. -
  3. Enter BIOS setup to enable SMEE, IOMMU, RMP coverage, and SEV-SNP. Set the SEV-ES ASID Space Limit to a non-zero number (higher is better).
  4. -
  5. Download the latest firmware version for your processor from AMD, unpack it, and place it in /lib/firmware/amd.
  6. -

Consult AMD's Using SEV with AMD EPYC Processors user guide for more information.

-

Kernel Setup

-

Install a kernel with version 6.11 or greater. If you're following this guide before 6.11 has been released, use 6.11-rc3. Don't use 6.11-rc4 - 6.11-rc6 as they contain a regression. 6.11-rc7+ might work.

-

Increase the user.max_inotify_instances sysctl limit by adding user.max_inotify_instances=8192 to /etc/sysctl.d/99-sysctl.conf and running sysctl --system.

-

K3s Setup

-
    -
  1. Follow the K3s setup instructions to create a cluster.
  2. -
  3. Install a block storage provider such as Longhorn and mark it as the default storage class.
  4. -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/getting-started/cluster-setup.html b/pr-preview/pr-1071/getting-started/cluster-setup.html deleted file mode 100644 index 4301f78721..0000000000 --- a/pr-preview/pr-1071/getting-started/cluster-setup.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Version: 1.2

Create a cluster

-

Prerequisites

-
    -
  • Install version 2.44.1 or newer of the Azure CLI. Note that your package manager will likely install an outdated version.
  • -
  • Install a recent version of kubectl.
  • -
-

Prepare using the AKS preview

-

First, log in to your Azure subscription:

-
az login
-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, create a CoCo enabled AKS cluster with:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.30 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation \
--node-count 1 \
--generate-ssh-keys
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show a single node:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
-

🥳 Congratulations. You're now ready to set up your first application with Contrast. Follow this example to learn how.

-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/getting-started/install.html b/pr-preview/pr-1071/getting-started/install.html deleted file mode 100644 index 3fc84eaaee..0000000000 --- a/pr-preview/pr-1071/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Version: 1.2

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/download/v1.2.0/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/gtagman.js b/pr-preview/pr-1071/gtagman.js deleted file mode 100644 index 57bf6717a5..0000000000 --- a/pr-preview/pr-1071/gtagman.js +++ /dev/null @@ -1,5 +0,0 @@ -(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': -new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], -j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= -'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); -})(window,document,'script','dataLayer','GTM-NF9NM7V'); diff --git a/pr-preview/pr-1071/img/GitHub-Banner_Contrast_2024.gif b/pr-preview/pr-1071/img/GitHub-Banner_Contrast_2024.gif deleted file mode 100644 index d3ad42cf5c..0000000000 Binary files a/pr-preview/pr-1071/img/GitHub-Banner_Contrast_2024.gif and /dev/null differ diff --git a/pr-preview/pr-1071/img/concept.svg b/pr-preview/pr-1071/img/concept.svg deleted file mode 100644 index af04ecafab..0000000000 --- a/pr-preview/pr-1071/img/concept.svg +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pr-preview/pr-1071/img/favicon.ico b/pr-preview/pr-1071/img/favicon.ico deleted file mode 100644 index 85a1642f79..0000000000 Binary files a/pr-preview/pr-1071/img/favicon.ico and /dev/null differ diff --git a/pr-preview/pr-1071/img/logos/contrast_icon.svg b/pr-preview/pr-1071/img/logos/contrast_icon.svg deleted file mode 100644 index 235ee27474..0000000000 --- a/pr-preview/pr-1071/img/logos/contrast_icon.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/pr-preview/pr-1071/index.html b/pr-preview/pr-1071/index.html deleted file mode 100644 index 4244c77de6..0000000000 --- a/pr-preview/pr-1071/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Version: 1.2

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next.html b/pr-preview/pr-1071/next.html deleted file mode 100644 index b8b5e3ca23..0000000000 --- a/pr-preview/pr-1071/next.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Contrast | Contrast - - - - -
Version: Next

Contrast

-

Welcome to the documentation of Contrast! Contrast runs confidential container deployments on Kubernetes at scale.

-

Contrast concept

-

Contrast is based on the Kata Containers and -Confidential Containers projects. -Confidential Containers are Kubernetes pods that are executed inside a confidential micro-VM and provide strong hardware-based isolation from the surrounding environment. -This works with unmodified containers in a lift-and-shift approach. -Contrast currently targets the CoCo preview on AKS.

-
tip

See the 📄whitepaper for more information on confidential computing.

-

Goal

-

Contrast is designed to keep all data always encrypted and to prevent access from the infrastructure layer. It removes the infrastructure provider from the trusted computing base (TCB). This includes access from datacenter employees, privileged cloud admins, own cluster administrators, and attackers coming through the infrastructure, for example, malicious co-tenants escalating their privileges.

-

Contrast integrates fluently with the existing Kubernetes workflows. It's compatible with managed Kubernetes, can be installed as a day-2 operation and imposes only minimal changes to your deployment flow.

-

Use Cases

-

Contrast provides unique security features and benefits. The core use cases are:

-
    -
  • Increasing the security of your containers
  • -
  • Moving sensitive workloads from on-prem to the cloud with Confidential Computing
  • -
  • Shielding the code and data even from the own cluster administrators
  • -
  • Increasing the trustworthiness of your SaaS offerings
  • -
  • Simplifying regulatory compliance
  • -
  • Multi-party computation for data collaboration
  • -
-

Next steps

-

You can learn more about the concept of Confidential Containers, features, and security benefits of Contrast in this section. To jump right into the action head to Getting started.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/about/telemetry.html b/pr-preview/pr-1071/next/about/telemetry.html deleted file mode 100644 index ff5b8f2914..0000000000 --- a/pr-preview/pr-1071/next/about/telemetry.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -CLI telemetry | Contrast - - - - -
Version: Next

CLI telemetry

-

The Contrast CLI sends telemetry data to Edgeless Systems when you use CLI commands. -This allows to understand how Contrast is used and to improve it.

-

The CLI sends the following data:

-
    -
  • The CLI version
  • -
  • The CLI target OS and architecture (GOOS and GOARCH)
  • -
  • The command that was run
  • -
  • The kind of error that occurred (if any)
  • -
-

The CLI doesn't collect sensitive information. -The implementation is open-source and can be reviewed.

-

IP addresses may be processed or stored for security purposes.

-

The data that the CLI collects adheres to the Edgeless Systems privacy policy.

-

You can disable telemetry by setting the environment variable DO_NOT_TRACK=1 before running the CLI.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/architecture/attestation.html b/pr-preview/pr-1071/next/architecture/attestation.html deleted file mode 100644 index 0a246fc82c..0000000000 --- a/pr-preview/pr-1071/next/architecture/attestation.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - -Attestation in Contrast | Contrast - - - - -
Version: Next

Attestation in Contrast

-

This document describes the attestation architecture of Contrast, adhering to the definitions of Remote ATtestation procedureS (RATS) in RFC 9334. -The following gives a detailed description of Contrast's attestation architecture. -At the end of this document, we included an FAQ that answers the most common questions regarding attestation in hindsight of the security benefits.

-

Attestation architecture

-

Contrast integrates with the RATS architecture, leveraging their definition of roles and processes including Attesters, Verifiers, and Relying Parties.

-

Conceptual attestation architecture

-

Figure 1: Conceptual attestation architecture. Taken from RFC 9334.

-
    -
  • Attester: Assigned to entities that are responsible for creating Evidence which is then sent to a Verifier.
  • -
  • Verifier: These entities utilize the Evidence, Reference Values, and Endorsements. They assess the trustworthiness of the Attester by applying an Appraisal Policy for Evidence. Following this assessment, Verifiers generate Attestation Results for use by Relying Parties. The Appraisal Policy for Evidence may be provided by the Verifier Owner, programmed into the Verifier, or acquired through other means.
  • -
  • Relying Party: Assigned to entities that utilize Attestation Results, applying their own appraisal policies to make specific decisions, such as authorization decisions. This process is referred to as the "appraisal of Attestation Results." The Appraisal Policy for Attestation Results might be sourced from the Relying Party Owner, configured by the owner, embedded in the Relying Party, or obtained through other protocols or mechanisms.
  • -
-

Components of Contrast's attestation

-

The key components involved in the attestation process of Contrast are detailed below:

-

Attester: Application Pods

-

This includes all Pods of the Contrast deployment that run inside Confidential Containers and generate cryptographic evidence reflecting their current configuration and state. -Their evidence is rooted in the hardware measurements from the CPU and their confidential VM environment. -The details of this evidence are given below in the section on evidence generation and appraisal.

-

Attestation flow of a confidential pod

-

Figure 2: Attestation flow of a confidential pod. Based on the layered attester graphic in RFC 9334.

-

Pods run in Contrast's runtime environment (B), effectively within a confidential VM. -During launch, the CPU (A) measures the initial memory content of the confidential VM that contains Contrast's pod-VM image and generates the corresponding attestation evidence. -The image is in IGVM format, encapsulating all information required to launch a virtual machine, including the kernel, the initramfs, and kernel cmdline. -The kernel cmdline contains the root hash for dm-verity that ensures the integrity of the root filesystem. -The root filesystem contains all components of the container's runtime environment including the guest agent (C).

-

In the userland, the guest agent takes care of enforcing the runtime policy of the pod. -While the policy is passed in during the initialization procedure via the host, the evidence for the runtime policy is part of the CPU measurements. -During the deployment the policy is annotated to the Kubernetes Pod resources. -The hypervisor adds the hash of the policy to the attestation report via the HOSTDATA (on AMD SEV-SNP) or MRCONFIGID (Intel TDX) fields. -When provided with the policy from the Kata host, the guest agent verifies that the policy's hash matches the one in the HOSTDATA/MRCONFIGID field.

-

In summary a Pod's evidence is the attestation report of the CPU that provides evidence for runtime environment and the runtime policy.

-

Verifier: Coordinator and CLI

-

The Coordinator acts as a verifier within the Contrast deployment, configured with a Manifest that defines the reference values and serves as an appraisal policy for all pods in the deployment. -It also pulls endorsements from hardware vendors to verify the hardware claims. -The Coordinator operates within the cluster as a confidential container and provides similar evidence as any other Pod when it acts as an attester. -In RATS terminology, the Coordinator's dual role is defined as a lead attester in a composite device which spans the entire deployment: Coordinator and the workload pods. -It collects evidence from other attesters and conveys it to a verifier, generating evidence about the layout of the whole composite device based on the Manifest as the appraisal policy.

-

Deployment attestation as a composite device

-

Figure 3: Contrast deployment as a composite device. Based on the composite device in RFC 9334.

-

The CLI serves as the verifier for the Coordinator and the entire Contrast deployment, containing the reference values for the Coordinator and the endorsements from hardware vendors. -These reference values are built into the CLI during our release process and can be reproduced offline via reproducible builds.

-

Relying Party: Data owner

-

A relying party in the Contrast scenario could be, for example, the data owner that interacts with the application. -The relying party can use the CLI to obtain the attestation results and Contrast's CA certificates bound to these results. -The CA certificates can then be used by the relying party to authenticate the application, for example through TLS connections.

-

Evidence generation and appraisal

-

Evidence types and formats

-

In Contrast, attestation evidence revolves around a hardware-generated attestation report, which contains several critical pieces of information:

-
    -
  • The hardware attestation report: This report includes details such as the chip identifier, platform information, microcode versions, and comprehensive guest measurements. The entire report is signed by the CPU's private key, ensuring the authenticity and integrity of the data provided.
  • -
  • The launch measurements: Included within the hardware attestation report, this is a digest generated by the CPU that represents a hash of all initial guest memory pages. This includes essential components like the kernel, initramfs, and the kernel command line. Notably, it incorporates the root filesystem's dm-verity root hash, verifying the integrity of the root filesystem.
  • -
  • The runtime policy hash: Also part of the hardware attestation report, this field contains the hash of the Rego policy which dictates all expected API commands and their values from the host to the Kata guest agent. It encompasses crucial settings such as dm-verity hashes for the container image layers, environment variables, and mount points.
  • -
-

Appraisal policies for evidence

-

The appraisal of this evidence in Contrast is governed by two main components:

-
    -
  • The Manifest: A JSON file used by the Coordinator to align with reference values. It sets the expectations for runtime policy hashes for each pod and includes what should be reported in the hardware attestation report for each component of the deployment.
  • -
  • The CLI's appraisal policy: This policy encompasses expected values of the Coordinator’s guest measurements and its runtime policy. It's embedded into the CLI during the build process and ensures that any discrepancy between the built-in values and those reported by the hardware attestation can be identified and addressed. The integrity of this policy is safeguardable through reproducible builds, allowing verification against the source code reference.
  • -
-

Frequently asked questions about attestation in Contrast

-

What's the purpose of remote attestation in Contrast?

-

Remote attestation in Contrast ensures that software runs within a secure, isolated confidential computing environment. -This process certifies that the memory is encrypted and confirms the integrity and authenticity of the software running within the deployment. -By validating the runtime environment and the policies enforced on it, Contrast ensures that the system operates in a trustworthy state and hasn't been tampered with.

-

How does Contrast ensure the security of the attestation process?

-

Contrast leverages hardware-rooted security features such as AMD SEV-SNP or Intel TDX to generate cryptographic evidence of a pod’s current state and configuration. -This evidence is checked against pre-defined appraisal policies to guarantee that only verified and authorized pods are part of a Contrast deployment.

-

What security benefits does attestation provide?

-

Attestation confirms the integrity of the runtime environment and the identity of the workloads. -It plays a critical role in preventing unauthorized changes and detecting potential modifications at runtime. -The attestation provides integrity and authenticity guarantees, enabling relying parties—such as workload operators or data owners—to confirm the effective protection against potential threats, including malicious cloud insiders, co-tenants, or compromised workload operators. -More details on the specific security benefits can be found here.

-

How can you verify the authenticity of attestation results?

-

Attestation results in Contrast are tied to cryptographic proofs generated and signed by the hardware itself. -These proofs are then verified using public keys from trusted hardware vendors, ensuring that the results aren't only accurate but also resistant to tampering. -For further authenticity verification, all of Contrast's code is reproducibly built, and the attestation evidence can be verified locally from the source code.

-

How are attestation results used by relying parties?

-

Relying parties use attestation results to make informed security decisions, such as allowing access to sensitive data or resources only if the attestation verifies the system's integrity. -Thereafter, the use of Contrast's CA certificates in TLS connections provides a practical approach to communicate securely with the application.

-

Summary

-

In summary, Contrast's attestation strategy adheres to the RATS guidelines and consists of robust verification mechanisms that ensure each component of the deployment is secure and trustworthy. -This comprehensive approach allows Contrast to provide a high level of security assurance to its users.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/architecture/certificates.html b/pr-preview/pr-1071/next/architecture/certificates.html deleted file mode 100644 index c91a88f2b8..0000000000 --- a/pr-preview/pr-1071/next/architecture/certificates.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - -Certificate authority | Contrast - - - - -
Version: Next

Certificate authority

-

The Coordinator acts as a certificate authority (CA) for the workloads -defined in the manifest. -After a workload pod's attestation has been verified by the Coordinator, -it receives a mesh certificate and the mesh CA certificate. -The mesh certificate can be used for example in a TLS connection as the server or -client certificate to proof to the other party that the workload has been -verified by the Coordinator. The other party can verify the mesh certificate -with the mesh CA certificate. While the certificates can be used by the workload -developer in different ways, they're automatically used in Contrast's service -mesh to establish mTLS connections between workloads in the same deployment.

-

Public key infrastructure

-

The Coordinator establishes a public key infrastructure (PKI) for all workloads -contained in the manifest. The Coordinator holds three certificates: the root CA -certificate, the intermediate CA certificate, and the mesh CA certificate. -The root CA certificate is a long-lasting certificate and its private key signs -the intermediate CA certificate. The intermediate CA certificate and the mesh CA -certificate share the same private key. This intermediate private key is used -to sign the mesh certificates. Moreover, the intermediate private key and -therefore the intermediate CA certificate and the mesh CA certificate are -rotated when setting a new manifest.

-

PKI certificate chain

-

Certificate rotation

-

Depending on the configuration of the first manifest, it allows the workload -owner to update the manifest and, therefore, the deployment. -Workload owners and data owners can be mutually untrusted parties. -To protect against the workload owner silently introducing malicious containers, -the Coordinator rotates the intermediate private key every time the manifest is -updated and, therefore, the -intermediate CA certificate and mesh CA certificate. If the user doesn't -trust the workload owner, they use the mesh CA certificate obtained when they -verified the Coordinator and the manifest. This ensures that the user only -connects to workloads defined in the manifest they verified since only those -workloads' certificates are signed with this intermediate private key.

-

Similarly, the service mesh also uses the mesh CA certificate obtained when the -workload was started, so the workload only trusts endpoints that have been -verified by the Coordinator based on the same manifest. Consequently, a -manifest update requires a fresh rollout of the services in the service mesh.

-

Usage of the different certificates

-
    -
  • The root CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This should only be used if the data owner trusts all future updates to the -manifest and workloads. This is, for instance, the case when the workload owner is -the same entity as the data owner.
  • -
  • The mesh CA certificate is returned when verifying the Coordinator. -The data owner can use it to verify the mesh certificates of the workloads. -This certificate is bound to the manifest set when the Coordinator is verified. -If the manifest is updated, the mesh CA certificate changes. -New workloads will receive mesh certificates signed by the new mesh CA certificate. -The Coordinator with the new manifest needs to be verified to retrieve the new mesh CA certificate. -The service mesh also uses the mesh CA certificate to verify the mesh certificates.
  • -
  • The intermediate CA certificate links the root CA certificate to the -mesh certificate so that the mesh certificate can be verified with the root CA -certificate. It's part of the certificate chain handed out by -endpoints in the service mesh.
  • -
  • The mesh certificate is part of the certificate chain handed out by -endpoints in the service mesh. During the startup of a pod, the Initializer -requests a certificate from the Coordinator. This mesh certificate will be returned if the Coordinator successfully -verifies the workload. The mesh certificate -contains X.509 extensions with information from the workloads attestation -document.
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/architecture/observability.html b/pr-preview/pr-1071/next/architecture/observability.html deleted file mode 100644 index 0968644e4c..0000000000 --- a/pr-preview/pr-1071/next/architecture/observability.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - -Observability | Contrast - - - - -
Version: Next

Observability

-

The Contrast Coordinator can expose metrics in the -Prometheus format. These can be monitored to quickly -identify problems in the gRPC layer or attestation errors. Prometheus metrics -are numerical values associated with a name and additional key/values pairs, -called labels.

-

Exposed metrics

-

The metrics can be accessed at the Coordinator pod at the port specified in the -CONTRAST_METRICS_PORT environment variable under the /metrics endpoint. By -default, this environment variable isn't specified, hence no metrics will be -exposed.

-

The Coordinator exports gRPC metrics under the prefix contrast_grpc_server_. -These metrics are labeled with the gRPC service name and method name. -Metrics of interest include contrast_grpc_server_handled_total, which counts -the number of requests by return code, and -contrast_grpc_server_handling_seconds_bucket, which produces a histogram of
-request latency.

-

The gRPC service userapi.UserAPI records metrics for the methods -SetManifest and GetManifest, which get called when setting the -manifest and verifying the -Coordinator respectively.

-

The meshapi.MeshAPI service records metrics for the method NewMeshCert, which -gets called by the Initializer when starting a -new workload. Attestation failures from workloads to the Coordinator can be -tracked with the counter contrast_meshapi_attestation_failures_total.

-

The current manifest generation is exposed as a -gauge with the metric -name contrast_coordinator_manifest_generation. If no manifest is set at the -Coordinator, this counter will be zero.

-

Service mesh metrics

-

The Service Mesh can be configured to expose -metrics via its Envoy admin -interface. Be -aware that the admin interface can expose private information and allows -destructive operations to be performed. To enable the admin interface for the -Service Mesh, set the annotation -contrast.edgeless.systems/servicemesh-admin-interface-port in the configuration -of your workload. If this annotation is set, the admin interface will be started -on this port.

-

To access the admin interface, the ingress settings of the Service Mesh have to -be configured to allow access to the specified port (see Configuring the -Proxy). All metrics will be -exposed under the /stats endpoint. Metrics in Prometheus format can be scraped -from the /stats/prometheus endpoint.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/architecture/secrets.html b/pr-preview/pr-1071/next/architecture/secrets.html deleted file mode 100644 index 3a1acadd0a..0000000000 --- a/pr-preview/pr-1071/next/architecture/secrets.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - -Secrets & recovery | Contrast - - - - -
Version: Next

Secrets & recovery

-

When the Coordinator is configured with the initial manifest, it generates a random secret seed. -From this seed, it uses an HKDF to derive the CA root key and a signing key for the manifest history. -This derivation is deterministic, so the seed can be used to bring any Coordinator to this Coordinator's state.

-

The secret seed is returned to the user on the first call to contrast set, encrypted with the user's public seed share owner key. -If no seed share owner key is provided, a key is generated and stored in the working directory.

-

Persistence

-

The Coordinator runs as a StatefulSet with a dynamically provisioned persistent volume. -This volume stores the manifest history and the associated runtime policies. -The manifest isn't considered sensitive information, because it needs to be passed to the untrusted infrastructure in order to start workloads. -However, the Coordinator must ensure its integrity and that the persisted data corresponds to the manifests set by authorized users. -Thus, the manifest is stored in plain text, but is signed with a private key derived from the Coordinator's secret seed.

-

Recovery

-

When a Coordinator starts up, it doesn't have access to the signing secret and can thus not verify the integrity of the persisted manifests. -It needs to be provided with the secret seed, from which it can derive the signing key that verifies the signatures. -This procedure is called recovery and is initiated by the workload owner. -The CLI decrypts the secret seed using the private seed share owner key, verifies the Coordinator and sends the seed through the Recover method. -The Coordinator recovers its key material and verifies the manifest history signature.

-

Workload Secrets

-

The Coordinator provides each workload a secret seed during attestation. -This secret can be used by the workload to derive additional secrets for example to encrypt persistent data. -Like the workload certificates, it's written to the secrets/workload-secret-seed path under the shared Kubernetes volume contrast-secrets.

-
warning

The workload owner can decrypt data encrypted with secrets derived from the workload secret. -The workload owner can derive the workload secret themselves, since it's derived from the secret seed known to the workload owner. -If the data owner and the workload owner is the same entity, then they can safely use the workload secrets.

-

Secure persistence

-

Remember that persistent volumes from the cloud provider are untrusted. -Using the workload secret, applications can set up trusted storage on top of untrusted block devices. -The following, slightly abbreviated resource outlines how this could be realized:

-
warning

This configuration snippet is intended to be educational and needs to be refined and adapted to your production environment. -Using it as-is may result in data corruption or data loss.

-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: volume-tester
spec:
template:
spec:
containers:
- name: main
image: my.registry/my-image@sha256:0123...
command:
- /bin/sh
- -ec
- | # <-- Custom script that mounts the encrypted disk and then calls the original application.
device=/dev/csi0
if ! cryptsetup isLuks $device; then
cryptsetup luksFormat $device /contrast/secrets/workload-secret-seed
cryptsetup open $device state -d /contrast/secrets/workload-secret-seed
mkfs.ext4 /dev/mapper/state
cryptsetup close state
fi
cryptsetup open $device state -d /contrast/secrets/workload-secret-seed
/path/to/original/app
name: volume-tester
volumeDevices:
- name: state
devicePath: /dev/csi0
securityContext:
privileged: true # <-- This is necessary for mounting devices.
runtimeClassName: contrast-cc
volumeClaimTemplates:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: state
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
volumeMode: Block # <-- The requested volume needs to be a raw block device.
-
note

This example assumes that you can modify the container image to include a shell and the cryptsetup utility. -Alternatively, you can set up a secure mount from a sidecar container inside an emptyDir mount shared with the main container. -The Contrast end-to-end tests include an example of this type of mount.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/architecture/security-considerations.html b/pr-preview/pr-1071/next/architecture/security-considerations.html deleted file mode 100644 index 1a98ac8b17..0000000000 --- a/pr-preview/pr-1071/next/architecture/security-considerations.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Security Considerations | Contrast - - - - -
Version: Next

Security Considerations

-

Contrast ensures application integrity and provides secure means of communication and bootstrapping (see security benefits). -However, care must be taken when interacting with the outside of Contrast's confidential environment. -This page presents some tips for writing secure applications and outlines the trust boundaries app developers need to know.

-

General recommendations

-

Authentication

-

The application receives credentials from the Contrast Coordinator during initialization. -This allows to authenticate towards peers and to verify credentials received from peers. -The application should use the certificate bundle to authenticate incoming requests and be wary of unauthenticated requests or requests with a different root of trust (for example the internet PKI).

-

The recommendation to authenticate not only applies to network traffic, but also to volumes, GPUs and other devices. -Generally speaking, all information provided by the world outside the confidential VM should be treated with due scepticism, especially if it's not authenticated. -Common cases where Kubernetes apps interact with external services include DNS, Kubernetes API clients and cloud storage endpoints.

-

Encryption

-

Any external persistence should be encrypted with an authenticated cipher. -This recommendation applies to block devices or filesystems mounted into the container, but also to cloud blob storage or external databases.

-

Contrast security guarantees

-

If an application authenticates with a certificate signed by the Contrast Mesh CA of a given manifest, Contrast provides the following guarantees:

-
    -
  1. The container images used by the app are the images specified in the resource definitions.
  2. -
  3. The command line arguments of containers are exactly the arguments specified in the resource definitions.
  4. -
  5. All environment variables are either specified in resource definitions, in the container image manifest or in a settings file for the Contrast CLI.
  6. -
  7. The containers run in a confidential VM that matches the reference values in the manifest.
  8. -
  9. The containers' root filesystems are mounted in encrypted memory.
  10. -
-

Limitations inherent to policy checking

-

Workload policies serve as workload identities. -From the perspective of the Contrast Coordinator, all workloads that authenticate with the same policy are equal. -Thus, it's not possible to disambiguate, for example, pods spawned from a deployment or to limit the amount of certificates issued per policy.

-

Container image references from Kubernetes resource definitions are taken into account when generating the policy. -A mutable reference may lead to policy failures or unverified image content, depending on the Contrast runtime. -Reliability and security can only be ensured with a full image reference, including digest. -The docker pull documentation explains pinned image references in detail.

-

Policies can only verify what can be inferred at generation time. -Some attributes of Kubernetes pods can't be predicted and thus can't be verified. -Particularly the downward API contains many fields that are dynamic or depend on the host environment, rendering it unsafe for process environment or arguments. -The same goes for ConfigMap and Secret resources, which can also be used to populate container fields. -If the application requires such external information, it should be injected as a mount point and carefully inspected before use.

-

Another type of dynamic content are persistent volumes. -Any volumes mounted to the pod need to be scrutinized, and sensitive data must not be written to unprotected volumes. -Ideally, a volume is mounted as a raw block device and authenticated encryption is added within the confidential container.

-

Logs

-

By default, container logs are visible to the host. -Sensitive information shouldn't be logged.

-

As of right now, hiding logs isn't natively supported. -If ReadStreamRequest is denied in the policy, the Kata Agent stops reading the logs. -This causes the pipes used for standard out and standard error to fill up and potentially deadlock the container. -If absolutely required, standard out and standard error should be manually redirected to /dev/null inside the container.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/basics/confidential-containers.html b/pr-preview/pr-1071/next/basics/confidential-containers.html deleted file mode 100644 index 6d217966b4..0000000000 --- a/pr-preview/pr-1071/next/basics/confidential-containers.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -Confidential Containers | Contrast - - - - -
Version: Next

Confidential Containers

-

Contrast uses some building blocks from Confidential Containers (CoCo), a CNCF Sandbox project that aims to standardize confidential computing at the pod level. -The project is under active development and many of the high-level features are still in flux. -Contrast uses the more stable core primitive provided by CoCo: its Kubernetes runtime.

-

Kubernetes RuntimeClass

-

Kubernetes can be extended to use more than one container runtime with RuntimeClass objects. -The Container Runtime Interface (CRI) implementation, for example containerd, dispatches pod management API calls to the appropriate RuntimeClass. -RuntimeClass implementations are usually based on an OCI runtime, such as runc, runsc or crun. -In CoCo's case, the runtime is Kata Containers with added confidential computing capabilities.

-

Kata Containers

-

Kata Containers is an OCI runtime that runs pods in VMs. -The pod VM spawns an agent process that accepts management commands from the Kata runtime running on the host. -There are two options for creating pod VMs: local to the Kubernetes node, or remote VMs created with cloud provider APIs. -Using local VMs requires either bare-metal servers or VMs with support for nested virtualization. -Local VMs communicate with the host over a virtual socket. -For remote VMs, host-to-agent communication is tunnelled through the cloud provider's network.

-

Kata Containers was originally designed to isolate the guest from the host, but it can also run pods in confidential VMs (CVMs) to shield pods from their underlying infrastructure. -In confidential mode, the guest agent is configured with an Open Policy Agent (OPA) policy to authorize API calls from the host. -This policy also contains checksums for the expected container images. -It's derived from Kubernetes resource definitions and its checksum is included in the attestation report.

-

AKS CoCo preview

-

Azure Kubernetes Service (AKS) provides CoCo-enabled node pools as a preview offering. -These node pools leverage Azure VM types capable of nested virtualization (CVM-in-VM) and the CoCo stack is pre-installed. -Contrast can be deployed directly into a CoCo-enabled AKS cluster.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/basics/features.html b/pr-preview/pr-1071/next/basics/features.html deleted file mode 100644 index 7b6b614c88..0000000000 --- a/pr-preview/pr-1071/next/basics/features.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Product features | Contrast - - - - -
Version: Next

Product features

-

Contrast simplifies the deployment and management of Confidential Containers, offering optimal data security for your workloads while integrating seamlessly with your existing Kubernetes environment.

-

From a security perspective, Contrast employs the Confidential Containers concept and provides security benefits that go beyond individual containers, shielding your entire deployment from the underlying infrastructure.

-

From an operational perspective, Contrast provides the following key features:

-
    -
  • -

    Managed Kubernetes compatibility: Initially compatible with Azure Kubernetes Service (AKS), Contrast is designed to support additional platforms such as AWS EKS and Google Cloud GKE as they begin to accommodate confidential containers.

    -
  • -
  • -

    Lightweight installation: Contrast can be integrated as a day-2 operation within existing clusters, adding minimal components to your setup. This facilitates straightforward deployments using your existing YAML configurations, Helm charts, or Kustomization, enabling native Kubernetes orchestration of your applications.

    -
  • -
  • -

    Remote attestation: Contrast generates a concise attestation statement that verifies the identity, authenticity, and integrity of your deployment both internally and to external parties. This architecture ensures that updates or scaling of the application don't compromise the attestation’s validity.

    -
  • -
  • -

    Service mesh: Contrast securely manages a Public Key Infrastructure (PKI) for your deployments, issues workload-specific certificates, and establishes transparent mutual TLS (mTLS) connections across pods. This is done by harnessing the envoy proxy to ensure secure communications within your Kubernetes cluster.

    -
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/basics/security-benefits.html b/pr-preview/pr-1071/next/basics/security-benefits.html deleted file mode 100644 index 5879bd10b3..0000000000 --- a/pr-preview/pr-1071/next/basics/security-benefits.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - -Contrast security overview | Contrast - - - - -
Version: Next

Contrast security overview

-

This document outlines the security measures of Contrast and its capability to counter various threats. -Contrast is designed to shield entire Kubernetes deployments from the infrastructure, enabling entities to manage sensitive information (such as regulated or personally identifiable information (PII)) in the public cloud, while maintaining data confidentiality and ownership.

-

Contrast is applicable in situations where establishing trust with the workload operator or the underlying infrastructure is challenging. -This is particularly beneficial for regulated sectors looking to transition sensitive activities to the cloud, without sacrificing security or compliance. -It allows for cloud adoption by maintaining a hardware-based separation from the cloud service provider.

-

Confidential computing foundation

-

Leveraging Confidential Computing technology, Contrast provides three defining security properties:

-
    -
  • Encryption of data in use: Contrast ensures that all data processed in memory is encrypted, making it inaccessible to unauthorized users or systems, even if they have physical access to the hardware.
  • -
  • Workload isolation: Each pod runs in its isolated runtime environment, preventing any cross-contamination between workloads, which is critical for multi-tenant infrastructures.
  • -
  • Remote attestation: This feature allows data owners and workload operators to verify that the Contrast environment executing their workloads hasn't been tampered with and is running in a secure, pre-approved configuration.
  • -
-

The runtime encryption is transparently provided by the confidential computing hardware during the workload's lifetime. -The workload isolation and remote attestation involves two phases:

-
    -
  • An attestation process detects modifications to the workload image or its runtime environment during the initialization. This protects the workload's integrity pre-attestation.
  • -
  • A protected runtime environment and a policy mechanism prevents the platform operator from accessing or compromising the instance at runtime. This protects a workload's integrity and confidentiality post-attestation.
  • -
-

For more details on confidential computing see our whitepaper. -The attestation architecture describes Contrast's attestation process and the resulting chain of trust in detail.

-

Components of a Contrast deployment

-

Contrast uses the Kubernetes runtime of the Confidential Containers project. -Confidential Containers significantly decrease the size of the trusted computing base (TCB) of a Kubernetes deployment, by isolating each pod within its own confidential micro-VM environment. -The TCB is the totality of elements in a computing environment that must be trusted not to be compromised. -A smaller TCB results in a smaller attack surface. The following diagram shows how Confidential Containers remove the cloud & datacenter infrastructure and the physical hosts, including the hypervisor, the host OS, the Kubernetes control plane, and other components, from the TCB (red). -In the confidential context, depicted in green, only the workload containers along with their confidential micro-VM environment are included within the TCB. -Their integrity is verifiable through remote attestation.

-

Contrast uses hardware-based mechanisms, specifically leveraging CPU features, such as AMD SEV or Intel TDX, to provide the isolation of the workload. -This implies that both the CPU and its microcode are integral components of the TCB. -However, it should be noted that the CPU microcode aspects aren't depicted in the accompanying graphic.

-

TCB comparison

-

Contrast adds the following components to a deployment that become part of the TCB. -The components that are part of the TCB are:

-
    -
  • The workload containers: Container images that run the actual application.
  • -
  • The runtime environment: The confidential micro-VM that acts as the container runtime.
  • -
  • The sidecar containers: Containers that provide additional functionality such as initialization and service mesh.
  • -
  • The runtime policies: Policies that enforce the runtime environments for the workload containers during their lifetime.
  • -
  • The manifest: A manifest file defining the reference values of an entire confidential deployment. It contains the policy hashes for all pods of the deployment and the expected hardware reference values for the Confidential Container runtime.
  • -
  • The Coordinator: An attestation service that runs in a Confidential Container in the Kubernetes cluster. The Coordinator is configured with the manifest. User-facing, you can verify this service and the effective manifest using remote attestation, providing you with a concise attestation for the entire deployment. Cluster-facing, it verifies all pods and their policies based on remote attestation procedures and the manifest.
  • -
-

Personas in a Contrast deployment

-

In a Contrast deployment, there are three parties:

-
    -
  • -

    The container image provider, who creates the container images that represent the application that has access to the protected data.

    -
  • -
  • -

    The workload operator, who runs the workload in a Kubernetes cluster. The operator typically has full administrative privileges to the deployment. The operator can manage cluster resources such as nodes, volumes, and networking rules, and the operator can interact with any Kubernetes or underlying cloud API.

    -
  • -
  • -

    The data owner, who owns the protected data. A data owner can verify the deployment using the Coordinator attestation service. The verification includes the identity, integrity, and confidentiality of the workloads, the runtime environment and the access permissions.

    -
  • -
-

Contrast supports a trust model where the container image provider, workload operator, and data owner are separate, mutually distrusting parties.

-

The following diagram shows the system components and parties.

-

Components and parties

-

Threat model and mitigations

-

This section describes the threat vectors that Contrast helps to mitigate.

-

The following attacks are out of scope for this document:

-
    -
  • Attacks on the application code itself, such as insufficient access controls.
  • -
  • Attacks on the Confidential Computing hardware directly, such as side-channel attacks.
  • -
  • Attacks on the availability, such as denial-of-service (DOS) attacks.
  • -
-

Possible attacks

-

Contrast is designed to defend against five possible attacks:

-
    -
  • A malicious cloud insider: malicious employees or third-party contractors of cloud service providers (CSPs) potentially have full access to various layers of the cloud infrastructure. That goes from the physical datacenter up to the hypervisor and Kubernetes layer. For example, they can access the physical memory of the machines, modify the hypervisor, modify disk contents, intercept network communications, and attempt to compromise the confidential container at runtime. A malicious insider can expand the attack surface or restrict the runtime environment. For example, a malicious operator can add a storage device to introduce new attack vectors. As another example, a malicious operator can constrain resources such as limiting a guest's memory size, changing its disk space, or changing firewall rules.
  • -
  • A malicious cloud co-tenant: malicious cloud user ("hackers") may break out of their tenancy and access other tenants' data. Advanced attackers may even be able to establish a permanent foothold within the infrastructure and access data over a longer period. The threats are analogous to the cloud insider access scenario, without the physical access.
  • -
  • A malicious workload operator: malicious workload operators, for example Kubernetes administrators, have full access to the workload deployment and the underlying Kubernetes platform. The threats are analogously to the cloud insider access scenario, with access to everything that's above the hypervisor level.
  • -
  • A malicious attestation client: this attacker connects to the attestation service and sends malformed request.
  • -
  • A malicious container image provider: a malicious container image provider has full control over the application development itself. This attacker might release a malicious version of the workload containing harmful operations.
  • -
-

Attack surfaces

-

The following table describes the attack surfaces that are available to attackers.

-
AttackerTargetAttack surfaceRisks
Cloud insiderConfidential Container, WorkloadPhysical memoryAttacker can dump the physical memory of the workloads.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk readsAnything read from the disk is within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadDisk writesAnything written to disk is visible to an attacker.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadKubernetes Control PlaneInstance attributes read from the Kubernetes control plane, including mount points and environment variables, are within the attacker's control.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadContainer RuntimeThe attacker can use container runtime APIs (for example "kubectl exec") to perform operations on the workload container.
Cloud insider, cloud hacker, workload operatorConfidential Container, WorkloadNetworkIntra-deployment (between containers) as well as external network connections to the image repository or attestation service can be intercepted.
Attestation clientCoordinator attestation serviceAttestation requestsThe attestation service has complex, crypto-heavy logic that's challenging to write defensively.
Container image providerWorkloadWorkloadThis attacker might release an upgrade to the workload containing harmful changes, such as a backdoor.
-

Threats and mitigations

-

Contrast shields a workload from the aforementioned threats with three main components:

-
    -
  1. The runtime environment safeguards against the physical memory and disk attack surface.
  2. -
  3. The runtime policies safeguard against the Kubernetes control plane and container runtime attack surface.
  4. -
  5. The service mesh safeguards against the network attack surface.
  6. -
-

The following tables describe concrete threats and how they're mitigated in Contrast grouped by these categories:

-
    -
  • Attacks on the confidential container environment
  • -
  • Attacks on the attestation service
  • -
  • Attacks on workloads
  • -
-

Attacks on the confidential container environment

-

This table describes potential threats and mitigation strategies related to the confidential container environment.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection of the launcher or image repository.An attacker can change the image URL and control the workload binary. However these actions are reflected in the attestation report. The image repository isn't controlled using an access list, therefore the image is assumed to be viewable by everyone. You must ensure that the workload container image doesn't contain any secrets.Within the runtime policies and attestation
An attacker modifies the workload image on disk after it was downloaded and measured.This threat is mitigated by a read-only partition that's integrity-protected. The workload image is protected by dm-verity.Within the Contrast runtime environment
An attacker modifies a container's runtime environment configuration in the Kubernetes control plane.The attestation process and the runtime policies detects unsafe configurations that load non-authentic images or perform any other modification to the expected runtime environment.Within the runtime policies and attestation
-

Attacks on the Coordinator attestation service

-

This table describes potential threats and mitigation strategies to the attestation service.

-
ThreatMitigationMitigation implementation
An attacker intercepts the Coordinator deployment and modifies the image or hijacks the runtime environment.This threat is mitigated by having an attestation procedure and attested, encrypted TLS connections to the Coordinator. The attestation evidence for the Coordinator image is distributed with our releases, protected by supply chain security, and fully reproducible.Within the attestation
An attacker intercepts the network connection between the workload and the Coordinator and reads secret keys from the wire.This threat is mitigated by having an attested, encrypted TLS connection. This connection helps protect the secrets from passive eavesdropping. The attacker can't create valid workload certificates that would be accepted in Contrast's service mesh. An attacker can't impersonate a valid workload container because the container's identity is guaranteed by the attestation protocol.Within the network between your workload and the Coordinator.
An attacker exploits parsing discrepancies, which leads to undetected changes in the attestation process.This risk is mitigated by having a parsing engine written in memory-safe Go that's tested against the attestation specification of the hardware vendor. The runtime policies are available as an attestation artifact for further inspection and audits to verify their effectiveness.Within the Coordinator
An attacker uses all service resources, which brings the Coordinator down in a denial of service (DoS) attack.In the future, this reliability risk is mitigated by having a distributed Coordinator service that can be easily replicated and scaled out as needed.Within the Coordinator
-

Attacks on workloads

-

This table describes potential threats and mitigation strategies related to workloads.

-
ThreatMitigationMitigation implementation
An attacker intercepts the network connection between two workload containers.This threat is mitigated by having transparently encrypted TLS connections between the containers in your deployment.Within the service mesh
An attacker reads or modifies data written to disk via persistent volumes.Currently, persistent volumes aren't supported in Contrast. In the future, this threat is mitigated by encrypted and integrity-protected volume mounts.Within the Contrast runtime environment
An attacker publishes a new image version containing malicious code.The attestation process and the runtime policies require a data owner to accept a specific version of the workload and any update to the workload needs to be explicitly acknowledged.Within the attestation
-

Examples of Contrast's threat model in practice

-

The following table describes three example use cases and how they map to the defined threat model in this document:

-
Use CaseExample Scenario
Migrate sensitive workloads to the cloudTechSolve Inc., a software development firm, aimed to enhance its defense-in-depth strategy for its cloud-based development environment, especially for projects involving proprietary algorithms and client data. TechSolve acts as the image provider, workload operator, and data owner, combining all three personas in this scenario. In our attestation terminology, they're the workload operator and relying party in one entity. Their threat model includes a malicious cloud insider and cloud co-tenant.
Make your SaaS more trustworthySaaSProviderX, a company offering cloud-based project management tools, sought to enhance its platform's trustworthiness amidst growing concerns about data breaches and privacy. Here, the relying party is the SaaS customer as the data owner. The goal is to achieve a form of operator exclusion and only allow selective operations on the deployment. Hence, their threat model includes a malicious workload operator.
Simplify regulatory complianceHealthSecure Inc. has been managing a significant volume of sensitive patient data on-premises. With the increasing demand for advanced data analytics and the need for scalable infrastructure, the firm decides to migrate its data analytics operations to the cloud. However, the primary concern is maintaining the confidentiality and security of patient data during and after the migration, in compliance with healthcare regulations. In this compliance scenario, the regulator serves as an additional relying party. HealthSecure must implement a mechanism that ensures the isolation of patient data can be verifiably guaranteed to the regulator.
-

In each scenario, Contrast ensures exclusive data access and processing capabilities are confined to the designated workloads. It achieves this by effectively isolating the workload from the infrastructure and other components of the stack. Data owners are granted the capability to audit and approve the deployment environment before submitting their data, ensuring a secure handover. Meanwhile, workload operators are equipped to manage and operate the application seamlessly, without requiring direct access to either the workload or its associated data.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/components/overview.html b/pr-preview/pr-1071/next/components/overview.html deleted file mode 100644 index 448e22a39b..0000000000 --- a/pr-preview/pr-1071/next/components/overview.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - -Components | Contrast - - - - -
Version: Next

Components

-

Contrast is composed of several key components that work together to manage and scale confidential containers effectively within Kubernetes environments. -This page provides an overview of the core components essential for deploying and managing Contrast.

-

components overview

-

The CLI (Command Line Interface)

-

The CLI serves as the primary management tool for Contrast deployments. It's designed to streamline the configuration and operation of Contrast in several ways:

-
    -
  • Installation and setup: The CLI facilitates the installation of the necessary runtime classes required for Contrast to function within a Kubernetes cluster.
  • -
  • Policy generation: It allows users to generate runtime policies, adapt the deployment files, and generate the Contrast manifest.
  • -
  • Configuration management: Through the CLI, users can configure the Contrast Coordinator with the generated manifest.
  • -
  • Verification and attestation: The CLI provides tools to verify the integrity and authenticity of the Coordinator and the entire deployment via remote attestation.
  • -
-

The Coordinator

-

The Contrast Coordinator is the central remote attestation service of a Contrast deployment. -It runs inside a confidential container inside your cluster. -The Coordinator can be verified via remote attestation, and a Contrast deployment is self-contained. -The Coordinator is configured with a manifest, a configuration file containing the reference attestation values of your deployment. -It ensures that your deployment's topology adheres to your specified manifest by verifying the identity and integrity of all confidential pods inside the deployment. -The Coordinator is also a certificate authority and issues certificates for your workload pods during the attestation procedure. -Your workload pods can establish secure, encrypted communication channels between themselves based on these certificates using the Coordinator as the root CA. -As your app needs to scale, the Coordinator transparently verifies new instances and then provides them with their certificates to join the deployment.

-

To verify your deployment, the Coordinator's remote attestation statement combined with the manifest offers a concise single remote attestation statement for your entire deployment. -A third party can use this to verify the integrity of your distributed app, making it easy to assure stakeholders of your app's identity and integrity.

-

The Manifest

-

The manifest is the configuration file for the Coordinator, defining your confidential deployment. -It's automatically generated from your deployment by the Contrast CLI. -It currently consists of the following parts:

-
    -
  • Policies: The identities of your Pods, represented by the hashes of their respective runtime policies.
  • -
  • Reference Values: The remote attestation reference values for the Kata confidential micro-VM that's the runtime environment of your Pods.
  • -
  • WorkloadOwnerKeyDigest: The workload owner's public key digest. Used for authenticating subsequent manifest updates.
  • -
-

Runtime policies

-

Runtime Policies are a mechanism to enable the use of the untrusted Kubernetes API for orchestration while ensuring the confidentiality and integrity of your confidential containers. -They allow us to enforce the integrity of your containers' runtime environment as defined in your deployment files. -The runtime policy mechanism is based on the Open Policy Agent (OPA) and translates the Kubernetes deployment YAML into the Rego policy language of OPA. -The Kata Agent inside the confidential micro-VM then enforces the policy by only acting on permitted requests. -The Contrast CLI provides the tooling for automatically translating Kubernetes deployment YAML into the Rego policy language of OPA.

-

The Initializer

-

Contrast provides an Initializer that handles the remote attestation on the workload side transparently and -fetches the workload certificate. The Initializer runs as an init container before your workload is started. -It provides the workload container and the service mesh sidecar with the workload certificates.

-

The Contrast runtime

-

Contrast depends on a Kubernetes runtime class, which is installed -by the node-installer DaemonSet. -This runtime consists of a containerd runtime plugin, a virtual machine manager (cloud-hypervisor), and a podvm image (IGVM and rootFS). -The installer takes care of provisioning every node in the cluster so it provides this runtime class.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/components/policies.html b/pr-preview/pr-1071/next/components/policies.html deleted file mode 100644 index 807526e6bb..0000000000 --- a/pr-preview/pr-1071/next/components/policies.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - -Policies | Contrast - - - - -
Version: Next

Policies

-

Kata runtime policies are an integral part of the Confidential Containers preview on AKS. -They prescribe how a Kubernetes pod must be configured to launch successfully in a confidential VM. -In Contrast, policies act as a workload identifier: only pods with a policy registered in the manifest receive workload certificates and may participate in the confidential deployment. -Verification of the Contrast Coordinator and its manifest transitively guarantees that all workloads meet the owner's expectations.

-

Structure

-

The Kata agent running in the confidential micro-VM exposes an RPC service AgentService to the Kata runtime. -This service handles potentially untrustworthy requests from outside the TCB, which need to be checked against a policy.

-

Kata runtime policies are written in the policy language Rego. -They specify what AgentService methods can be called, and the permissible parameters for each call.

-

Policies consist of two parts: a list of rules and a data section. -While the list of rules is static, the data section is populated with information from the PodSpec and other sources.

-

Generation

-

Runtime policies are programmatically generated from Kubernetes manifests by the Contrast CLI. -The generate subcommand inspects pod definitions and derives rules for validating the pod at the Kata agent. -There are two important integrity checks: container image checksums and OCI runtime parameters.

-

For each of the container images used in a pod, the CLI downloads all image layers and produces a cryptographic dm-verity checksum. -These checksums are the basis for the policy's storage data.

-

The CLI combines information from the PodSpec, ConfigMaps, and Secrets in the provided Kubernetes manifests to derive a permissible set of command-line arguments and environment variables. -These constitute the policy's OCI data.

-

Evaluation

-

The generated policy document is annotated to the pod definitions in Base64 encoding. -This annotation is propagated to the Kata runtime, which calculates the SHA256 checksum for the policy and uses that as SNP HOSTDATA or TDX MRCONFIGID for the confidential micro-VM.

-

After the VM launched, the runtime calls the agent's SetPolicy method with the full policy document. -If the policy doesn't match the checksum in HOSTDATA or MRCONFIGID, the agent rejects the policy. -Otherwise, it applies the policy to all future AgentService requests.

-

Guarantees

-

The policy evaluation provides the following guarantees for pods launched with the correct generated policy:

-
    -
  • Command and its arguments are set as specified in the resources.
  • -
  • There are no unexpected additional environment variables.
  • -
  • The container image layers correspond to the layers observed at policy generation time. -Thus, only the expected workload image can be instantiated.
  • -
  • Executing additional processes in a container is prohibited.
  • -
  • Sending data to a container's standard input is prohibited.
  • -
-

The current implementation of policy checking has some blind spots:

-
    -
  • Containers can be started in any order, or be omitted entirely.
  • -
  • Environment variables may be missing.
  • -
  • Volumes other than the container root volume don't have integrity checks (particularly relevant for mounted ConfigMaps and Secrets).
  • -
-

Trust

-

Contrast verifies its confidential containers following these steps:

-
    -
  1. The Contrast CLI generates a policy and attaches it to the pod definition.
  2. -
  3. Kubernetes schedules the pod on a node with the confidential computing runtime.
  4. -
  5. Containerd invokes the Kata runtime to create the pod sandbox.
  6. -
  7. The Kata runtime starts a CVM with the policy's digest as HOSTDATA/MRCONFIGID.
  8. -
  9. The Kata runtime sets the policy using the SetPolicy method.
  10. -
  11. The Kata agent verifies that the incoming policy's digest matches HOSTDATA/MRCONFIGID.
  12. -
  13. The CLI sets a manifest in the Contrast Coordinator, including a list of permitted policies.
  14. -
  15. The Contrast Initializer sends an attestation report to the Contrast Coordinator, asking for a mesh certificate.
  16. -
  17. The Contrast Coordinator verifies that the started pod has a permitted policy hash in its HOSTDATA/MRCONFIGID field.
  18. -
-

After the last step, we know that the policy hasn't been tampered with and, thus, that the workload matches expectations and may receive mesh certificates.

-

Platform Differences

-

Contrast uses different rules and data sections for different platforms. -This results in different policy hashes for different platforms.

-

The generate command automatically derives the correct set of rules and data sections from the reference-values flag.

-

The verify, set, and recover commands need to know the coordinator's expected policy hash to verify its identity. -By default these commands assume that the coordinator is using the policy for the AKS-CLH-SNP platform. -If the coordinator is running on a different platform, the correct policy hash can be looked up in the coordinator-policy.hash file bundled with the Contrast release. -The coordinator policy hash can be overwritten using the --coordinator-policy-hash flag.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/components/runtime.html b/pr-preview/pr-1071/next/components/runtime.html deleted file mode 100644 index aafa1c8d33..0000000000 --- a/pr-preview/pr-1071/next/components/runtime.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - -Contrast Runtime | Contrast - - - - -
Version: Next

Contrast Runtime

-

The Contrast runtime is responsible for starting pods as confidential virtual machines. -This works by specifying the runtime class to be used in a pod spec and by registering the runtime class with the apiserver. -The RuntimeClass resource defines a name for referencing the class and -a handler used by the container runtime (containerd) to identify the class.

-
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# This name is used by pods in the runtimeClassName field
name: contrast-cc-abcdef
# This name is used by the
# container runtime interface implementation (containerd)
handler: contrast-cc-abcdef
-

Confidential pods that are part of a Contrast deployment need to specify the -same runtime class in the runtimeClassName field, so Kubernetes uses the -Contrast runtime instead of the default containerd / runc handler.

-
apiVersion: v1
kind: Pod
spec:
runtimeClassName: contrast-cc-abcdef
# ...
-

Node-level components

-

The runtime consists of additional software components that need to be installed -and configured on every SEV-SNP-enabled/TDX-enabled worker node. -This installation is performed automatically by the node-installer DaemonSet.

-

Runtime components

-

Containerd shim

-

The handler field in the Kubernetes RuntimeClass instructs containerd not to use the default runc implementation. -Instead, containerd invokes a custom plugin called containerd-shim-contrast-cc-v2. -This shim is described in more detail in the upstream source repository and in the containerd documentation.

-

Virtual machine manager (VMM)

-

The containerd shim uses a virtual machine monitor to create a confidential virtual machine for every pod. -On AKS, Contrast uses cloud-hypervisor. -On bare metal, Contrast uses QEMU. -The appropriate files are installed on every node by the node-installer.

-

Snapshotters

-

Contrast uses containerd snapshotters to provide container images to the pod-VM. -Each snapshotter consists of a host component that pulls container images and a guest component used to mount/pull container images.

-

On AKS, Contrast uses the tardev snapshotter to provide container images as block devices to the pod-VM. -The tardev snapshotter uses dm-verity to protect the integrity of container images. -Expected dm-verity container image hashes are part of Contrast runtime policies and are enforced by the kata-agent. -This enables workload attestation by specifying the allowed container image as part of the policy. Read the chapter on policies for more information.

-

On bare metal, Contrast uses the nydus snapshotter to store metadata about the images. This metadata is communicated to the guest, so that it can pull the images itself.

-

Pod-VM image

-

Every pod-VM starts with the same guest image. It consists of an IGVM file and a root filesystem. -The IGVM file describes the initial memory contents of a pod-VM and consists of:

-
    -
  • Linux kernel image
  • -
  • initrd
  • -
  • kernel commandline
  • -
-

Additionally, a root filesystem image is used that contains a read-only partition with the user space of the pod-VM and a verity partition to guarantee the integrity of the root filesystem. -The root filesystem contains systemd as the init system, and the kata agent for managing the pod.

-

This pod-VM image isn't specific to any pod workload. Instead, container images are mounted at runtime.

-

Node installer DaemonSet

-

The RuntimeClass resource above registers the runtime with the Kubernetes api. -The node-level installation is carried out by the Contrast node-installer -DaemonSet that ships with every Contrast release.

-

After deploying the installer, it performs the following steps on each node:

-
    -
  • Install the Contrast containerd shim (containerd-shim-contrast-cc-v2)
  • -
  • Install cloud-hypervisor or QEMU as the virtual machine manager (VMM)
  • -
  • Install an IGVM file or separate firmware and kernel files for pod-VMs of this class
  • -
  • Install a read only root filesystem disk image for the pod-VMs of this class
  • -
  • Reconfigure containerd by adding a runtime plugin that corresponds to the handler field of the Kubernetes RuntimeClass
  • -
  • Restart containerd to make it aware of the new plugin
  • -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/components/service-mesh.html b/pr-preview/pr-1071/next/components/service-mesh.html deleted file mode 100644 index e619aa0c82..0000000000 --- a/pr-preview/pr-1071/next/components/service-mesh.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -Service mesh | Contrast - - - - -
Version: Next

Service mesh

-

The Contrast service mesh secures the communication of the workload by automatically -wrapping the network traffic inside mutual TLS (mTLS) connections. The -verification of the endpoints in the connection establishment is based on -certificates that are part of the -PKI of the Coordinator.

-

The service mesh can be enabled on a per-workload basis by adding a service mesh -configuration to the workload's object annotations. During the contrast generate -step, the service mesh is added as a sidecar -container to -all workloads which have a specified configuration. The service mesh container first -sets up iptables rules based on its configuration and then starts -Envoy for TLS origination and termination.

-

Configuring the proxy

-

The service mesh container can be configured using the following object annotations:

-
    -
  • contrast.edgeless.systems/servicemesh-ingress to configure ingress.
  • -
  • contrast.edgeless.systems/servicemesh-egress to configure egress.
  • -
  • contrast.edgeless.systems/servicemesh-admin-interface-port to configure the Envoy -admin interface. If not specified, no admin interface will be started.
  • -
-

If you aren't using the automatic service mesh injection and want to configure the -service mesh manually, set the environment variables CONTRAST_INGRESS_PROXY_CONFIG, -CONTRAST_EGRESS_PROXY_CONFIG and CONTRAST_ADMIN_PORT in the service mesh sidecar directly.

-

Ingress

-

All TCP ingress traffic is routed over Envoy by default. Since we use -TPROXY, the destination address -remains the same throughout the packet handling.

-

Any incoming connection is required to present a client certificate signed by the -mesh CA certificate. -Envoy presents a certificate chain of the mesh -certificate of the workload and the intermediate CA certificate as the server certificate.

-

If the deployment contains workloads which should be reachable from outside the -Service Mesh, while still handing out the certificate chain, disable client -authentication by setting the annotation contrast.edgeless.systems/servicemesh-ingress as -<name>#<port>#false. Separate multiple entries with ##. You can choose any -descriptive string identifying the service on the given port for the <name> field, -as it's only informational.

-

Disable redirection and TLS termination altogether by specifying -<name>#<port>#true. This can be beneficial if the workload itself handles TLS -on that port or if the information exposed on this port is non-sensitive.

-

The following example workload exposes a web service on port 8080 and metrics on -port 7890. The web server is exposed to a 3rd party end-user which wants to -verify the deployment, therefore it's still required that the server hands out -it certificate chain signed by the mesh CA certificate. The metrics should be -exposed via TCP without TLS.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-ingress: "web#8080#false##metrics#7890#true"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: web-svc
image: ghcr.io/edgelesssys/frontend:v1.2.3@...
ports:
- containerPort: 8080
name: web
- containerPort: 7890
name: metrics
-

When invoking contrast generate, the resulting deployment will be injected with the -Contrast service mesh as an init container.

-
# ...
initContainers:
- env:
- name: CONTRAST_INGRESS_PROXY_CONFIG
value: "web#8080#false##metrics#7890#true"
image: "ghcr.io/edgelesssys/contrast/service-mesh-proxy:latest"
name: contrast-service-mesh
restartPolicy: Always
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- name: contrast-secrets
mountPath: /contrast
-

Note, that changing the environment variables of the sidecar container directly will -only have an effect if the workload isn't configured to automatically generate a -service mesh component on contrast generate. Otherwise, the service mesh sidecar -container will be regenerated on every invocation of the command.

-

Egress

-

To be able to route the egress traffic of the workload through Envoy, the remote -endpoints' IP address and port must be configurable.

-
    -
  • Choose an IP address inside the 127.0.0.0/8 CIDR and a port not yet in use -by the pod.
  • -
  • Configure the workload to connect to this IP address and port.
  • -
  • Set <name>#<chosen IP>:<chosen port>#<original-hostname-or-ip>:<original-port> -as the contrast.edgeless.systems/servicemesh-egress workload annotation. Separate multiple -entries with ##. Choose any string identifying the service on the given port as -<name>.
  • -
-

This redirects the traffic over Envoy. The endpoint must present a valid -certificate chain which must be verifiable with the -mesh CA certificate. -Furthermore, Envoy uses a certificate chain with the mesh certificate of the workload -and the intermediate CA certificate as the client certificate.

-

The following example workload has no ingress connections and two egress -connection to different microservices. The microservices are part -of the confidential deployment. One is reachable under billing-svc:8080 and -the other under cart-svc:8080.

-
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
annotations:
contrast.edgeless.systems/servicemesh-egress: "billing#127.137.0.1:8081#billing-svc:8080##cart#127.137.0.2:8081#cart-svc:8080"
spec:
replicas: 1
template:
spec:
runtimeClassName: contrast-cc
containers:
- name: currency-conversion
image: ghcr.io/edgelesssys/conversion:v1.2.3@...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/deployment.html b/pr-preview/pr-1071/next/deployment.html deleted file mode 100644 index 1950ae342e..0000000000 --- a/pr-preview/pr-1071/next/deployment.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - -Workload deployment | Contrast - - - - -
Version: Next

Workload deployment

-

The following instructions will guide you through the process of making an existing Kubernetes deployment -confidential and deploying it together with Contrast.

-

A running CoCo-enabled cluster is required for these steps, see the setup guide on how to set up a cluster on AKS.

-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass (contrast-cc), -which needs to be installed in the cluster prior to the Coordinator or any confidential workloads. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Install the latest Contrast Coordinator release, comprising a single replica deployment and a -LoadBalancer service, into your cluster.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-aks-clh-snp.yml
-

Prepare your Kubernetes resources

-

Your Kubernetes resources need some modifications to run as Confidential Containers. -This section guides you through the process and outlines the necessary changes.

-

Security review

-

Contrast ensures integrity and confidentiality of the applications, but interactions with untrusted systems require the developers' attention. -Review the security considerations and the certificates section for writing secure Contrast application.

-

RuntimeClass

-

Contrast will add annotations to your Kubernetes YAML files. If you want to keep the original files -unchanged, you can copy the files into a separate local directory. -You can also generate files from a Helm chart or from a Kustomization.

-
mkdir resources
kustomize build $MY_RESOURCE_DIR > resources/all.yml
-

To specify that a workload (pod, deployment, etc.) should be deployed as confidential containers, -add runtimeClassName: contrast-cc to the pod spec (pod definition or template). -This is a placeholder name that will be replaced by a versioned runtimeClassName when generating policies.

-
spec: # v1.PodSpec
runtimeClassName: contrast-cc
-

Handling TLS

-

In the initialization process, the contrast-secrets shared volume is populated with X.509 certificates for your workload. -These certificates are used by the Contrast Service Mesh, but can also be used by your application directly. -The following tab group explains the setup for both scenarios.

-

Contrast can be configured to handle TLS in a sidecar container. -This is useful for workloads that are hard to configure with custom certificates, like Java applications.

Configuration of the sidecar depends heavily on the application. -The following example is for an application with these properties:

    -
  • The container has a main application at TCP port 8001, which should be TLS-wrapped and doesn't require client authentication.
  • -
  • The container has a metrics endpoint at TCP port 8080, which should be accessible in plain text.
  • -
  • All other endpoints require client authentication.
  • -
  • The app connects to a Kubernetes service backend.default:4001, which requires client authentication.
  • -

Add the following annotations to your workload:

metadata: # apps/v1.Deployment, apps/v1.DaemonSet, ...
annotations:
contrast.edgeless.systems/servicemesh-ingress: "main#8001#false##metrics#8080#true"
contrast.edgeless.systems/servicemesh-egress: "backend#127.0.0.2:4001#backend.default:4001"

During the generate step, this configuration will be translated into a Service Mesh sidecar container which handles TLS connections automatically. -The only change required to the app itself is to let it connect to 127.0.0.2:4001 to reach the backend service. -You can find more detailed documentation in the Service Mesh chapter.

-

Generate policy annotations and manifest

-

Run the generate command to add the necessary components to your deployment files. -This will add the Contrast Initializer to every workload with the specified contrast-cc runtime class -and the Contrast Service Mesh to all workloads that have a specified configuration. -After that, it will generate the execution policies and add them as annotations to your deployment files. -A manifest.json with the reference values of your deployment will be created.

-
contrast generate --reference-values aks-clh-snp resources/
-
warning

Please be aware that runtime policies currently have some blind spots. For example, they can't guarantee the starting order of containers. See the current limitations for more details.

-

If you don't want the Contrast Initializer to automatically be added to your -workloads, there are two ways you can skip the Initializer injection step, -depending on how you want to customize your deployment.

-

You can disable the Initializer injection completely by specifying the ---skip-initializer flag in the generate command.

contrast generate --reference-values aks-clh-snp --skip-initializer resources/
-

When disabling the automatic Initializer injection, you can manually add the -Initializer as a sidecar container to your workload before generating the -policies. Configure the workload to use the certificates written to the -contrast-secrets volumeMount.

-
# v1.PodSpec
spec:
initContainers:
- env:
- name: COORDINATOR_HOST
value: coordinator
image: "ghcr.io/edgelesssys/contrast/initializer:latest"
name: contrast-initializer
volumeMounts:
- mountPath: /contrast
name: contrast-secrets
volumes:
- emptyDir: {}
name: contrast-secrets
-

Apply the resources

-

Apply the resources to the cluster. Your workloads will block in the initialization phase until a -manifest is set at the Coordinator.

-
kubectl apply -f resources/
-

Connect to the Contrast Coordinator

-

For the next steps, we will need to connect to the Coordinator. The released Coordinator resource -includes a LoadBalancer definition we can use.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
-
Port-forwarding of Confidential Containers

kubectl port-forward uses a Container Runtime Interface (CRI) method that isn't supported by the Kata shim. -If you can't use a public load balancer, you can deploy a port-forwarder. -The port-forwarder relays traffic from a CoCo pod and can be accessed via kubectl port-forward.

Upstream tracking issue: https://github.com/kata-containers/kata-containers/issues/1693.

-

Set the manifest

-

Attest the Coordinator and set the manifest:

-
contrast set -c "${coordinator}:1313" resources/
-

This will use the reference values from the manifest file to attest the Coordinator. -After this step, the Coordinator will start issuing TLS certificates to the workloads. The init container -will fetch a certificate for the workload and the workload is started.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Verify the Coordinator

-

An end user (data owner) can verify the Contrast deployment using the verify command.

-
contrast verify -c "${coordinator}:1313"
-

The CLI will attest the Coordinator using the reference values from the given manifest file. It will then write the -service mesh root certificate and the history of manifests into the verify/ directory. In addition, the policies -referenced in the active manifest are also written to the directory. The verification will fail if the active -manifest at the Coordinator doesn't match the manifest passed to the CLI.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Communicate with workloads

-

You can securely connect to the workloads using the Coordinator's mesh-ca.pem as a trusted CA certificate. -First, expose the service on a public IP address via a LoadBalancer service:

-
kubectl patch svc ${MY_SERVICE} -p '{"spec": {"type": "LoadBalancer"}}'
kubectl wait --timeout=30s --for=jsonpath='{.status.loadBalancer.ingress}' service/${MY_SERVICE}
lbip=$(kubectl get svc ${MY_SERVICE} -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $lbip
-
Subject alternative names and LoadBalancer IP

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the SAN field. -Validation fails since the certificate contains no IP entries as a subject alternative name (SAN). -For example, attempting to connect with curl and the mesh CA certificate will throw the following error:

$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Recover the Coordinator

-

If the Contrast Coordinator restarts, it enters recovery mode and waits for an operator to provide key material. -For demonstration purposes, you can simulate this scenario by deleting the Coordinator pod.

-
kubectl delete pod -l app.kubernetes.io/name=coordinator
-

Kubernetes schedules a new pod, but that pod doesn't have access to the key material the previous pod held in memory and can't issue certificates for workloads yet. -You can confirm this by running verify again, or you can restart a workload pod, which should stay in the initialization phase. -However, the secret seed in your working directory is sufficient to recover the coordinator.

-
contrast recover -c "${coordinator}:1313"
-

Now that the Coordinator is recovered, all workloads should pass initialization and enter the running state. -You can now verify the Coordinator again, which should return the same manifest you set before.

-
warning

The recovery process invalidates the mesh CA certificate: -existing workloads won't be able to communicate with workloads newly spawned. -All workloads should be restarted after the recovery succeeded.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/examples/emojivoto.html b/pr-preview/pr-1071/next/examples/emojivoto.html deleted file mode 100644 index fd6ad3beb3..0000000000 --- a/pr-preview/pr-1071/next/examples/emojivoto.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - -Confidential emoji voting | Contrast - - - - -
Version: Next

Confidential emoji voting

-

screenshot of the emojivoto UI

-

This tutorial guides you through deploying emojivoto as a -confidential Contrast deployment and validating the deployment from a voter's perspective.

-

Emojivoto is an example app allowing users to vote for different emojis and view votes -on a leader board. It has a microservice architecture consisting of a -web frontend (web), a gRPC backend for listing available emojis (emoji), and a backend for -the voting and leader board logic (voting). The vote-bot simulates user traffic by submitting -votes to the frontend.

-

Emojivoto can be seen as a lighthearted example of an app dealing with sensitive data. -Contrast protects emojivoto in two ways. First, it shields emojivoto as a whole from the infrastructure, for example, Azure. -Second, it can be configured to also prevent data access even from the administrator of the app. In the case of emojivoto, this gives assurance to users that their votes remain secret.

-

emojivoto components topology

-

Prerequisites

-
    -
  • Installed Contrast CLI
  • -
  • A running Kubernetes cluster with support for confidential containers, either on AKS or on bare metal.
  • -
-

Steps to deploy emojivoto with Contrast

-

Download the deployment files

-

The emojivoto deployment files are part of the Contrast release. You can download them by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/latest/download/emojivoto-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass, -which needs to be installed to the cluster initially. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-aks-clh-snp.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads to facilitate the attestation and certificate pulling before the actual workload is started.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the different components of emojivoto.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Deploy emojivoto

-

Now that the coordinator has a manifest set, which defines the emojivoto deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Inter-deployment communication

The Contrast Coordinator issues mesh certificates after successfully validating workloads. -These certificates can be used for secure inter-deployment communication. The Initializer -sends an attestation report to the Coordinator, retrieves certificates and a private key in return -and writes them to a volumeMount. The service mesh sidecar is configured to use the credentials -from the volumeMount when communicating with other parts of the deployment over mTLS. -The public facing frontend for voting uses the mesh certificate without client authentication.

-

Verifying the deployment as a user

-

In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before casting a vote. -With Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment. -Contrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future. -Successful verification of the Coordinator means that the user can be sure that the given manifest will be enforced.

-

Verifying the Coordinator

-

A user can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Auditing the manifest history and artifacts

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A potential voter should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Connecting securely to the application

-

After ensuring the configuration of the Coordinator fits the expectation, the user can securely connect -to the application using the Coordinator's mesh-ca.pem as a trusted CA certificate.

-

To access the web frontend, expose the service on a public IP address via a LoadBalancer service:

-
frontendIP=$(kubectl get svc web-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Frontend is available at https://$frontendIP, you can visit it in your browser."
-

Using openssl, the certificate of the service can be validated with the mesh-ca.pem:

-
openssl s_client -CAfile verify/mesh-ca.pem -verify_return_error -connect ${frontendIP}:443 < /dev/null
-

Updating the certificate SAN and the manifest (optional)

-

By default, mesh certificates are issued with a wildcard DNS entry. The web frontend is accessed -via load balancer IP in this demo. Tools like curl check the certificate for IP entries in the subject alternative name (SAN) field. -Validation fails since the certificate contains no IP entries as a SAN. -For example, a connection attempt using the curl and the mesh CA certificate with throw the following error:

-
$ curl --cacert ./verify/mesh-ca.pem "https://${frontendIP}:443"
curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.34'
-

Configuring the service SAN in the manifest

-

The Policies section of the manifest maps policy hashes to a list of SANs. To enable certificate verification -of the web frontend with tools like curl, edit the policy with your favorite editor and add the frontendIP to -the list that already contains the "web" DNS entry:

-
   "Policies": {
...
"99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b": {
"SANs": [
"web",
- "*"
+ "*",
+ "203.0.113.34"
],
"WorkloadSecretID": "web"
},
-

Updating the manifest

-

Next, set the changed manifest at the coordinator with:

-
contrast set -c "${coordinator}:1313" deployment/
-

The Contrast Coordinator will rotate the mesh ca certificate on the manifest update. Workload certificates issued -after the manifest update are thus issued by another certificate authority and services receiving the new CA certificate chain -won't trust parts of the deployment that got their certificate issued before the update. This way, Contrast ensures -that parts of the deployment that received a security update won't be infected by parts of the deployment at an older -patch level that may have been compromised. The mesh-ca.pem is updated with the new CA certificate chain.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Rolling out the update

-

The Coordinator has the new manifest set, but the different containers of the app are still -using the older certificate authority. The Contrast Initializer terminates after the initial attestation -flow and won't pull new certificates on manifest updates.

-

To roll out the update, use:

-
kubectl rollout restart deployment/emoji
kubectl rollout restart deployment/vote-bot
kubectl rollout restart deployment/voting
kubectl rollout restart deployment/web
-

After the update has been rolled out, connecting to the frontend using curl will successfully validate -the service certificate and return the HTML document of the voting site:

-
curl --cacert ./mesh-ca.pem "https://${frontendIP}:443"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/examples/mysql.html b/pr-preview/pr-1071/next/examples/mysql.html deleted file mode 100644 index af8cf16eba..0000000000 --- a/pr-preview/pr-1071/next/examples/mysql.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - -Encrypted volume mount | Contrast - - - - -
Version: Next

Encrypted volume mount

-

This tutorial guides you through deploying a simple application with an -encrypted MySQL database using the Contrast workload -secret.

-

MySQL is an open-source database used to organize data into -tables and quickly retrieve information about its content. All of the data in a -MySQL database is stored in the /var/lib/mysql directory. In this example, we -use the workload secret to setup an encrypted LUKS mount for the -/var/lib/mysql directory to easily deploy an application with encrypted -persistent storage using Contrast.

-

The resources provided in this demo are designed for educational purposes and -shouldn't be used in a production environment without proper evaluation. When -working with persistent storage, regular backups are recommended in order to -prevent data loss. For confidential applications, please also refer to the -security considerations. Also be -aware of the differences in security implications of the workload secrets for -the data owner and the workload owner. For more details, see the Workload -Secrets documentation.

-

Prerequisites

-
    -
  • Installed Contrast CLI
  • -
  • A running Kubernetes cluster with support for confidential containers, either on AKS or on bare metal
  • -
-

Steps to deploy MySQL with Contrast

-

Download the deployment files

-

The MySQL deployment files are part of the Contrast release. You can download them by running:

-
curl -fLO https://github.com/edgelesssys/contrast/releases/latest/download/mysql-demo.yml --create-dirs --output-dir deployment
-

Deploy the Contrast runtime

-

Contrast depends on a custom Kubernetes RuntimeClass, -which needs to be installed to the cluster initially. -This consists of a RuntimeClass resource and a DaemonSet that performs installation on worker nodes. -This step is only required once for each version of the runtime. -It can be shared between Contrast deployments.

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/runtime-aks-clh-snp.yml
-

Deploy the Contrast Coordinator

-

Deploy the Contrast Coordinator, comprising a single replica deployment and a -LoadBalancer service, into your cluster:

-
kubectl apply -f https://github.com/edgelesssys/contrast/releases/latest/download/coordinator-aks-clh-snp.yml
-

Generate policy annotations and manifest

-

Run the generate command to generate the execution policies and add them as -annotations to your deployment files. A manifest.json file with the reference values -of your deployment will be created:

-
contrast generate --reference-values aks-clh-snp deployment/
-
Runtime class and Initializer

The deployment YAML shipped for this demo is already configured to be used with Contrast. -A runtime class contrast-cc -was added to the pods to signal they should be run as Confidential Containers. During the generation process, -the Contrast Initializer will be added as an init container to these -workloads. It will attest the pod to the Coordinator and fetch the workload certificates and the workload secret.

Further, the deployment YAML is also configured with the Contrast service mesh. -The configured service mesh proxy provides transparent protection for the communication between -the MySQL server and client.

-

Set the manifest

-

Configure the coordinator with a manifest. It might take up to a few minutes -for the load balancer to be created and the Coordinator being available.

-
coordinator=$(kubectl get svc coordinator -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "The user API of your Contrast Coordinator is available at $coordinator:1313"
contrast set -c "${coordinator}:1313" deployment/
-

The CLI will use the reference values from the manifest to attest the Coordinator deployment -during the TLS handshake. If the connection succeeds, it's ensured that the Coordinator -deployment hasn't been tampered with.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Deploy MySQL

-

Now that the coordinator has a manifest set, which defines the MySQL deployment as an allowed workload, -we can deploy the application:

-
kubectl apply -f deployment/
-
Persistent workload secrets

During the initialization process of the workload pod, the Contrast Initializer -sends an attestation report to the Coordinator and receives a workload secret -derived from the Coordinator's secret seed and the workload secret ID specified in the -manifest, and writes it to a secure in-memory volumeMount.

-

The MySQL deployment is declared as a StatefulSet with a mounted block device. -An init container running cryptsetup uses the workload secret at -/contrast/secrets/workload-secret-seed to generate a key and setup the block -device as a LUKS partition. Before starting the MySQL container, the init -container uses the generated key to open the LUKS device, which is then mounted -by the MySQL container. For the MySQL container, this process is completely -transparent and works like mounting any other volume. The cryptsetup container -will remain running to provide the necessary decryption context for the workload -container.

-

Verifying the deployment as a user

-

In different scenarios, users of an app may want to verify its security and identity before sharing data, for example, before connecting to the database. -With Contrast, a user only needs a single remote-attestation step to verify the deployment - regardless of the size or scale of the deployment. -Contrast is designed such that, by verifying the Coordinator, the user transitively verifies those systems the Coordinator has already verified or will verify in the future. -Successful verification of the Coordinator means that the user can be sure that the given manifest will be enforced.

-

Verifying the Coordinator

-

A user can verify the Contrast deployment using the verify -command:

-
contrast verify -c "${coordinator}:1313" -m manifest.json
-

The CLI will verify the Coordinator via remote attestation using the reference values from a given manifest. This manifest needs -to be communicated out of band to everyone wanting to verify the deployment, as the verify command checks -if the currently active manifest at the Coordinator matches the manifest given to the CLI. If the command succeeds, -the Coordinator deployment was successfully verified to be running in the expected Confidential -Computing environment with the expected code version. The Coordinator will then return its -configuration over the established TLS channel. The CLI will store this information, namely the root -certificate of the mesh (mesh-ca.pem) and the history of manifests, into the verify/ directory. -In addition, the policies referenced in the manifest history are also written into the same directory.

-
warning

On bare metal, the coordinator policy hash must be overwritten using --coordinator-policy-hash.

-

Auditing the manifest history and artifacts

-

In the next step, the Coordinator configuration that was written by the verify command needs to be audited. -A user of the application should inspect the manifest and the referenced policies. They could delegate -this task to an entity they trust.

-

Connecting to the application

-

Other confidential containers can securely connect to the MySQL server via the -Service Mesh. The configured mysql-client -deployment connects to the MySQL server and inserts test data into a table. To -view the logs of the mysql-client deployment, use the following commands:

-
kubectl logs -l app.kubernetes.io/name=mysql-client -c mysql-client
-

The Service Mesh ensures an mTLS connection between the MySQL client and server -using the mesh certificates. As a result, no other workload can connect to the -MySQL server unless explicitly allowed in the manifest.

-

Updating the deployment

-

Because the workload secret is derived from the WorkloadSecredID specified in -the manifest and not to an individual pod, once the pod restarts, the -cryptsetup init container can deterministically generate the same key again -and open the already partitioned LUKS device. -For more information on using the workload secret, see Workload -Secrets.

-

For example, after making changes to the deployment files, the runtime policies -need to be regenerated with contrast generate and the new manifest needs to be -set using contrast set.

-
contrast generate deployment/
contrast set -c "${coordinator}:1313" deployment/
-

The new deployment can then be applied by running:

-
kubectl rollout restart statefulset/mysql-backend
kubectl rollout restart deployment/mysql-client
-

The new MySQL backend pod will then start up the cryptsetup init container which -receives the same workload secret as before and can therefore generate the -correct key to open the LUKS device. All previously stored data in the MySQL -database is available in the newly created pod in an encrypted volume mount.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/features-limitations.html b/pr-preview/pr-1071/next/features-limitations.html deleted file mode 100644 index b13dac0e5f..0000000000 --- a/pr-preview/pr-1071/next/features-limitations.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - -Planned features and limitations | Contrast - - - - -
Version: Next

Planned features and limitations

-

This section lists planned features and current limitations of Contrast.

-

Availability

-
    -
  • Platform support: At present, Contrast is exclusively available on Azure AKS, supported by the Confidential Container preview for AKS. Expansion to other cloud platforms is planned, pending the availability of necessary infrastructure enhancements.
  • -
  • Bare-metal support: Support for running Contrast on bare-metal Kubernetes is available for AMD SEV-SNP and Intel TDX.
  • -
-

Kubernetes features

-
    -
  • Persistent volumes: Contrast only supports volumes with volumeMode: Block. These block devices are provided by the untrusted environment and should be treated accordingly. We plan to provide transparent encryption on top of block devices in a future release.
  • -
  • Port forwarding: This feature isn't yet supported by Kata Containers. You can deploy a port-forwarder as a workaround.
  • -
  • Resource limits: There is an existing bug on AKS where container memory limits are incorrectly applied. The current workaround involves using only memory requests instead of limits.
  • -
-

Runtime policies

-
    -
  • Coverage: While the enforcement of workload policies generally functions well, there are scenarios not yet fully covered. It's crucial to review deployments specifically for these edge cases.
  • -
  • Order of events: The current policy evaluation mechanism on API requests isn't stateful, so it can't ensure a prescribed order of events. Consequently, there's no guaranteed enforcement that the service mesh sidecar container runs before the workload container. This order ensures that all traffic between pods is securely encapsulated within TLS connections.
  • -
  • Absence of events: Policies can't ensure certain events have happened. A container, such as the service mesh sidecar, can be omitted entirely. Environment variables may be missing.
  • -
  • Volume integrity checks: Integrity checks don't cover any volume mounts, such as ConfigMaps and Secrets.
  • -
-
warning

The policy limitations, in particular the missing guarantee that our service mesh sidecar has been started before the workload container, affect the service mesh implementation of Contrast. -Currently, this requires inspecting the iptables rules on startup or terminating TLS connections in the workload directly.

-

Tooling integration

-
    -
  • CLI availability: The CLI tool is currently only available for Linux. This limitation arises because certain upstream dependencies haven't yet been ported to other platforms.
  • -
-

Automatic recovery and high availability

-

The Contrast Coordinator is a singleton and can't be scaled to more than one instance. -When this instance's pod is restarted, for example for node maintenance, it needs to be recovered manually. -In a future release, we plan to support distributed Coordinator instances that can recover automatically.

-

Overriding Kata configuration

-

Kata Containers supports overriding certain configuration values via Kubernetes annotations.

-

It needs to be noted that setting these values is unsupported, and doing so may lead to unexpected -behaviour, as Contrast isn't tested against all possible configuration combinations.

- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/getting-started/bare-metal.html b/pr-preview/pr-1071/next/getting-started/bare-metal.html deleted file mode 100644 index a6bb333b74..0000000000 --- a/pr-preview/pr-1071/next/getting-started/bare-metal.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -Prepare a bare-metal instance | Contrast - - - - -
Version: Next

Prepare a bare-metal instance

-

Hardware and firmware setup

-
    -
  1. Update your BIOS to a version that supports AMD SEV-SNP. Updating to the latest available version is recommended as newer versions will likely contain security patches for AMD SEV-SNP.
  2. -
  3. Enter BIOS setup to enable SMEE, IOMMU, RMP coverage, and SEV-SNP. Set the SEV-ES ASID Space Limit to a non-zero number (higher is better).
  4. -
  5. Download the latest firmware version for your processor from AMD, unpack it, and place it in /lib/firmware/amd.
  6. -

Consult AMD's Using SEV with AMD EPYC Processors user guide for more information.

-

Kernel Setup

-

Install a kernel with version 6.11 or greater. If you're following this guide before 6.11 has been released, use 6.11-rc3. Don't use 6.11-rc4 - 6.11-rc6 as they contain a regression. 6.11-rc7+ might work.

-

Increase the user.max_inotify_instances sysctl limit by adding user.max_inotify_instances=8192 to /etc/sysctl.d/99-sysctl.conf and running sysctl --system.

-

K3s Setup

-
    -
  1. Follow the K3s setup instructions to create a cluster.
  2. -
  3. Install a block storage provider such as Longhorn and mark it as the default storage class.
  4. -
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/getting-started/cluster-setup.html b/pr-preview/pr-1071/next/getting-started/cluster-setup.html deleted file mode 100644 index 43bbf6f9c3..0000000000 --- a/pr-preview/pr-1071/next/getting-started/cluster-setup.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - -Create a cluster | Contrast - - - - -
Version: Next

Create a cluster

-

Prerequisites

-
    -
  • Install version 2.44.1 or newer of the Azure CLI. Note that your package manager will likely install an outdated version.
  • -
  • Install a recent version of kubectl.
  • -
-

Prepare using the AKS preview

-

First, log in to your Azure subscription:

-
az login
-

CoCo on AKS is currently in preview. An extension for the az CLI is needed to create such a cluster. -Add the extension with the following commands:

-
az extension add \
--name aks-preview \
--allow-preview true
az extension update \
--name aks-preview \
--allow-preview true
-

Then register the required feature flags in your subscription to allow access to the public preview:

-
az feature register \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview"
-

The registration can take a few minutes. The status of the operation can be checked with the following -command, which should show the registration state as Registered:

-
az feature show \
--namespace "Microsoft.ContainerService" \
--name "KataCcIsolationPreview" \
--output table
-

Afterward, refresh the registration of the ContainerService provider:

-
az provider register \
--namespace "Microsoft.ContainerService"
-

Create resource group

-

The AKS with CoCo preview is currently available in the following locations:

-
CentralIndia
eastus
EastUS2EUAP
GermanyWestCentral
japaneast
northeurope
SwitzerlandNorth
UAENorth
westeurope
westus
-

Set the name of the resource group you want to use:

-
azResourceGroup="ContrastDemo"
-

You can either use an existing one or create a new resource group with the following command:

-
azLocation="westus" # Select a location from the list above

az group create \
--name "${azResourceGroup:?}" \
--location "${azLocation:?}"
-

Create AKS cluster

-

First, create a CoCo enabled AKS cluster with:

-
# Select the name for your AKS cluster
azClusterName="ContrastDemo"

az aks create \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}" \
--kubernetes-version 1.30 \
--os-sku AzureLinux \
--node-vm-size Standard_DC4as_cc_v5 \
--workload-runtime KataCcIsolation \
--node-count 1 \
--generate-ssh-keys
-

Finally, update your kubeconfig with the credentials to access the cluster:

-
az aks get-credentials \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
-

For validation, list the available nodes using kubectl:

-
kubectl get nodes
-

It should show a single node:

-
NAME                                STATUS   ROLES    AGE     VERSION
aks-nodepool1-32049705-vmss000000 Ready <none> 9m47s v1.29.0
-

🥳 Congratulations. You're now ready to set up your first application with Contrast. Follow this example to learn how.

-

Cleanup

-

After trying out Contrast, you might want to clean up the cloud resources created in this step. -In case you've created a new resource group, you can just delete that group with

-
az group delete \
--name "${azResourceGroup:?}"
-

Deleting the resource group will also delete the cluster and all other related resources.

-

To only cleanup the AKS cluster and node pools, run

-
az aks delete \
--resource-group "${azResourceGroup:?}" \
--name "${azClusterName:?}"
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/getting-started/install.html b/pr-preview/pr-1071/next/getting-started/install.html deleted file mode 100644 index 6d4bc86bf2..0000000000 --- a/pr-preview/pr-1071/next/getting-started/install.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -Installation | Contrast - - - - -
Version: Next

Installation

-

Download the Contrast CLI from the latest release:

-
curl --proto '=https' --tlsv1.2 -fLo contrast https://github.com/edgelesssys/contrast/releases/latest/download/contrast
-

After that, install the Contrast CLI in your PATH, e.g.:

-
sudo install contrast /usr/local/bin/contrast
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/next/troubleshooting.html b/pr-preview/pr-1071/next/troubleshooting.html deleted file mode 100644 index d0cf694662..0000000000 --- a/pr-preview/pr-1071/next/troubleshooting.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - -Troubleshooting | Contrast - - - - -
Version: Next

Troubleshooting

-

This section contains information on how to debug your Contrast deployment.

-

Logging

-

Collecting logs can be a good first step to identify problems in your -deployment. Both the CLI and the Contrast Coordinator as well as the Initializer -can be configured to emit additional logs.

-

CLI

-

The CLI logs can be configured with the --log-level command-line flag, which -can be set to either debug, info, warn or error. The default is info. -Setting this to debug can get more fine-grained information as to where the -problem lies.

-

Coordinator and Initializer

-

The logs from the Coordinator and the Initializer can be configured via the -environment variables CONTRAST_LOG_LEVEL, CONTRAST_LOG_FORMAT and -CONTRAST_LOG_SUBSYSTEMS.

-
    -
  • CONTRAST_LOG_LEVEL can be set to one of either debug, info, warn, or -error, similar to the CLI (defaults to info).
  • -
  • CONTRAST_LOG_FORMAT can be set to text or json, determining the output -format (defaults to text).
  • -
  • CONTRAST_LOG_SUBSYSTEMS is a comma-separated list of subsystems that should -be enabled for logging, which are disabled by default. Subsystems include: -kds-getter, issuer and validator. -To enable all subsystems, use * as the value for this environment variable. -Warnings and error messages from subsystems get printed regardless of whether -the subsystem is listed in the CONTRAST_LOG_SUBSYSTEMS environment variable.
  • -
-

To configure debug logging with all subsystems for your Coordinator, add the -following variables to your container definition.

-
spec: # v1.PodSpec
containers:
image: "ghcr.io/edgelesssys/contrast/coordinator:latest"
name: coordinator
env:
- name: CONTRAST_LOG_LEVEL
value: debug
- name: CONTRAST_LOG_SUBSYSTEMS
value: "*"
# ...
-
info

While the Contrast Coordinator has a policy that allows certain configurations, -the Initializer and service mesh don't. When changing environment variables of other -parts than the Coordinator, ensure to rerun contrast generate to update the policy.

-

To access the logs generated by the Coordinator, you can use kubectl with the -following command:

-
kubectl logs <coordinator-pod-name>
-

Pod fails to start

-

If the Coordinator or a workload pod fails to even start, it can be helpful to -look at the events of the pod during the startup process using the describe -command.

-
kubectl -n <namespace> events --for pod/<coordinator-pod-name>
-

Example output:

-
LAST SEEN  TYPE     REASON  OBJECT             MESSAGE
32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...
-

A common error, as in this example, is that the container creation was blocked by the -policy. Potential reasons are a modification of the deployment YAML without updating -the policies afterward, or a version mismatch between Contrast components.

-

Regenerating the policies

-

To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated -policies, rerun

-
contrast generate
-

on your deployment. If any of the policy annotations change, re-deploy with the updated policies.

-

Pin container images

-

When generating the policies, Contrast will download the images specified in your deployment -YAML and include their cryptographic identity. If the image tag is moved to another -container image after the policy has been generated, the image downloaded at deploy time -will differ from the one at generation time, and the policy enforcement won't allow the -container to be started in the pod VM.

-

To ensure the correct image is always used, pin the container image to a fixed sha256:

-
image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac
-

This way, the same image will still be pulled when the container tag (22.04) is moved -to another image.

-

Validate Contrast components match

-

A version mismatch between Contrast components can cause policy validation or attestation -to fail. Each Contrast runtime is identifiable based on its (shortened) measurement value -used to name the runtime class version.

-

First, analyze which runtime class is currently installed in your cluster by running

-
kubectl get runtimeclasses
-

This should give you output similar to the following one.

-
NAME                                           HANDLER                                        AGE
contrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h
kata-cc-isolation kata-cc 45d
-

The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided -by the AKS CoCo preview, which isn't used by Contrast).

-

Next, check if the pod that won't start has the correct runtime class configured, and the -Coordinator uses the exact same runtime:

-
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>
-

The output should list the runtime class the pod is using:

-
contrast-cc-aks-clh-snp-7173acb5
-

Version information about the currently used CLI can be obtained via the version flag:

-
contrast --version
-
contrast version v0.X.0

runtime handler: contrast-cc-aks-clh-snp-7173acb5
launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35
genpolicy version: 3.2.0.azl1.genpolicy0
image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...
ghcr.io/edgelesssys/contrast/initializer@sha256:...
- - \ No newline at end of file diff --git a/pr-preview/pr-1071/search-index-docs-default-0.5.json b/pr-preview/pr-1071/search-index-docs-default-0.5.json deleted file mode 100644 index 8e5afeeecf..0000000000 --- a/pr-preview/pr-1071/search-index-docs-default-0.5.json +++ /dev/null @@ -1 +0,0 @@ -{"documents":[{"id":104,"pageTitle":"Contrast","sectionTitle":"Contrast","sectionRoute":"/contrast/pr-preview/pr-1071/0.5","type":"docs"},{"id":105,"pageTitle":"Contrast","sectionTitle":"Goal","sectionRoute":"/contrast/pr-preview/pr-1071/0.5#goal","type":"docs"},{"id":106,"pageTitle":"Contrast","sectionTitle":"Use Cases","sectionRoute":"/contrast/pr-preview/pr-1071/0.5#use-cases","type":"docs"},{"id":107,"pageTitle":"Contrast","sectionTitle":"Next steps","sectionRoute":"/contrast/pr-preview/pr-1071/0.5#next-steps","type":"docs"},{"id":108,"pageTitle":"Architecture","sectionTitle":"Architecture","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture","type":"docs"},{"id":109,"pageTitle":"Architecture","sectionTitle":"🗃️ Components","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture","type":"docs"},{"id":110,"pageTitle":"Architecture","sectionTitle":"📄️ Confidential Containers","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture","type":"docs"},{"id":111,"pageTitle":"Architecture","sectionTitle":"🗃️ Attestation","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture","type":"docs"},{"id":112,"pageTitle":"Architecture","sectionTitle":"🗃️ Certificates and Identities","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture","type":"docs"},{"id":113,"pageTitle":"Architecture","sectionTitle":"🗃️ Network Encryption","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture","type":"docs"},{"id":114,"pageTitle":"coordinator","sectionTitle":"coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinator","type":"docs"},{"id":115,"pageTitle":"hardware","sectionTitle":"hardware","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardware","type":"docs"},{"id":1,"pageTitle":"manifest","sectionTitle":"manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifest","type":"docs"},{"id":2,"pageTitle":"pod-vm","sectionTitle":"pod-vm","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vm","type":"docs"},{"id":3,"pageTitle":"runtime-policies","sectionTitle":"runtime-policies","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policies","type":"docs"},{"id":5,"pageTitle":"pki","sectionTitle":"pki","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pki","type":"docs"},{"id":4,"pageTitle":"cli","sectionTitle":"cli","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/components/cli","type":"docs"},{"id":6,"pageTitle":"coordinator","sectionTitle":"coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinator","type":"docs"},{"id":148,"pageTitle":"init-container","sectionTitle":"init-container","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/components/init-container","type":"docs"},{"id":7,"pageTitle":"confidential-containers","sectionTitle":"confidential-containers","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containers","type":"docs"},{"id":9,"pageTitle":"protocols-and-keys","sectionTitle":"protocols-and-keys","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keys","type":"docs"},{"id":8,"pageTitle":"sidecar","sectionTitle":"sidecar","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecar","type":"docs"},{"id":10,"pageTitle":"Confidential Containers","sectionTitle":"Confidential Containers","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers","type":"docs"},{"id":11,"pageTitle":"Confidential Containers","sectionTitle":"Kubernetes RuntimeClass","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers#kubernetes-runtimeclass","type":"docs"},{"id":12,"pageTitle":"Confidential Containers","sectionTitle":"Kata Containers","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers#kata-containers","type":"docs"},{"id":13,"pageTitle":"Confidential Containers","sectionTitle":"AKS CoCo Preview","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/basics/confidential-containers#aks-coco-preview","type":"docs"},{"id":14,"pageTitle":"Product Features","sectionTitle":"Product Features","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/basics/features","type":"docs"},{"id":15,"pageTitle":"security-benefits","sectionTitle":"security-benefits","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/basics/security-benefits","type":"docs"},{"id":17,"pageTitle":"","sectionTitle":"📄️ Hardware","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/attestation","type":"docs"},{"id":18,"pageTitle":"","sectionTitle":"📄️ Pod VM","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/attestation","type":"docs"},{"id":19,"pageTitle":"","sectionTitle":"📄️ Runtime policies","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/attestation","type":"docs"},{"id":20,"pageTitle":"","sectionTitle":"📄️ Manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/attestation","type":"docs"},{"id":21,"pageTitle":"","sectionTitle":"📄️ Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/attestation","type":"docs"},{"id":16,"pageTitle":"","sectionTitle":"📄️ PKI","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identities","type":"docs"},{"id":22,"pageTitle":"","sectionTitle":"📄️ Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/components","type":"docs"},{"id":23,"pageTitle":"","sectionTitle":"📄️ Init container","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/components","type":"docs"},{"id":24,"pageTitle":"","sectionTitle":"📄️ CLI","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/components","type":"docs"},{"id":25,"pageTitle":"","sectionTitle":"📄️ Sidecar","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption","type":"docs"},{"id":26,"pageTitle":"","sectionTitle":"📄️ Protocols and Keys","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/category/network-encryption","type":"docs"},{"id":29,"pageTitle":"Workload deployment","sectionTitle":"Workload deployment","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment","type":"docs"},{"id":30,"pageTitle":"Workload deployment","sectionTitle":"Deploy the Contrast Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#deploy-the-contrast-coordinator","type":"docs"},{"id":31,"pageTitle":"Workload deployment","sectionTitle":"Prepare your Kubernetes resources","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#prepare-your-kubernetes-resources","type":"docs"},{"id":32,"pageTitle":"Workload deployment","sectionTitle":"Generate policy annotations and manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#generate-policy-annotations-and-manifest","type":"docs"},{"id":33,"pageTitle":"Workload deployment","sectionTitle":"Apply the resources","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#apply-the-resources","type":"docs"},{"id":34,"pageTitle":"Workload deployment","sectionTitle":"Connect to the Contrast Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#connect-to-the-contrast-coordinator","type":"docs"},{"id":35,"pageTitle":"Workload deployment","sectionTitle":"Set the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#set-the-manifest","type":"docs"},{"id":36,"pageTitle":"Workload deployment","sectionTitle":"Verify the Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#verify-the-coordinator","type":"docs"},{"id":37,"pageTitle":"Workload deployment","sectionTitle":"Communicate with workloads","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/deployment#communicate-with-workloads","type":"docs"},{"id":27,"pageTitle":"Examples","sectionTitle":"Examples","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples","type":"docs"},{"id":28,"pageTitle":"Examples","sectionTitle":"📄️ Confidential emoji voting","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples","type":"docs"},{"id":38,"pageTitle":"Confidential emoji voting","sectionTitle":"Confidential emoji voting","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto","type":"docs"},{"id":39,"pageTitle":"Confidential emoji voting","sectionTitle":"Motivation","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#motivation","type":"docs"},{"id":40,"pageTitle":"Confidential emoji voting","sectionTitle":"Prerequisites","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#prerequisites","type":"docs"},{"id":41,"pageTitle":"Confidential emoji voting","sectionTitle":"Steps to deploy emojivoto with Contrast","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#steps-to-deploy-emojivoto-with-contrast","type":"docs"},{"id":42,"pageTitle":"Confidential emoji voting","sectionTitle":"Deploy the Contrast Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#deploy-the-contrast-coordinator","type":"docs"},{"id":43,"pageTitle":"Confidential emoji voting","sectionTitle":"Generate policy annotations and manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#generate-policy-annotations-and-manifest","type":"docs"},{"id":44,"pageTitle":"Confidential emoji voting","sectionTitle":"Set the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#set-the-manifest","type":"docs"},{"id":45,"pageTitle":"Confidential emoji voting","sectionTitle":"Deploy emojivoto","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#deploy-emojivoto","type":"docs"},{"id":46,"pageTitle":"Confidential emoji voting","sectionTitle":"Voter's perspective: Verifying the ballot","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#voters-perspective-verifying-the-ballot","type":"docs"},{"id":47,"pageTitle":"Confidential emoji voting","sectionTitle":"Attest the Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#attest-the-coordinator","type":"docs"},{"id":48,"pageTitle":"Confidential emoji voting","sectionTitle":"Manifest history and artifact audit","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#manifest-history-and-artifact-audit","type":"docs"},{"id":49,"pageTitle":"Confidential emoji voting","sectionTitle":"Confidential connection to the attested workload","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#confidential-connection-to-the-attested-workload","type":"docs"},{"id":50,"pageTitle":"Confidential emoji voting","sectionTitle":"Certificate SAN and manifest update (optional)","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#certificate-san-and-manifest-update-optional","type":"docs"},{"id":51,"pageTitle":"Confidential emoji voting","sectionTitle":"Configure the service SAN in the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#configure-the-service-san-in-the-manifest","type":"docs"},{"id":52,"pageTitle":"Confidential emoji voting","sectionTitle":"Update the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#update-the-manifest","type":"docs"},{"id":53,"pageTitle":"Confidential emoji voting","sectionTitle":"Rolling out the update","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/examples/emojivoto#rolling-out-the-update","type":"docs"},{"id":54,"pageTitle":"Getting started","sectionTitle":"Getting started","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started","type":"docs"},{"id":55,"pageTitle":"Getting started","sectionTitle":"📄️ Install","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started","type":"docs"},{"id":56,"pageTitle":"Getting started","sectionTitle":"📄️ Cluster setup","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started","type":"docs"},{"id":57,"pageTitle":"Getting started","sectionTitle":"📄️ First steps","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started","type":"docs"},{"id":58,"pageTitle":"Create a cluster","sectionTitle":"Create a cluster","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup","type":"docs"},{"id":59,"pageTitle":"Create a cluster","sectionTitle":"Prerequisites","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup#prerequisites","type":"docs"},{"id":60,"pageTitle":"Create a cluster","sectionTitle":"Prepare using the AKS preview","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup#prepare-using-the-aks-preview","type":"docs"},{"id":61,"pageTitle":"Create a cluster","sectionTitle":"Create resource group","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup#create-resource-group","type":"docs"},{"id":62,"pageTitle":"Create a cluster","sectionTitle":"Create AKS cluster","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup#create-aks-cluster","type":"docs"},{"id":63,"pageTitle":"Create a cluster","sectionTitle":"Cleanup","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setup#cleanup","type":"docs"},{"id":116,"pageTitle":"first-steps","sectionTitle":"first-steps","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/first-steps","type":"docs"},{"id":117,"pageTitle":"Installation","sectionTitle":"Installation","sectionRoute":"/contrast/pr-preview/pr-1071/0.5/getting-started/install","type":"docs"}],"index":{"version":"2.3.9","fields":["title","content","tags"],"fieldVectors":[["title/104",[0,1.237]],["content/104",[0,1.401,1,2.927,2,2.549,3,1.564,4,1.845,5,1.721,6,0.864,7,2.038,8,2.301,9,3.446,10,1.738,11,2.549,12,1.202,13,2.115,14,2.927,15,2.927,16,1.423,17,1.564,18,2.927,19,1.646,20,2.115,21,2.927,22,2.115,23,2.927,24,2.927,25,2.927,26,2.927,27,2.927,28,2.115,29,2.301,30,1.564,31,1.646,32,1.423,33,2.927,34,2.301,35,2.927,36,2.115,37,2.549,38,1.738]],["tags/104",[]],["title/105",[39,5.154]],["content/105",[0,1.027,6,0.837,7,1.99,9,2.229,17,1.515,38,1.684,40,2.229,41,2.469,42,1.905,43,2.834,44,2.229,45,2.834,46,2.541,47,4.052,48,2.834,49,2.834,50,1.905,51,2.834,52,2.229,53,2.834,54,2.834,55,4.278,56,1.905,57,2.834,58,1.078,59,2.469,60,2.834,61,2.834,62,2.049,63,1.786,64,2.834,65,2.834,66,2.834,67,2.834,68,2.469,69,2.834,70,2.049,71,2.834,72,2.469,73,2.469,74,2.049,75,1.443,76,2.469,77,1.905,78,2.229,79,2.834,80,2.469,81,2.469,82,2.469]],["tags/105",[]],["title/106",[83,1.374,84,3.024]],["content/106",[0,0.839,4,1.032,5,0.963,17,1.867,38,2.964,42,3.354,56,2.349,58,1.329,59,3.044,83,1.147,84,2.526,85,3.495,86,2.806,87,2.202,88,2.526,89,3.044,90,4.99,91,3.495,92,3.044,93,1.436,94,3.495,95,2.748,96,3.044,97,3.495,98,3.495,99,3.495,100,2.748,101,3.044,102,3.495,103,3.495,104,3.495,105,3.044,106,3.495]],["tags/106",[]],["title/107",[107,3.024,108,2.034]],["content/107",[0,1.152,4,1.418,5,1.323,36,3.47,86,2.699,87,3.024,88,3.47,109,4.8,110,4.181,111,4.181,112,4.8,113,4.8,114,4.8,115,4.8,116,4.181,117,3.47]],["tags/107",[]],["title/108",[118,4.052]],["content/108",[4,1.302,5,1.215,44,3.466,77,2.963,119,1.098,120,3.466,121,3.84,122,4.71,123,1.811,124,3.84,125,1.741,126,3.466,127,3.466,128,3.466]],["tags/108",[]],["title/109",[119,0.63,120,3.29]],["content/109",[121,5.567,122,4.296]],["tags/109",[]],["title/110",[4,1.04,5,0.97,119,0.53]],["content/110",[]],["tags/110",[]],["title/111",[119,0.63,123,1.719]],["content/111",[122,4.296,124,5.567]],["tags/111",[]],["title/112",[119,0.53,125,1.391,126,2.769]],["content/112",[122,4.296,127,5.025]],["tags/112",[]],["title/113",[44,2.769,119,0.53,128,2.769]],["content/113",[77,4.296,122,4.296]],["tags/113",[]],["title/114",[129,1.155]],["content/114",[]],["tags/114",[]],["title/115",[19,2.898]],["content/115",[]],["tags/115",[]],["title/1",[130,1.42]],["content/1",[]],["tags/1",[]],["title/2",[12,1.719,16,2.034]],["content/2",[]],["tags/2",[]],["title/3",[131,1.865,132,1.653]],["content/3",[]],["tags/3",[]],["title/5",[133,3.725]],["content/5",[]],["tags/5",[]],["title/4",[134,2.397]],["content/4",[]],["tags/4",[]],["title/6",[129,1.155]],["content/6",[]],["tags/6",[]],["title/148",[5,1.153,135,2.485]],["content/148",[]],["tags/148",[]],["title/7",[4,1.236,5,1.153]],["content/7",[]],["tags/7",[]],["title/9",[136,3.024,137,2.485]],["content/9",[]],["tags/9",[]],["title/8",[138,3.725]],["content/8",[]],["tags/8",[]],["title/10",[4,1.236,5,1.153]],["content/10",[0,1.209,4,1.488,5,0.976,7,1.647,11,4.387,12,1.455,17,1.892,30,2.691,36,2.559,38,2.103,83,1.654,87,2.231,89,3.084,131,1.578,139,3.084,140,3.084,141,3.541,142,3.541,143,3.541,144,3.541,145,4.387,146,3.541,147,3.541,148,3.541,149,3.541,150,3.541,151,3.084,152,3.541,153,3.541,154,3.541]],["tags/10",[]],["title/11",[7,1.946,155,3.645]],["content/11",[4,0.969,5,1.548,7,1.527,9,2.581,10,1.95,12,1.349,36,2.373,38,1.95,63,2.068,74,2.373,83,1.078,84,2.373,131,2.748,155,4.894,156,3.282,157,2.859,158,3.282,159,2.859,160,2.859,161,4.77,162,3.282,163,3.282,164,2.581,165,2.859,166,3.282,167,3.282,168,2.859,169,2.581,170,3.282,171,3.282,172,3.282,173,3.282,174,2.581,175,2.859]],["tags/11",[]],["title/12",[5,1.153,10,2.485]],["content/12",[3,2.079,4,0.9,5,1.244,7,1.417,10,2.311,12,1.855,16,2.999,17,0.986,20,1.334,40,1.451,47,1.451,52,1.451,56,2.048,62,1.334,72,1.608,74,1.334,83,0.606,95,1.451,123,0.758,128,1.451,131,1.358,132,1.537,164,2.396,165,1.608,168,1.608,176,3.891,177,1.846,178,4.516,179,1.451,180,1.846,181,1.038,182,3.93,183,1.608,184,1.608,185,1.358,186,3.389,187,1.334,188,2.396,189,1.334,190,1.846,191,1.846,192,1.846,193,1.241,194,1.608,195,2.654,196,2.202,197,1.608,198,1.846,199,1.846,200,1.846,201,1.451,202,1.608,203,1.608,204,1.846,205,0.897,206,1.846,207,1.846,208,1.451,209,3.047,210,1.451,211,1.608,212,1.846,213,0.859,214,1.451,215,1.608]],["tags/12",[]],["title/13",[30,1.882,31,1.98,32,1.712]],["content/13",[0,0.885,6,1.089,7,1.714,16,2.519,17,1.969,30,3.202,31,2.073,32,2.519,58,1.401,75,1.876,100,2.898,175,3.211,187,3.745,194,3.211,195,3.211,202,3.211,216,4.074,217,1.792,218,3.745,219,4.074,220,3.686,221,3.211,222,3.686,223,3.686,224,3.686]],["tags/13",[]],["title/14",[87,2.636,225,4.184]],["content/14",[0,1.204,4,0.945,5,1.047,6,1.265,7,1.993,8,1.11,12,0.58,17,1.298,22,1.02,32,0.686,40,1.11,42,0.949,47,1.91,56,0.949,58,0.924,68,2.787,70,2.312,73,2.117,74,2.312,75,0.719,76,1.23,77,0.949,78,1.91,80,1.23,83,0.463,86,2.409,87,0.889,88,1.02,93,0.998,95,1.11,100,1.11,101,1.23,105,1.23,110,1.23,118,1.11,120,1.11,123,0.998,125,0.558,126,1.11,133,1.02,137,1.443,169,1.11,174,1.11,188,1.11,193,0.949,196,1.02,203,1.23,205,0.686,216,1.11,217,1.181,218,1.02,226,1.412,227,1.412,228,1.91,229,1.412,230,1.412,231,1.412,232,1.412,233,1.412,234,0.838,235,0.889,236,0.949,237,1.23,238,1.412,239,1.412,240,1.412,241,1.412,242,1.412,243,1.412,244,1.412,245,2.43,246,0.949,247,1.23,248,1.412,249,1.11,250,1.23,251,1.23,252,1.23,253,1.412,254,1.412,255,2.117,256,0.838,257,1.412,258,1.412,259,0.838,260,1.412,261,1.23,262,1.412,263,1.412,264,1.756,265,0.794,266,1.412,267,1.23,268,1.412,269,0.794,270,0.754,271,0.949,272,0.838,273,1.23,274,1.23,275,1.412,276,1.412,277,0.949,278,1.23,279,0.754,280,1.23,281,1.412,282,1.412,283,1.412]],["tags/14",[]],["title/15",[86,2.353,88,3.024]],["content/15",[]],["tags/15",[]],["title/17",[19,2.353,119,0.63]],["content/17",[12,2.123,16,2.512,19,2.906,119,1.154,129,1.158,130,1.424,131,2.303,132,2.042]],["tags/17",[]],["title/18",[12,1.447,16,1.712,119,0.53]],["content/18",[12,2.123,16,2.512,19,2.906,119,1.154,129,1.158,130,1.424,131,2.303,132,2.042]],["tags/18",[]],["title/19",[119,0.53,131,1.569,132,1.391]],["content/19",[12,2.123,16,2.512,19,2.906,119,1.154,129,1.158,130,1.424,131,2.303,132,2.042]],["tags/19",[]],["title/20",[119,0.63,130,1.153]],["content/20",[12,2.123,16,2.512,19,2.906,119,1.154,129,1.158,130,1.424,131,2.303,132,2.042]],["tags/20",[]],["title/21",[119,0.63,129,0.937]],["content/21",[12,2.123,16,2.512,19,2.906,119,1.154,129,1.158,130,1.424,131,2.303,132,2.042]],["tags/21",[]],["title/16",[119,0.63,133,3.024]],["content/16",[119,0.962,133,4.619]],["tags/16",[]],["title/22",[119,0.63,129,0.937]],["content/22",[5,1.575,119,1.117,129,1.28,134,2.658,135,3.394]],["tags/22",[]],["title/23",[5,0.97,119,0.53,135,2.092]],["content/23",[5,1.575,119,1.117,129,1.28,134,2.658,135,3.394]],["tags/23",[]],["title/24",[119,0.63,134,1.946]],["content/24",[5,1.575,119,1.117,129,1.28,134,2.658,135,3.394]],["tags/24",[]],["title/25",[119,0.63,138,3.024]],["content/25",[119,1.067,136,4.313,137,3.544,138,4.313]],["tags/25",[]],["title/26",[119,0.53,136,2.545,137,2.092]],["content/26",[119,1.067,136,4.313,137,3.544,138,4.313]],["tags/26",[]],["title/29",[6,1.236,93,1.719]],["content/29",[0,1.009,3,2.245,4,1.241,6,1.675,7,1.954,30,2.245,34,3.304,58,1.598,62,3.037,70,3.037,108,2.043,179,3.304,189,3.037,218,3.037,234,2.496,246,2.825,284,3.661,285,4.941,286,4.202,287,4.202,288,2.139,289,3.304]],["tags/29",[]],["title/30",[0,0.845,6,1.04,129,0.789]],["content/30",[0,1.152,6,1.418,58,1.825,75,2.444,129,1.075,217,2.333,290,3.774,291,3.774,292,4.181,293,3.774,294,4.181,295,3.227,296,2.699,297,3.227,298,3.47,299,4.8]],["tags/30",[]],["title/31",[7,1.638,213,1.638,300,3.068]],["content/31",[0,0.732,4,0.545,5,0.509,6,0.9,7,0.859,10,1.81,12,1.598,20,2.202,41,1.608,83,0.606,93,1.598,119,0.68,125,0.729,129,0.414,139,1.608,186,1.608,201,1.451,205,0.897,211,1.608,213,1.81,214,1.451,235,1.92,236,1.241,249,1.451,250,3.389,251,1.608,252,3.389,256,1.096,277,3.036,301,2.451,302,1.241,303,3.551,304,1.334,305,1.846,306,3.047,307,1.846,308,1.451,309,3.047,310,3.047,311,3.047,312,3.047,313,1.846,314,1.846,315,1.846,316,1.846,317,1.846,318,1.846,319,3.047,320,2.654,321,2.654,322,3.047,323,1.334,324,2.654,325,2.811,326,3.389,327,1.846,328,1.846,329,1.846,330,1.846,331,1.163,332,1.846,333,1.846,334,1.846,335,1.846]],["tags/31",[]],["title/32",[130,0.838,132,1.201,256,1.806,302,2.044]],["content/32",[0,1.113,3,2.477,6,1.788,13,3.35,132,1.831,181,2.607,185,2.066,213,2.156,256,4.004,301,2.92,302,3.116,303,3.644,331,2.92,336,4.038,337,3.116]],["tags/32",[]],["title/33",[213,1.946,297,2.813]],["content/33",[58,1.858,93,2.008,129,1.095,130,1.347,140,4.257,213,2.913,235,3.079,288,2.488,296,2.748,297,4.211,298,3.532,338,4.887,339,4.257]],["tags/33",[]],["title/34",[0,0.845,129,0.789,279,1.882]],["content/34",[4,0.812,5,1.152,6,0.812,10,1.632,12,1.129,30,1.468,46,1.632,52,2.16,83,1.66,107,1.986,108,1.336,129,1.133,131,1.225,159,2.394,160,2.394,193,1.847,213,1.278,214,2.16,271,1.847,272,1.632,279,1.468,291,2.16,295,1.847,296,2.35,340,1.986,341,2.394,342,1.986,343,1.986,344,6.078,345,6.078,346,2.748,347,2.748,348,2.748,349,2.748,350,1.986,351,1.986,352,2.748,353,2.394,354,1.847,355,2.748,356,2.748,357,2.748,358,2.748,359,2.748]],["tags/34",[]],["title/35",[130,1.153,288,2.13]],["content/35",[0,1.025,5,1.176,93,2.659,108,2.075,117,4.143,123,1.754,125,1.686,129,1.284,130,1.176,135,2.535,213,1.985,272,2.535,277,2.869,288,2.918,326,3.718,360,2.69,361,2.869,362,4.269]],["tags/35",[]],["title/36",[129,0.937,259,2.485]],["content/36",[0,1.198,6,1.032,42,2.349,83,1.638,123,1.436,125,1.381,129,0.783,130,1.375,132,1.381,134,2.321,181,1.966,217,1.699,236,2.349,259,3.77,270,1.867,308,3.923,323,2.526,331,2.202,337,2.349,360,2.202,361,2.349,363,3.495,364,2.526,365,3.044,366,2.748,367,3.044,368,2.349,369,2.748,370,2.748]],["tags/36",[]],["title/37",[93,1.719,196,3.024]],["content/37",[5,0.432,29,1.232,46,0.931,50,1.054,63,0.988,77,1.054,83,1.135,86,0.881,93,0.644,119,0.613,125,2.086,182,1.232,217,1.681,221,1.365,234,0.931,269,1.494,270,2.176,271,1.054,272,0.931,279,1.848,280,1.365,295,2.325,296,1.494,321,1.365,325,2.291,339,1.365,342,1.921,343,1.133,350,1.133,351,1.133,354,1.786,360,0.988,368,1.054,371,1.365,372,2.566,373,1.232,374,1.054,375,1.365,376,3.585,377,1.365,378,1.232,379,2.657,380,1.567,381,1.567,382,1.567,383,1.567,384,1.567,385,1.567,386,1.567,387,1.567,388,1.567,389,1.567,390,1.232,391,1.567,392,3.013,393,3.013,394,1.365,395,1.365,396,1.232,397,2.719,398,1.054,399,0.988,400,1.232,401,1.232,402,2.738,403,1.232,404,1.786,405,1.365,406,1.365,407,1.365,408,1.365,409,1.365,410,1.232,411,2.089,412,1.232,413,1.365,414,1.365,415,1.365,416,1.232,417,2.315,418,1.365,419,1.365,420,1.365,421,1.365,422,1.365]],["tags/37",[]],["title/27",[63,3.247]],["content/27",[4,1.688,119,0.86,423,4.131,424,3.394,425,4.978,426,3.6,427,4.978]],["tags/27",[]],["title/28",[4,0.898,119,0.458,423,2.197,424,1.806]],["content/28",[425,5.438,426,3.934,427,5.438]],["tags/28",[]],["title/38",[4,1.04,423,2.545,424,2.092]],["content/38",[0,0.718,4,0.884,6,1.572,62,2.162,63,1.885,118,2.352,228,2.352,269,1.682,285,2.606,353,2.606,364,3.22,398,2.995,399,2.807,423,3.847,424,3.927,426,2.807,428,2.991,429,2.162,430,2.162,431,2.352,432,2.352,433,2.991,434,4.455,435,4.455,436,2.991,437,2.991,438,2.991,439,4.455,440,2.162,441,1.885,442,2.991,443,2.606,444,2.991,445,2.991]],["tags/38",[]],["title/39",[446,5.154]],["content/39",[3,1.798,4,0.994,17,1.798,22,2.432,38,1.998,42,2.262,83,1.594,92,2.931,93,1.995,123,1.382,179,2.645,189,3.51,217,1.636,237,2.931,261,2.931,273,2.931,364,3.51,365,2.931,424,3.705,430,2.432,447,3.364,448,3.364,449,3.364,450,4.23,451,4.855,452,2.931,453,3.364,454,2.931,455,3.364,456,3.364,457,3.364]],["tags/39",[]],["title/40",[458,3.725]],["content/40",[0,1.009,3,2.245,4,1.241,5,1.158,6,1.241,28,3.037,31,2.363,34,3.304,58,2.441,75,2.887,134,1.954,185,1.873,193,2.825,234,2.496,246,2.825,284,4.941,441,2.648,459,4.202,460,3.304,461,3.037]],["tags/40",[]],["title/41",[0,0.73,6,0.898,108,1.478,426,1.915]],["content/41",[]],["tags/41",[]],["title/42",[0,0.845,6,1.04,129,0.789]],["content/42",[0,1.195,6,1.872,58,1.892,129,1.115,217,2.419,292,4.335,293,3.913,294,4.335,295,3.346,296,2.799,297,3.346,298,3.597,462,4.977]],["tags/42",[]],["title/43",[130,0.838,132,1.201,256,1.806,302,2.044]],["content/43",[0,1.229,3,2.268,4,0.828,5,1.17,6,1.686,10,1.666,12,1.152,13,2.028,20,2.028,83,0.921,93,1.744,117,2.028,123,1.152,125,1.108,131,1.892,132,1.108,135,1.666,174,3.337,181,1.578,185,1.25,205,1.364,235,2.674,236,1.886,247,2.443,249,2.205,256,3.042,301,1.767,302,1.886,303,3.337,320,2.443,331,1.767,336,2.443,337,1.886,400,2.205,463,4.245,464,2.805,465,2.205,466,2.805,467,2.443,468,2.205,469,2.805]],["tags/43",[]],["title/44",[130,1.153,288,2.13]],["content/44",[0,1.087,6,1.593,83,1.004,123,1.257,129,1.493,130,0.843,134,1.423,164,2.405,185,1.363,205,1.487,264,2.211,277,2.056,279,1.635,288,1.557,289,2.405,331,1.928,337,2.056,341,2.665,342,2.211,343,2.211,350,2.211,351,2.211,360,1.928,361,2.056,364,2.211,366,2.405,390,2.405,441,2.854,470,2.665,471,2.665,472,2.665,473,3.059,474,3.059,475,3.059,476,3.059,477,2.665,478,2.665,479,3.059,480,3.059]],["tags/44",[]],["title/45",[6,1.236,426,2.636]],["content/45",[0,0.61,6,1.733,83,1.581,86,1.429,93,1.979,123,1.044,125,1.903,129,1.079,130,0.7,137,1.509,196,3.92,201,1.998,205,1.235,215,2.213,235,1.601,255,2.213,269,1.429,270,1.358,272,1.509,278,2.213,288,1.294,296,1.429,297,1.708,298,1.837,324,3.428,354,1.708,367,2.213,378,1.998,426,2.48,430,1.837,431,1.998,432,1.998,460,1.998,478,2.213,481,2.541,482,2.541,483,3.935,484,1.998,485,2.541,486,2.541,487,2.213,488,1.998,489,1.837,490,2.541,491,2.541,492,2.541,493,2.213,494,2.541]],["tags/45",[]],["title/46",[228,2.39,259,1.806,450,2.648,495,3.04]],["content/46",[0,0.788,4,0.969,6,1.659,8,2.581,108,1.596,123,2.534,129,1.259,130,0.904,188,3.75,205,1.596,259,3.337,293,2.581,304,2.373,340,2.373,424,1.95,429,2.373,452,2.859,454,2.859,465,2.581,468,2.581,496,3.282,497,3.282,498,3.282,499,3.282,500,3.282,501,3.282,502,3.282,503,3.282,504,2.859,505,3.282,506,3.282,507,3.282]],["tags/46",[]],["title/47",[123,1.719,129,0.937]],["content/47",[0,0.981,3,1.425,4,0.788,6,1.206,22,1.927,37,2.323,38,1.584,83,1.341,96,2.323,123,1.095,125,1.053,129,1.112,130,1.125,132,1.053,134,1.9,181,2.297,197,2.323,205,1.296,210,3.211,236,1.792,259,3.562,270,2.182,274,2.323,277,1.792,308,3.211,323,1.927,325,1.5,331,1.68,337,1.792,360,1.68,361,1.792,366,2.096,368,1.792,369,3.211,370,2.096,372,1.68,429,1.927,477,2.323,484,2.096,488,2.096,489,1.927,508,2.323,509,2.666,510,2.666,511,2.666]],["tags/47",[]],["title/48",[130,0.838,369,2.39,512,3.04,513,2.648]],["content/48",[50,3.063,107,3.294,108,2.215,129,1.021,130,1.256,132,1.8,181,2.563,205,2.215,259,2.707,323,3.294,340,3.294,370,3.583,429,3.294,508,3.97,513,3.97,514,4.557,515,4.557,516,4.557,517,4.557]],["tags/48",[]],["title/49",[4,0.898,93,1.249,123,1.249,279,1.624]],["content/49",[46,1.701,50,1.926,83,1.416,86,1.611,93,1.177,119,0.431,125,1.704,129,0.642,205,1.393,210,2.252,217,2.521,264,2.071,269,1.611,270,2.304,271,1.926,279,2.304,295,1.926,342,3.117,343,2.071,354,1.926,371,2.495,372,3.268,373,2.252,375,2.495,376,2.252,377,2.495,390,2.252,398,2.899,399,2.717,411,2.252,417,3.757,418,2.495,419,2.495,420,2.495,421,2.495,422,2.495,441,1.805,518,2.864,519,2.864,520,2.864,521,2.864,522,2.864]],["tags/49",[]],["title/50",[125,1.057,130,0.737,184,2.33,265,1.504,404,1.798]],["content/50",[5,0.728,29,2.076,46,1.568,63,1.664,83,0.867,119,0.397,125,2.359,182,2.076,234,1.568,269,1.485,270,2.166,272,1.568,279,1.411,325,2.775,350,1.909,351,1.909,354,1.775,368,1.775,372,1.664,376,3.879,392,3.531,393,3.531,394,2.3,395,2.3,396,2.076,397,3.879,398,1.775,399,1.664,400,2.076,401,2.076,402,3.72,403,2.076,404,2.725,405,2.3,406,2.3,407,2.3,408,2.3,409,2.3,410,2.076,411,2.076,412,2.076,413,2.3,414,2.3,415,2.3,416,2.076]],["tags/50",[]],["title/51",[130,0.838,205,1.478,217,1.478,404,2.044]],["content/51",[5,0.939,111,2.968,119,1.099,125,1.346,130,0.939,132,2.479,218,2.463,301,2.146,396,2.678,397,2.678,398,3.857,399,2.146,401,2.678,402,2.29,404,2.29,416,2.678,440,3.542,465,2.678,504,2.968,523,3.407,524,3.407,525,3.407,526,3.407,527,3.407,528,3.407,529,3.407]],["tags/51",[]],["title/52",[130,1.153,265,2.353]],["content/52",[0,1.17,6,1.618,50,1.741,81,2.256,86,1.456,93,1.064,107,1.872,125,2.471,129,0.895,130,1.343,145,2.256,208,2.036,217,1.259,264,1.872,265,3.081,267,2.256,270,2.134,272,2.895,288,2.033,360,1.632,361,1.741,368,1.741,372,1.632,373,3.14,378,2.036,460,3.832,468,2.036,530,2.59,531,2.59,532,2.59,533,2.887,534,2.887,535,3.993,536,3.479,537,2.59,538,2.59,539,2.256]],["tags/52",[]],["title/53",[265,1.98,540,3.068,541,2.769]],["content/53",[0,0.61,2,2.213,5,0.7,82,2.213,83,1.581,123,1.044,125,1.903,129,0.569,130,1.084,151,2.213,208,1.998,217,1.235,235,2.48,265,2.709,269,1.429,270,1.358,279,1.358,288,1.294,296,3.05,372,1.601,399,1.601,402,2.645,410,1.998,412,1.998,424,1.509,430,1.837,432,1.998,443,2.213,467,2.213,484,1.998,488,1.998,534,2.845,536,2.213,539,2.213,540,3.428,541,3.094,542,2.541,543,5.423,544,5.423,545,2.541,546,3.935,547,2.541,548,2.541,549,2.541]],["tags/53",[]],["title/54",[116,3.645,117,3.024]],["content/54",[58,1.928,75,2.581,108,2.465,119,1.059,246,3.408,374,3.408,458,3.665,461,3.665,533,3.665,550,3.987,551,3.987]],["tags/54",[]],["title/55",[75,2.13,119,0.63]],["content/55",[461,4.411,533,4.411,550,4.798,551,4.798]],["tags/55",[]],["title/56",[58,1.339,119,0.53,246,2.367]],["content/56",[458,4.732]],["tags/56",[]],["title/57",[108,1.712,119,0.53,374,2.367]],["content/57",[]],["tags/57",[]],["title/58",[58,1.591,185,1.865]],["content/58",[]],["tags/58",[]],["title/59",[458,3.725]],["content/59",[13,3.597,32,2.419,58,1.892,75,2.534,134,2.315,185,2.218,216,3.913,290,3.913,489,3.597,552,6.337,553,4.977,554,4.977,555,3.346]],["tags/59",[]],["title/60",[31,1.71,32,1.478,83,0.998,300,2.648]],["content/60",[17,1.779,28,1.487,30,1.099,31,3.185,32,2.038,46,1.222,58,0.782,78,1.617,87,2.642,119,0.991,134,0.957,169,1.617,181,1.872,185,0.917,189,1.487,234,1.977,265,1.157,271,1.383,301,2.097,325,2.71,340,1.487,403,1.617,431,3.297,470,1.792,471,1.792,472,1.792,555,3.807,556,4.818,557,3.329,558,4.818,559,2.057,560,2.057,561,4.193,562,4.193,563,3.329,564,4.193,565,1.792,566,2.9,567,2.057,568,2.057,569,2.057,570,2.057,571,2.057,572,2.057]],["tags/60",[]],["title/61",[185,1.569,213,1.638,573,2.545]],["content/61",[28,2.211,30,1.635,31,1.721,32,1.487,70,2.211,83,1.487,119,0.812,157,2.665,181,1.721,185,2.019,213,2.107,234,2.69,288,1.557,304,2.211,325,2.547,440,2.211,441,1.928,534,2.211,555,2.056,573,3.899,574,5.394,575,3.059,576,3.059,577,3.059,578,3.059,579,3.059,580,3.059,581,3.059,582,3.059,583,3.059,584,3.059,585,3.059,586,3.059,587,2.665,588,3.059,589,2.405,590,3.059]],["tags/61",[]],["title/62",[32,1.712,58,1.339,185,1.569]],["content/62",[7,0.751,16,1.324,30,0.863,32,2.603,46,0.959,58,1.578,83,0.53,93,0.663,119,1.043,127,2.142,131,0.719,137,0.959,183,1.406,185,1.214,187,4.066,193,1.085,213,1.644,219,1.269,256,0.959,265,0.908,269,0.908,296,1.532,301,1.716,325,2.829,374,1.085,440,1.167,441,1.017,489,1.969,493,2.373,555,2.376,565,1.406,566,1.406,573,2.555,587,1.406,589,2.779,591,1.614,592,3.079,593,1.614,594,2.724,595,2.724,596,2.724,597,2.724,598,2.724,599,2.724,600,1.614,601,1.614,602,1.614,603,2.724,604,1.614,605,1.614,606,1.614,607,1.614,608,1.614,609,1.614,610,1.614,611,2.724,612,2.724,613,2.724,614,1.614,615,2.724,616,1.614,617,1.614]],["tags/62",[]],["title/63",[618,4.489]],["content/63",[0,0.743,3,1.653,32,2.221,56,2.08,58,1.737,84,2.237,108,1.504,119,0.817,185,2.036,187,2.237,213,2.974,219,2.433,289,2.433,304,2.237,325,2.569,534,2.237,541,2.433,555,3.071,573,4.623,589,3.591,592,2.696,618,2.696,619,3.094,620,3.094,621,3.094,622,6.395,623,3.094]],["tags/63",[]],["title/116",[108,2.034,374,2.813]],["content/116",[]],["tags/116",[]],["title/117",[75,2.624]],["content/117",[0,1.551,31,2.045,75,1.851,134,2.387,290,2.859,291,4.035,402,3.45,461,3.71,487,3.168,533,2.628,550,4.677,551,4.035,624,5.132,625,5.132,626,3.636,627,3.636,628,3.636,629,3.636,630,3.636,631,3.636,632,3.636,633,3.636]],["tags/117",[]]],"invertedIndex":[["",{"_index":119,"title":{"16":{},"17":{},"18":{},"19":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"28":{},"55":{},"56":{},"57":{},"109":{},"110":{},"111":{},"112":{},"113":{}},"content":{"16":{},"17":{},"18":{},"19":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"31":{},"37":{},"49":{},"50":{},"51":{},"54":{},"60":{},"61":{},"62":{},"63":{},"108":{}},"tags":{}}],["1",{"_index":127,"title":{},"content":{"62":{},"108":{},"112":{}},"tags":{}}],["1.29",{"_index":593,"title":{},"content":{"62":{}},"tags":{}}],["2",{"_index":77,"title":{},"content":{"14":{},"37":{},"105":{},"108":{},"113":{}},"tags":{}}],["203.0.113.34",{"_index":416,"title":{},"content":{"37":{},"50":{},"51":{}},"tags":{}}],["3",{"_index":121,"title":{},"content":{"108":{},"109":{}},"tags":{}}],["30",{"_index":382,"title":{},"content":{"37":{}},"tags":{}}],["32049705",{"_index":610,"title":{},"content":{"62":{}},"tags":{}}],["32238657",{"_index":616,"title":{},"content":{"62":{}},"tags":{}}],["45",{"_index":617,"title":{},"content":{"62":{}},"tags":{}}],["5",{"_index":124,"title":{},"content":{"108":{},"111":{}},"tags":{}}],["60",{"_index":413,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b",{"_index":529,"title":{},"content":{"51":{}},"tags":{}}],["9m47",{"_index":614,"title":{},"content":{"62":{}},"tags":{}}],["abov",{"_index":588,"title":{},"content":{"61":{}},"tags":{}}],["accept",{"_index":180,"title":{},"content":{"12":{}},"tags":{}}],["access",{"_index":46,"title":{},"content":{"34":{},"37":{},"49":{},"50":{},"60":{},"62":{},"105":{}},"tags":{}}],["accommod",{"_index":243,"title":{},"content":{"14":{}},"tags":{}}],["account",{"_index":553,"title":{},"content":{"59":{}},"tags":{}}],["action",{"_index":114,"title":{},"content":{"107":{}},"tags":{}}],["activ",{"_index":147,"title":{},"content":{"10":{}},"tags":{}}],["actual",{"_index":469,"title":{},"content":{"43":{}},"tags":{}}],["ad",{"_index":174,"title":{},"content":{"11":{},"14":{},"43":{}},"tags":{}}],["add",{"_index":301,"title":{},"content":{"31":{},"32":{},"43":{},"51":{},"60":{},"62":{}},"tags":{}}],["addit",{"_index":236,"title":{},"content":{"14":{},"31":{},"36":{},"43":{},"47":{}},"tags":{}}],["address",{"_index":377,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["admin",{"_index":57,"title":{},"content":{"105":{}},"tags":{}}],["administr",{"_index":59,"title":{},"content":{"105":{},"106":{}},"tags":{}}],["afterward",{"_index":570,"title":{},"content":{"60":{}},"tags":{}}],["ag",{"_index":608,"title":{},"content":{"62":{}},"tags":{}}],["agent",{"_index":178,"title":{},"content":{"12":{}},"tags":{}}],["aim",{"_index":143,"title":{},"content":{"10":{}},"tags":{}}],["ak",{"_index":32,"title":{"13":{},"60":{},"62":{}},"content":{"13":{},"14":{},"59":{},"60":{},"61":{},"62":{},"63":{},"104":{}},"tags":{}}],["allow",{"_index":431,"title":{},"content":{"38":{},"45":{},"60":{}},"tags":{}}],["alreadi",{"_index":465,"title":{},"content":{"43":{},"46":{},"51":{}},"tags":{}}],["altern",{"_index":393,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["alway",{"_index":43,"title":{},"content":{"105":{}},"tags":{}}],["annot",{"_index":302,"title":{"32":{},"43":{}},"content":{"31":{},"32":{},"43":{}},"tags":{}}],["anoth",{"_index":532,"title":{},"content":{"52":{}},"tags":{}}],["api",{"_index":164,"title":{},"content":{"11":{},"12":{},"44":{}},"tags":{}}],["app",{"_index":430,"title":{},"content":{"38":{},"39":{},"45":{},"53":{}},"tags":{}}],["appli",{"_index":297,"title":{"33":{}},"content":{"30":{},"33":{},"42":{},"45":{}},"tags":{}}],["applic",{"_index":255,"title":{},"content":{"14":{},"45":{}},"tags":{}}],["approach",{"_index":27,"title":{},"content":{"104":{}},"tags":{}}],["appropri",{"_index":166,"title":{},"content":{"11":{}},"tags":{}}],["architectur",{"_index":118,"title":{"108":{}},"content":{"14":{},"38":{}},"tags":{}}],["archiv",{"_index":626,"title":{},"content":{"117":{}},"tags":{}}],["artifact",{"_index":512,"title":{"48":{}},"content":{},"tags":{}}],["attack",{"_index":60,"title":{},"content":{"105":{}},"tags":{}}],["attempt",{"_index":407,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["attest",{"_index":123,"title":{"47":{},"49":{},"111":{}},"content":{"12":{},"14":{},"35":{},"36":{},"39":{},"43":{},"44":{},"45":{},"46":{},"47":{},"53":{},"108":{}},"tags":{}}],["attestation’",{"_index":268,"title":{},"content":{"14":{}},"tags":{}}],["audit",{"_index":513,"title":{"48":{}},"content":{"48":{}},"tags":{}}],["authent",{"_index":260,"title":{},"content":{"14":{}},"tags":{}}],["author",{"_index":208,"title":{},"content":{"12":{},"52":{},"53":{}},"tags":{}}],["avail",{"_index":441,"title":{},"content":{"38":{},"40":{},"44":{},"49":{},"61":{},"62":{}},"tags":{}}],["aw",{"_index":238,"title":{},"content":{"14":{}},"tags":{}}],["az",{"_index":555,"title":{},"content":{"59":{},"60":{},"61":{},"62":{},"63":{}},"tags":{}}],["azclusternam",{"_index":592,"title":{},"content":{"62":{},"63":{}},"tags":{}}],["azclustername=\"contrastdemo",{"_index":591,"title":{},"content":{"62":{}},"tags":{}}],["azloc",{"_index":590,"title":{},"content":{"61":{}},"tags":{}}],["azlocation=\"westu",{"_index":586,"title":{},"content":{"61":{}},"tags":{}}],["azresourcegroup",{"_index":589,"title":{},"content":{"61":{},"62":{},"63":{}},"tags":{}}],["azresourcegroup=\"contrastdemo",{"_index":585,"title":{},"content":{"61":{}},"tags":{}}],["azur",{"_index":216,"title":{},"content":{"13":{},"14":{},"59":{}},"tags":{}}],["azurelinux",{"_index":596,"title":{},"content":{"62":{}},"tags":{}}],["backend",{"_index":439,"title":{},"content":{"38":{}},"tags":{}}],["balanc",{"_index":351,"title":{},"content":{"34":{},"37":{},"44":{},"50":{}},"tags":{}}],["ballot",{"_index":450,"title":{"46":{}},"content":{"39":{}},"tags":{}}],["bare",{"_index":190,"title":{},"content":{"12":{}},"tags":{}}],["base",{"_index":9,"title":{},"content":{"11":{},"104":{},"105":{}},"tags":{}}],["bash",{"_index":383,"title":{},"content":{"37":{}},"tags":{}}],["be",{"_index":473,"title":{},"content":{"44":{}},"tags":{}}],["befor",{"_index":468,"title":{},"content":{"43":{},"46":{},"52":{}},"tags":{}}],["begin",{"_index":242,"title":{},"content":{"14":{}},"tags":{}}],["benefit",{"_index":88,"title":{"15":{}},"content":{"14":{},"106":{},"107":{}},"tags":{}}],["beyond",{"_index":231,"title":{},"content":{"14":{}},"tags":{}}],["block",{"_index":140,"title":{},"content":{"10":{},"33":{}},"tags":{}}],["board",{"_index":435,"title":{},"content":{"38":{}},"tags":{}}],["bot",{"_index":443,"title":{},"content":{"38":{},"53":{}},"tags":{}}],["both",{"_index":261,"title":{},"content":{"14":{},"39":{}},"tags":{}}],["browser",{"_index":522,"title":{},"content":{"49":{}},"tags":{}}],["build",{"_index":139,"title":{},"content":{"10":{},"31":{}},"tags":{}}],["bundl",{"_index":461,"title":{},"content":{"40":{},"54":{},"55":{},"117":{}},"tags":{}}],["c",{"_index":360,"title":{},"content":{"35":{},"36":{},"37":{},"44":{},"47":{},"52":{}},"tags":{}}],["ca",{"_index":373,"title":{},"content":{"37":{},"49":{},"52":{}},"tags":{}}],["cacert",{"_index":410,"title":{},"content":{"37":{},"50":{},"53":{}},"tags":{}}],["cafil",{"_index":419,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["call",{"_index":165,"title":{},"content":{"11":{},"12":{}},"tags":{}}],["can't",{"_index":349,"title":{},"content":{"34":{}},"tags":{}}],["capabl",{"_index":175,"title":{},"content":{"11":{},"13":{}},"tags":{}}],["case",{"_index":84,"title":{"106":{}},"content":{"11":{},"63":{},"106":{}},"tags":{}}],["cc",{"_index":320,"title":{},"content":{"31":{},"43":{}},"tags":{}}],["centralindia",{"_index":575,"title":{},"content":{"61":{}},"tags":{}}],["cert",{"_index":326,"title":{},"content":{"31":{},"35":{}},"tags":{}}],["certif",{"_index":125,"title":{"50":{},"112":{}},"content":{"14":{},"31":{},"35":{},"36":{},"37":{},"43":{},"45":{},"47":{},"49":{},"50":{},"51":{},"52":{},"53":{},"108":{}},"tags":{}}],["chain",{"_index":535,"title":{},"content":{"52":{}},"tags":{}}],["chang",{"_index":81,"title":{},"content":{"52":{},"105":{}},"tags":{}}],["channel",{"_index":509,"title":{},"content":{"47":{}},"tags":{}}],["chart",{"_index":251,"title":{},"content":{"14":{},"31":{}},"tags":{}}],["chart_nam",{"_index":314,"title":{},"content":{"31":{}},"tags":{}}],["check",{"_index":403,"title":{},"content":{"37":{},"50":{},"60":{}},"tags":{}}],["checksum",{"_index":209,"title":{},"content":{"12":{}},"tags":{}}],["class",{"_index":463,"title":{},"content":{"43":{}},"tags":{}}],["clean",{"_index":620,"title":{},"content":{"63":{}},"tags":{}}],["cleanup",{"_index":618,"title":{"63":{}},"content":{"63":{}},"tags":{}}],["cli",{"_index":134,"title":{"4":{},"24":{}},"content":{"22":{},"23":{},"24":{},"36":{},"40":{},"44":{},"47":{},"59":{},"60":{},"117":{}},"tags":{}}],["cloud",{"_index":56,"title":{},"content":{"12":{},"14":{},"63":{},"105":{},"106":{}},"tags":{}}],["cluster",{"_index":58,"title":{"56":{},"58":{},"62":{}},"content":{"13":{},"14":{},"29":{},"30":{},"33":{},"40":{},"42":{},"54":{},"59":{},"60":{},"62":{},"63":{},"105":{},"106":{}},"tags":{}}],["cncf",{"_index":141,"title":{},"content":{"10":{}},"tags":{}}],["co",{"_index":65,"title":{},"content":{"105":{}},"tags":{}}],["coco",{"_index":30,"title":{"13":{}},"content":{"10":{},"13":{},"29":{},"34":{},"60":{},"61":{},"62":{},"104":{}},"tags":{}}],["coco'",{"_index":173,"title":{},"content":{"11":{}},"tags":{}}],["code",{"_index":96,"title":{},"content":{"47":{},"106":{}},"tags":{}}],["collabor",{"_index":106,"title":{},"content":{"106":{}},"tags":{}}],["come",{"_index":61,"title":{},"content":{"105":{}},"tags":{}}],["command",{"_index":181,"title":{},"content":{"12":{},"32":{},"36":{},"43":{},"47":{},"48":{},"60":{},"61":{}},"tags":{}}],["commun",{"_index":196,"title":{"37":{}},"content":{"12":{},"14":{},"45":{}},"tags":{}}],["compat",{"_index":73,"title":{},"content":{"14":{},"105":{}},"tags":{}}],["complianc",{"_index":103,"title":{},"content":{"106":{}},"tags":{}}],["compon",{"_index":120,"title":{"109":{}},"content":{"14":{},"108":{}},"tags":{}}],["compris",{"_index":292,"title":{},"content":{"30":{},"42":{}},"tags":{}}],["compromis",{"_index":267,"title":{},"content":{"14":{},"52":{}},"tags":{}}],["comput",{"_index":38,"title":{},"content":{"10":{},"11":{},"39":{},"47":{},"104":{},"105":{},"106":{}},"tags":{}}],["concept",{"_index":110,"title":{},"content":{"14":{},"107":{}},"tags":{}}],["concis",{"_index":257,"title":{},"content":{"14":{}},"tags":{}}],["confidenti",{"_index":4,"title":{"7":{},"10":{},"28":{},"38":{},"49":{},"110":{}},"content":{"10":{},"11":{},"12":{},"14":{},"27":{},"29":{},"31":{},"34":{},"38":{},"39":{},"40":{},"43":{},"46":{},"47":{},"104":{},"106":{},"107":{},"108":{}},"tags":{}}],["config",{"_index":333,"title":{},"content":{"31":{}},"tags":{}}],["configur",{"_index":205,"title":{"51":{}},"content":{"12":{},"14":{},"31":{},"43":{},"44":{},"45":{},"46":{},"47":{},"48":{},"49":{}},"tags":{}}],["connect",{"_index":279,"title":{"34":{},"49":{}},"content":{"14":{},"34":{},"37":{},"44":{},"49":{},"50":{},"53":{}},"tags":{}}],["consid",{"_index":447,"title":{},"content":{"39":{}},"tags":{}}],["consist",{"_index":437,"title":{},"content":{"38":{}},"tags":{}}],["contain",{"_index":5,"title":{"7":{},"10":{},"12":{},"23":{},"110":{},"148":{}},"content":{"10":{},"11":{},"12":{},"14":{},"22":{},"23":{},"24":{},"31":{},"34":{},"35":{},"37":{},"40":{},"43":{},"50":{},"51":{},"53":{},"104":{},"106":{},"107":{},"108":{}},"tags":{}}],["containerd",{"_index":162,"title":{},"content":{"11":{}},"tags":{}}],["containers/issues/1693",{"_index":359,"title":{},"content":{"34":{}},"tags":{}}],["containers/kata",{"_index":358,"title":{},"content":{"34":{}},"tags":{}}],["containerservic",{"_index":572,"title":{},"content":{"60":{}},"tags":{}}],["contrast",{"_index":0,"title":{"30":{},"34":{},"41":{},"42":{},"104":{}},"content":{"10":{},"13":{},"14":{},"29":{},"30":{},"31":{},"32":{},"35":{},"36":{},"38":{},"40":{},"42":{},"43":{},"44":{},"45":{},"46":{},"47":{},"52":{},"53":{},"63":{},"104":{},"105":{},"106":{},"107":{},"117":{}},"tags":{}}],["contrast.zip",{"_index":628,"title":{},"content":{"117":{}},"tags":{}}],["coordin",{"_index":129,"title":{"6":{},"21":{},"22":{},"30":{},"34":{},"36":{},"42":{},"47":{},"114":{}},"content":{"17":{},"18":{},"19":{},"20":{},"21":{},"22":{},"23":{},"24":{},"30":{},"31":{},"33":{},"34":{},"35":{},"36":{},"42":{},"44":{},"45":{},"46":{},"47":{},"48":{},"49":{},"52":{},"53":{}},"tags":{}}],["coordinator'",{"_index":371,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["coordinator.yml",{"_index":462,"title":{},"content":{"42":{}},"tags":{}}],["coordinator:1313",{"_index":474,"title":{},"content":{"44":{}},"tags":{}}],["coordinator=$(kubectl",{"_index":341,"title":{},"content":{"34":{},"44":{}},"tags":{}}],["coordinator_host",{"_index":330,"title":{},"content":{"31":{}},"tags":{}}],["coordinator}:1313",{"_index":361,"title":{},"content":{"35":{},"36":{},"44":{},"47":{},"52":{}},"tags":{}}],["copi",{"_index":306,"title":{},"content":{"31":{}},"tags":{}}],["core",{"_index":89,"title":{},"content":{"10":{},"106":{}},"tags":{}}],["count",{"_index":599,"title":{},"content":{"62":{}},"tags":{}}],["cp",{"_index":315,"title":{},"content":{"31":{}},"tags":{}}],["creat",{"_index":185,"title":{"58":{},"61":{},"62":{}},"content":{"12":{},"32":{},"40":{},"43":{},"44":{},"59":{},"60":{},"61":{},"62":{},"63":{}},"tags":{}}],["credenti",{"_index":493,"title":{},"content":{"45":{},"62":{}},"tags":{}}],["cri",{"_index":160,"title":{},"content":{"11":{},"34":{}},"tags":{}}],["crun",{"_index":172,"title":{},"content":{"11":{}},"tags":{}}],["curl",{"_index":402,"title":{},"content":{"37":{},"50":{},"51":{},"53":{},"117":{}},"tags":{}}],["current",{"_index":28,"title":{},"content":{"40":{},"60":{},"61":{},"104":{}},"tags":{}}],["cvm",{"_index":202,"title":{},"content":{"12":{},"13":{}},"tags":{}}],["data",{"_index":42,"title":{},"content":{"14":{},"36":{},"39":{},"105":{},"106":{}},"tags":{}}],["datacent",{"_index":53,"title":{},"content":{"105":{}},"tags":{}}],["day",{"_index":76,"title":{},"content":{"14":{},"105":{}},"tags":{}}],["decid",{"_index":496,"title":{},"content":{"46":{}},"tags":{}}],["default",{"_index":394,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["defin",{"_index":482,"title":{},"content":{"45":{}},"tags":{}}],["definit",{"_index":214,"title":{},"content":{"12":{},"31":{},"34":{}},"tags":{}}],["deleg",{"_index":515,"title":{},"content":{"48":{}},"tags":{}}],["delet",{"_index":622,"title":{},"content":{"63":{}},"tags":{}}],["demo",{"_index":400,"title":{},"content":{"37":{},"43":{},"50":{}},"tags":{}}],["deploy",{"_index":6,"title":{"29":{},"30":{},"41":{},"42":{},"45":{}},"content":{"13":{},"14":{},"29":{},"30":{},"31":{},"32":{},"34":{},"36":{},"38":{},"40":{},"42":{},"43":{},"44":{},"45":{},"46":{},"47":{},"52":{},"104":{},"105":{}},"tags":{}}],["deployment/emoji",{"_index":545,"title":{},"content":{"53":{}},"tags":{}}],["deployment/vot",{"_index":546,"title":{},"content":{"53":{}},"tags":{}}],["deployment/web",{"_index":547,"title":{},"content":{"53":{}},"tags":{}}],["deriv",{"_index":212,"title":{},"content":{"12":{}},"tags":{}}],["design",{"_index":40,"title":{},"content":{"12":{},"14":{},"105":{}},"tags":{}}],["dev/nul",{"_index":422,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["develop",{"_index":148,"title":{},"content":{"10":{}},"tags":{}}],["differ",{"_index":432,"title":{},"content":{"38":{},"45":{},"53":{}},"tags":{}}],["directli",{"_index":224,"title":{},"content":{"13":{}},"tags":{}}],["directori",{"_index":308,"title":{},"content":{"31":{},"36":{},"47":{}},"tags":{}}],["dispatch",{"_index":163,"title":{},"content":{"11":{}},"tags":{}}],["distribut",{"_index":498,"title":{},"content":{"46":{}},"tags":{}}],["dn",{"_index":396,"title":{},"content":{"37":{},"50":{},"51":{}},"tags":{}}],["do",{"_index":499,"title":{},"content":{"46":{}},"tags":{}}],["document",{"_index":2,"title":{},"content":{"53":{},"104":{}},"tags":{}}],["don't",{"_index":266,"title":{},"content":{"14":{}},"tags":{}}],["done",{"_index":280,"title":{},"content":{"14":{},"37":{}},"tags":{}}],["download",{"_index":550,"title":{},"content":{"54":{},"55":{},"117":{}},"tags":{}}],["dure",{"_index":475,"title":{},"content":{"44":{}},"tags":{}}],["e.g",{"_index":631,"title":{},"content":{"117":{}},"tags":{}}],["each",{"_index":494,"title":{},"content":{"45":{}},"tags":{}}],["eastu",{"_index":576,"title":{},"content":{"61":{}},"tags":{}}],["eastus2euap",{"_index":577,"title":{},"content":{"61":{}},"tags":{}}],["echo",{"_index":390,"title":{},"content":{"37":{},"44":{},"49":{}},"tags":{}}],["edit",{"_index":525,"title":{},"content":{"51":{}},"tags":{}}],["editor",{"_index":527,"title":{},"content":{"51":{}},"tags":{}}],["ek",{"_index":239,"title":{},"content":{"14":{}},"tags":{}}],["embed",{"_index":366,"title":{},"content":{"36":{},"44":{},"47":{}},"tags":{}}],["emoji",{"_index":423,"title":{"28":{},"38":{}},"content":{"27":{},"38":{}},"tags":{}}],["emojivoto",{"_index":426,"title":{"41":{},"45":{}},"content":{"27":{},"28":{},"38":{},"45":{}},"tags":{}}],["employ",{"_index":229,"title":{},"content":{"14":{}},"tags":{}}],["employe",{"_index":54,"title":{},"content":{"105":{}},"tags":{}}],["emptydir",{"_index":335,"title":{},"content":{"31":{}},"tags":{}}],["enabl",{"_index":218,"title":{},"content":{"13":{},"14":{},"29":{},"51":{}},"tags":{}}],["encrypt",{"_index":44,"title":{"113":{}},"content":{"105":{},"108":{}},"tags":{}}],["end",{"_index":363,"title":{},"content":{"36":{}},"tags":{}}],["enforc",{"_index":507,"title":{},"content":{"46":{}},"tags":{}}],["ensur",{"_index":264,"title":{},"content":{"14":{},"44":{},"49":{},"52":{}},"tags":{}}],["entir",{"_index":233,"title":{},"content":{"14":{}},"tags":{}}],["entiti",{"_index":517,"title":{},"content":{"48":{}},"tags":{}}],["entri",{"_index":397,"title":{},"content":{"37":{},"50":{},"51":{}},"tags":{}}],["env",{"_index":329,"title":{},"content":{"31":{}},"tags":{}}],["environ",{"_index":22,"title":{},"content":{"14":{},"39":{},"47":{},"104":{}},"tags":{}}],["envoy",{"_index":282,"title":{},"content":{"14":{}},"tags":{}}],["error",{"_index":409,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["escal",{"_index":67,"title":{},"content":{"105":{}},"tags":{}}],["establish",{"_index":274,"title":{},"content":{"14":{},"47":{}},"tags":{}}],["etc",{"_index":318,"title":{},"content":{"31":{}},"tags":{}}],["even",{"_index":97,"title":{},"content":{"106":{}},"tags":{}}],["exampl",{"_index":63,"title":{"27":{}},"content":{"11":{},"37":{},"38":{},"50":{},"105":{}},"tags":{}}],["execut",{"_index":13,"title":{},"content":{"32":{},"43":{},"59":{},"104":{}},"tags":{}}],["exist",{"_index":70,"title":{},"content":{"14":{},"29":{},"61":{},"105":{}},"tags":{}}],["expect",{"_index":210,"title":{},"content":{"12":{},"47":{},"49":{}},"tags":{}}],["expos",{"_index":375,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["extend",{"_index":156,"title":{},"content":{"11":{}},"tags":{}}],["extens",{"_index":556,"title":{},"content":{"60":{}},"tags":{}}],["extern",{"_index":263,"title":{},"content":{"14":{}},"tags":{}}],["f",{"_index":298,"title":{},"content":{"30":{},"33":{},"42":{},"45":{}},"tags":{}}],["facilit",{"_index":247,"title":{},"content":{"14":{},"43":{}},"tags":{}}],["fail",{"_index":406,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["fair",{"_index":452,"title":{},"content":{"39":{},"46":{}},"tags":{}}],["favorit",{"_index":526,"title":{},"content":{"51":{}},"tags":{}}],["featur",{"_index":87,"title":{"14":{}},"content":{"10":{},"14":{},"60":{},"106":{},"107":{}},"tags":{}}],["fetch",{"_index":362,"title":{},"content":{"35":{}},"tags":{}}],["few",{"_index":471,"title":{},"content":{"44":{},"60":{}},"tags":{}}],["field",{"_index":405,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["file",{"_index":303,"title":{},"content":{"31":{},"32":{},"43":{}},"tags":{}}],["final",{"_index":605,"title":{},"content":{"62":{}},"tags":{}}],["first",{"_index":374,"title":{"57":{},"116":{}},"content":{"37":{},"54":{},"62":{}},"tags":{}}],["fit",{"_index":518,"title":{},"content":{"49":{}},"tags":{}}],["flag",{"_index":559,"title":{},"content":{"60":{}},"tags":{}}],["flo",{"_index":624,"title":{},"content":{"117":{}},"tags":{}}],["flow",{"_index":82,"title":{},"content":{"53":{},"105":{}},"tags":{}}],["fluentli",{"_index":69,"title":{},"content":{"105":{}},"tags":{}}],["flux",{"_index":152,"title":{},"content":{"10":{}},"tags":{}}],["follow",{"_index":234,"title":{},"content":{"14":{},"29":{},"37":{},"40":{},"50":{},"60":{},"61":{}},"tags":{}}],["forward",{"_index":345,"title":{},"content":{"34":{}},"tags":{}}],["frontend",{"_index":399,"title":{},"content":{"37":{},"38":{},"49":{},"50":{},"51":{},"53":{}},"tags":{}}],["frontendip",{"_index":528,"title":{},"content":{"51":{}},"tags":{}}],["frontendip=$(kubectl",{"_index":519,"title":{},"content":{"49":{}},"tags":{}}],["frontendip}:443",{"_index":421,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["futur",{"_index":502,"title":{},"content":{"46":{}},"tags":{}}],["gener",{"_index":256,"title":{"32":{},"43":{}},"content":{"14":{},"31":{},"32":{},"43":{},"62":{}},"tags":{}}],["germanywestcentr",{"_index":578,"title":{},"content":{"61":{}},"tags":{}}],["get",{"_index":116,"title":{"54":{}},"content":{"107":{}},"tags":{}}],["ghcr.io/edgelesssys/contrast/initializer:latest",{"_index":328,"title":{},"content":{"31":{}},"tags":{}}],["gke",{"_index":241,"title":{},"content":{"14":{}},"tags":{}}],["go",{"_index":230,"title":{},"content":{"14":{}},"tags":{}}],["goal",{"_index":39,"title":{"105":{}},"content":{},"tags":{}}],["googl",{"_index":240,"title":{},"content":{"14":{}},"tags":{}}],["grep",{"_index":386,"title":{},"content":{"37":{}},"tags":{}}],["group",{"_index":573,"title":{"61":{}},"content":{"61":{},"62":{},"63":{}},"tags":{}}],["grpc",{"_index":438,"title":{},"content":{"38":{}},"tags":{}}],["guest",{"_index":176,"title":{},"content":{"12":{}},"tags":{}}],["guid",{"_index":285,"title":{},"content":{"29":{},"38":{}},"tags":{}}],["handshak",{"_index":476,"title":{},"content":{"44":{}},"tags":{}}],["har",{"_index":281,"title":{},"content":{"14":{}},"tags":{}}],["hardwar",{"_index":19,"title":{"17":{},"115":{}},"content":{"17":{},"18":{},"19":{},"20":{},"21":{},"104":{}},"tags":{}}],["hash",{"_index":524,"title":{},"content":{"51":{}},"tags":{}}],["hasn't",{"_index":479,"title":{},"content":{"44":{}},"tags":{}}],["head",{"_index":115,"title":{},"content":{"107":{}},"tags":{}}],["helm",{"_index":250,"title":{},"content":{"14":{},"31":{}},"tags":{}}],["high",{"_index":150,"title":{},"content":{"10":{}},"tags":{}}],["highli",{"_index":448,"title":{},"content":{"39":{}},"tags":{}}],["histori",{"_index":369,"title":{"48":{}},"content":{"36":{},"47":{}},"tags":{}}],["host",{"_index":182,"title":{},"content":{"12":{},"37":{},"50":{}},"tags":{}}],["html",{"_index":548,"title":{},"content":{"53":{}},"tags":{}}],["http",{"_index":492,"title":{},"content":{"45":{}},"tags":{}}],["https://$frontendip",{"_index":520,"title":{},"content":{"49":{}},"tags":{}}],["https://${frontendip}:443",{"_index":412,"title":{},"content":{"37":{},"50":{},"53":{}},"tags":{}}],["https://github.com/edgelesssys/contrast/releases/latest/download/contrast",{"_index":629,"title":{},"content":{"117":{}},"tags":{}}],["https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml",{"_index":299,"title":{},"content":{"30":{}},"tags":{}}],["https://github.com/kata",{"_index":357,"title":{},"content":{"34":{}},"tags":{}}],["ident",{"_index":126,"title":{"112":{}},"content":{"14":{},"108":{}},"tags":{}}],["imag",{"_index":211,"title":{},"content":{"12":{},"31":{}},"tags":{}}],["implement",{"_index":161,"title":{},"content":{"11":{}},"tags":{}}],["impos",{"_index":79,"title":{},"content":{"105":{}},"tags":{}}],["includ",{"_index":52,"title":{},"content":{"12":{},"34":{},"105":{}},"tags":{}}],["increas",{"_index":90,"title":{},"content":{"106":{}},"tags":{}}],["individu",{"_index":232,"title":{},"content":{"14":{}},"tags":{}}],["infect",{"_index":538,"title":{},"content":{"52":{}},"tags":{}}],["inform",{"_index":37,"title":{},"content":{"47":{},"104":{}},"tags":{}}],["infrastructur",{"_index":47,"title":{},"content":{"12":{},"14":{},"105":{}},"tags":{}}],["ingress",{"_index":387,"title":{},"content":{"37":{}},"tags":{}}],["init",{"_index":135,"title":{"23":{},"148":{}},"content":{"22":{},"23":{},"24":{},"35":{},"43":{}},"tags":{}}],["initcontain",{"_index":322,"title":{},"content":{"31":{}},"tags":{}}],["initi",{"_index":235,"title":{},"content":{"14":{},"31":{},"33":{},"43":{},"45":{},"53":{}},"tags":{}}],["insid",{"_index":14,"title":{},"content":{"104":{}},"tags":{}}],["inspect",{"_index":514,"title":{},"content":{"48":{}},"tags":{}}],["instal",{"_index":75,"title":{"55":{},"117":{}},"content":{"13":{},"14":{},"30":{},"40":{},"54":{},"59":{},"105":{},"117":{}},"tags":{}}],["instruct",{"_index":284,"title":{},"content":{"29":{},"40":{}},"tags":{}}],["integr",{"_index":68,"title":{},"content":{"14":{},"105":{}},"tags":{}}],["inter",{"_index":483,"title":{},"content":{"45":{}},"tags":{}}],["interest",{"_index":451,"title":{},"content":{"39":{}},"tags":{}}],["interfac",{"_index":159,"title":{},"content":{"11":{},"34":{}},"tags":{}}],["intern",{"_index":262,"title":{},"content":{"14":{}},"tags":{}}],["ip",{"_index":376,"title":{},"content":{"37":{},"49":{},"50":{}},"tags":{}}],["isn't",{"_index":347,"title":{},"content":{"34":{}},"tags":{}}],["isol",{"_index":20,"title":{},"content":{"12":{},"31":{},"43":{},"104":{}},"tags":{}}],["issu",{"_index":272,"title":{},"content":{"14":{},"34":{},"35":{},"37":{},"45":{},"50":{},"52":{}},"tags":{}}],["it'",{"_index":72,"title":{},"content":{"12":{},"105":{}},"tags":{}}],["item",{"_index":122,"title":{},"content":{"108":{},"109":{},"111":{},"112":{},"113":{}},"tags":{}}],["japaneast",{"_index":579,"title":{},"content":{"61":{}},"tags":{}}],["jump",{"_index":112,"title":{},"content":{"107":{}},"tags":{}}],["kata",{"_index":10,"title":{"12":{}},"content":{"11":{},"12":{},"31":{},"34":{},"43":{},"104":{}},"tags":{}}],["kataccisol",{"_index":604,"title":{},"content":{"62":{}},"tags":{}}],["kataccisolationpreview",{"_index":563,"title":{},"content":{"60":{}},"tags":{}}],["keep",{"_index":41,"title":{},"content":{"31":{},"105":{}},"tags":{}}],["key",{"_index":137,"title":{"9":{},"26":{}},"content":{"14":{},"25":{},"26":{},"45":{},"62":{}},"tags":{}}],["kubeconfig",{"_index":606,"title":{},"content":{"62":{}},"tags":{}}],["kubectl",{"_index":296,"title":{},"content":{"30":{},"33":{},"34":{},"37":{},"42":{},"45":{},"53":{},"62":{}},"tags":{}}],["kubernet",{"_index":7,"title":{"11":{},"31":{}},"content":{"10":{},"11":{},"12":{},"13":{},"14":{},"29":{},"31":{},"62":{},"104":{},"105":{}},"tags":{}}],["kustom",{"_index":252,"title":{},"content":{"14":{},"31":{}},"tags":{}}],["latest",{"_index":290,"title":{},"content":{"30":{},"59":{},"117":{}},"tags":{}}],["layer",{"_index":48,"title":{},"content":{"105":{}},"tags":{}}],["lbip",{"_index":391,"title":{},"content":{"37":{}},"tags":{}}],["lbip=$(kubectl",{"_index":389,"title":{},"content":{"37":{}},"tags":{}}],["leader",{"_index":434,"title":{},"content":{"38":{}},"tags":{}}],["leak",{"_index":457,"title":{},"content":{"39":{}},"tags":{}}],["learn",{"_index":109,"title":{},"content":{"107":{}},"tags":{}}],["level",{"_index":145,"title":{},"content":{"10":{},"52":{}},"tags":{}}],["leverag",{"_index":220,"title":{},"content":{"13":{}},"tags":{}}],["lift",{"_index":25,"title":{},"content":{"104":{}},"tags":{}}],["lightweight",{"_index":244,"title":{},"content":{"14":{}},"tags":{}}],["list",{"_index":440,"title":{},"content":{"38":{},"51":{},"61":{},"62":{}},"tags":{}}],["load",{"_index":350,"title":{},"content":{"34":{},"37":{},"44":{},"50":{}},"tags":{}}],["loadbalanc",{"_index":295,"title":{},"content":{"30":{},"34":{},"37":{},"42":{},"49":{}},"tags":{}}],["local",{"_index":186,"title":{},"content":{"12":{},"31":{}},"tags":{}}],["locat",{"_index":574,"title":{},"content":{"61":{}},"tags":{}}],["logic",{"_index":442,"title":{},"content":{"38":{}},"tags":{}}],["login",{"_index":552,"title":{},"content":{"59":{}},"tags":{}}],["make",{"_index":286,"title":{},"content":{"29":{}},"tags":{}}],["malici",{"_index":64,"title":{},"content":{"105":{}},"tags":{}}],["manag",{"_index":74,"title":{},"content":{"11":{},"12":{},"14":{},"105":{}},"tags":{}}],["mani",{"_index":149,"title":{},"content":{"10":{}},"tags":{}}],["manifest",{"_index":130,"title":{"1":{},"20":{},"32":{},"35":{},"43":{},"44":{},"48":{},"50":{},"51":{},"52":{}},"content":{"17":{},"18":{},"19":{},"20":{},"21":{},"33":{},"35":{},"36":{},"44":{},"45":{},"46":{},"47":{},"48":{},"51":{},"52":{},"53":{}},"tags":{}}],["manifest.json",{"_index":336,"title":{},"content":{"32":{},"43":{}},"tags":{}}],["map",{"_index":523,"title":{},"content":{"51":{}},"tags":{}}],["match",{"_index":415,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["mean",{"_index":505,"title":{},"content":{"46":{}},"tags":{}}],["mesh",{"_index":270,"title":{},"content":{"14":{},"36":{},"37":{},"45":{},"47":{},"49":{},"50":{},"52":{},"53":{}},"tags":{}}],["metal",{"_index":191,"title":{},"content":{"12":{}},"tags":{}}],["method",{"_index":346,"title":{},"content":{"34":{}},"tags":{}}],["micro",{"_index":15,"title":{},"content":{"104":{}},"tags":{}}],["microservic",{"_index":436,"title":{},"content":{"38":{}},"tags":{}}],["microsoft.containerservic",{"_index":562,"title":{},"content":{"60":{}},"tags":{}}],["minim",{"_index":80,"title":{},"content":{"14":{},"105":{}},"tags":{}}],["minut",{"_index":472,"title":{},"content":{"44":{},"60":{}},"tags":{}}],["mkdir",{"_index":309,"title":{},"content":{"31":{}},"tags":{}}],["mode",{"_index":204,"title":{},"content":{"12":{}},"tags":{}}],["more",{"_index":36,"title":{},"content":{"10":{},"11":{},"104":{},"107":{}},"tags":{}}],["motiv",{"_index":446,"title":{"39":{}},"content":{},"tags":{}}],["mountpath",{"_index":332,"title":{},"content":{"31":{}},"tags":{}}],["move",{"_index":91,"title":{},"content":{"106":{}},"tags":{}}],["mtl",{"_index":278,"title":{},"content":{"14":{},"45":{}},"tags":{}}],["multi",{"_index":104,"title":{},"content":{"106":{}},"tags":{}}],["mutual",{"_index":276,"title":{},"content":{"14":{}},"tags":{}}],["mv",{"_index":632,"title":{},"content":{"117":{}},"tags":{}}],["my_resource_dir",{"_index":310,"title":{},"content":{"31":{}},"tags":{}}],["my_servic",{"_index":379,"title":{},"content":{"37":{}},"tags":{}}],["name",{"_index":325,"title":{},"content":{"31":{},"37":{},"47":{},"50":{},"60":{},"61":{},"62":{},"63":{}},"tags":{}}],["namespac",{"_index":561,"title":{},"content":{"60":{}},"tags":{}}],["nativ",{"_index":253,"title":{},"content":{"14":{}},"tags":{}}],["need",{"_index":340,"title":{},"content":{"34":{},"46":{},"48":{},"60":{}},"tags":{}}],["nest",{"_index":194,"title":{},"content":{"12":{},"13":{}},"tags":{}}],["network",{"_index":128,"title":{"113":{}},"content":{"12":{},"108":{}},"tags":{}}],["new",{"_index":534,"title":{},"content":{"52":{},"53":{},"61":{},"63":{}},"tags":{}}],["next",{"_index":107,"title":{"107":{}},"content":{"34":{},"48":{},"52":{}},"tags":{}}],["node",{"_index":187,"title":{},"content":{"12":{},"13":{},"62":{},"63":{}},"tags":{}}],["nodepool",{"_index":602,"title":{},"content":{"62":{}},"tags":{}}],["nodepool1",{"_index":609,"title":{},"content":{"62":{}},"tags":{}}],["nodepool2",{"_index":603,"title":{},"content":{"62":{}},"tags":{}}],["none",{"_index":613,"title":{},"content":{"62":{}},"tags":{}}],["northeurop",{"_index":580,"title":{},"content":{"61":{}},"tags":{}}],["now",{"_index":481,"title":{},"content":{"45":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":343,"title":{},"content":{"34":{},"37":{},"44":{},"49":{}},"tags":{}}],["object",{"_index":158,"title":{},"content":{"11":{}},"tags":{}}],["oci",{"_index":168,"title":{},"content":{"11":{},"12":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"13":{},"14":{},"106":{}},"tags":{}}],["older",{"_index":539,"title":{},"content":{"52":{},"53":{}},"tags":{}}],["on",{"_index":157,"title":{},"content":{"11":{},"61":{}},"tags":{}}],["opa",{"_index":207,"title":{},"content":{"12":{}},"tags":{}}],["open",{"_index":206,"title":{},"content":{"12":{}},"tags":{}}],["openssl",{"_index":417,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"14":{},"60":{},"105":{}},"tags":{}}],["optim",{"_index":226,"title":{},"content":{"14":{}},"tags":{}}],["option",{"_index":184,"title":{"50":{}},"content":{"12":{}},"tags":{}}],["orchestr",{"_index":254,"title":{},"content":{"14":{}},"tags":{}}],["origin",{"_index":201,"title":{},"content":{"12":{},"31":{},"45":{}},"tags":{}}],["os",{"_index":594,"title":{},"content":{"62":{}},"tags":{}}],["out",{"_index":541,"title":{"53":{}},"content":{"53":{},"63":{}},"tags":{}}],["output",{"_index":568,"title":{},"content":{"60":{}},"tags":{}}],["output=jsonpath='{.status.loadbalanc",{"_index":385,"title":{},"content":{"37":{}},"tags":{}}],["over",{"_index":197,"title":{},"content":{"12":{},"47":{}},"tags":{}}],["owner",{"_index":365,"title":{},"content":{"36":{},"39":{}},"tags":{}}],["p",{"_index":380,"title":{},"content":{"37":{}},"tags":{}}],["part",{"_index":460,"title":{},"content":{"40":{},"45":{},"52":{}},"tags":{}}],["parti",{"_index":105,"title":{},"content":{"14":{},"106":{}},"tags":{}}],["patch",{"_index":378,"title":{},"content":{"37":{},"45":{},"52":{}},"tags":{}}],["path",{"_index":630,"title":{},"content":{"117":{}},"tags":{}}],["permiss",{"_index":554,"title":{},"content":{"59":{}},"tags":{}}],["perspect",{"_index":228,"title":{"46":{}},"content":{"14":{},"38":{}},"tags":{}}],["phase",{"_index":338,"title":{},"content":{"33":{}},"tags":{}}],["pki",{"_index":133,"title":{"5":{},"16":{}},"content":{"14":{},"16":{}},"tags":{}}],["plain",{"_index":491,"title":{},"content":{"45":{}},"tags":{}}],["platform",{"_index":237,"title":{},"content":{"14":{},"39":{}},"tags":{}}],["pleas",{"_index":459,"title":{},"content":{"40":{}},"tags":{}}],["pod",{"_index":12,"title":{"2":{},"18":{}},"content":{"10":{},"11":{},"12":{},"14":{},"17":{},"18":{},"19":{},"20":{},"21":{},"31":{},"34":{},"43":{},"104":{}},"tags":{}}],["polici",{"_index":132,"title":{"3":{},"19":{},"32":{},"43":{}},"content":{"12":{},"17":{},"18":{},"19":{},"20":{},"21":{},"32":{},"36":{},"43":{},"47":{},"48":{},"51":{}},"tags":{}}],["pool",{"_index":219,"title":{},"content":{"13":{},"62":{},"63":{}},"tags":{}}],["port",{"_index":344,"title":{},"content":{"34":{}},"tags":{}}],["potenti",{"_index":508,"title":{},"content":{"47":{},"48":{}},"tags":{}}],["pre",{"_index":223,"title":{},"content":{"13":{}},"tags":{}}],["prem",{"_index":94,"title":{},"content":{"106":{}},"tags":{}}],["prepar",{"_index":300,"title":{"31":{},"60":{}},"content":{},"tags":{}}],["prerequisit",{"_index":458,"title":{"40":{},"59":{}},"content":{"54":{},"56":{}},"tags":{}}],["prevent",{"_index":45,"title":{},"content":{"105":{}},"tags":{}}],["preview",{"_index":31,"title":{"13":{},"60":{}},"content":{"13":{},"40":{},"60":{},"61":{},"104":{},"117":{}},"tags":{}}],["primit",{"_index":154,"title":{},"content":{"10":{}},"tags":{}}],["privat",{"_index":487,"title":{},"content":{"45":{},"117":{}},"tags":{}}],["privileg",{"_index":55,"title":{},"content":{"105":{}},"tags":{}}],["process",{"_index":179,"title":{},"content":{"12":{},"29":{},"39":{}},"tags":{}}],["product",{"_index":225,"title":{"14":{}},"content":{},"tags":{}}],["project",{"_index":11,"title":{},"content":{"10":{},"104":{}},"tags":{}}],["protect",{"_index":455,"title":{},"content":{"39":{}},"tags":{}}],["protocol",{"_index":136,"title":{"9":{},"26":{}},"content":{"25":{},"26":{}},"tags":{}}],["prove",{"_index":453,"title":{},"content":{"39":{}},"tags":{}}],["provid",{"_index":17,"title":{},"content":{"10":{},"12":{},"13":{},"14":{},"39":{},"60":{},"104":{},"105":{},"106":{}},"tags":{}}],["provider'",{"_index":200,"title":{},"content":{"12":{}},"tags":{}}],["proxi",{"_index":283,"title":{},"content":{"14":{}},"tags":{}}],["public",{"_index":271,"title":{},"content":{"14":{},"34":{},"37":{},"49":{},"60":{}},"tags":{}}],["pull",{"_index":467,"title":{},"content":{"43":{},"53":{}},"tags":{}}],["r",{"_index":316,"title":{},"content":{"31":{}},"tags":{}}],["readi",{"_index":612,"title":{},"content":{"62":{}},"tags":{}}],["receiv",{"_index":533,"title":{},"content":{"52":{},"54":{},"55":{},"117":{}},"tags":{}}],["refer",{"_index":337,"title":{},"content":{"32":{},"36":{},"43":{},"44":{},"47":{}},"tags":{}}],["referenc",{"_index":370,"title":{},"content":{"36":{},"47":{},"48":{}},"tags":{}}],["refresh",{"_index":571,"title":{},"content":{"60":{}},"tags":{}}],["regardless",{"_index":497,"title":{},"content":{"46":{}},"tags":{}}],["regist",{"_index":558,"title":{},"content":{"60":{}},"tags":{}}],["registr",{"_index":564,"title":{},"content":{"60":{}},"tags":{}}],["regulatori",{"_index":102,"title":{},"content":{"106":{}},"tags":{}}],["relat",{"_index":623,"title":{},"content":{"63":{}},"tags":{}}],["relay",{"_index":352,"title":{},"content":{"34":{}},"tags":{}}],["releas",{"_index":291,"title":{},"content":{"30":{},"34":{},"117":{}},"tags":{}}],["release_nam",{"_index":313,"title":{},"content":{"31":{}},"tags":{}}],["remot",{"_index":188,"title":{},"content":{"12":{},"14":{},"46":{}},"tags":{}}],["remov",{"_index":49,"title":{},"content":{"105":{}},"tags":{}}],["replica",{"_index":294,"title":{},"content":{"30":{},"42":{}},"tags":{}}],["report",{"_index":215,"title":{},"content":{"12":{},"45":{}},"tags":{}}],["requir",{"_index":189,"title":{},"content":{"12":{},"29":{},"39":{},"60":{}},"tags":{}}],["resourc",{"_index":213,"title":{"31":{},"33":{},"61":{}},"content":{"12":{},"31":{},"32":{},"33":{},"34":{},"35":{},"61":{},"62":{},"63":{}},"tags":{}}],["resources/all.yml",{"_index":311,"title":{},"content":{"31":{}},"tags":{}}],["restart",{"_index":544,"title":{},"content":{"53":{}},"tags":{}}],["retriev",{"_index":486,"title":{},"content":{"45":{}},"tags":{}}],["return",{"_index":488,"title":{},"content":{"45":{},"47":{},"53":{}},"tags":{}}],["right",{"_index":113,"title":{},"content":{"107":{}},"tags":{}}],["role",{"_index":607,"title":{},"content":{"62":{}},"tags":{}}],["roll",{"_index":540,"title":{"53":{}},"content":{"53":{}},"tags":{}}],["rollout",{"_index":543,"title":{},"content":{"53":{}},"tags":{}}],["root",{"_index":368,"title":{},"content":{"36":{},"37":{},"47":{},"50":{},"52":{}},"tags":{}}],["root.pem",{"_index":372,"title":{},"content":{"37":{},"47":{},"49":{},"50":{},"52":{},"53":{}},"tags":{}}],["rotat",{"_index":530,"title":{},"content":{"52":{}},"tags":{}}],["run",{"_index":3,"title":{},"content":{"12":{},"29":{},"32":{},"39":{},"40":{},"43":{},"47":{},"63":{},"104":{}},"tags":{}}],["runc",{"_index":170,"title":{},"content":{"11":{}},"tags":{}}],["runsc",{"_index":171,"title":{},"content":{"11":{}},"tags":{}}],["runtim",{"_index":131,"title":{"3":{},"19":{}},"content":{"10":{},"11":{},"12":{},"17":{},"18":{},"19":{},"20":{},"21":{},"34":{},"43":{},"62":{}},"tags":{}}],["runtimeclass",{"_index":155,"title":{"11":{}},"content":{"11":{}},"tags":{}}],["runtimeclassnam",{"_index":319,"title":{},"content":{"31":{}},"tags":{}}],["s_client",{"_index":418,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["saa",{"_index":99,"title":{},"content":{"106":{}},"tags":{}}],["same",{"_index":511,"title":{},"content":{"47":{}},"tags":{}}],["san",{"_index":404,"title":{"50":{},"51":{}},"content":{"37":{},"50":{},"51":{}},"tags":{}}],["sandbox",{"_index":142,"title":{},"content":{"10":{}},"tags":{}}],["scale",{"_index":8,"title":{},"content":{"14":{},"46":{},"104":{}},"tags":{}}],["screenshot",{"_index":425,"title":{},"content":{"27":{},"28":{}},"tags":{}}],["seamlessli",{"_index":227,"title":{},"content":{"14":{}},"tags":{}}],["second",{"_index":601,"title":{},"content":{"62":{}},"tags":{}}],["secret",{"_index":449,"title":{},"content":{"39":{}},"tags":{}}],["section",{"_index":111,"title":{},"content":{"51":{},"107":{}},"tags":{}}],["secur",{"_index":86,"title":{"15":{}},"content":{"14":{},"37":{},"45":{},"49":{},"52":{},"106":{},"107":{}},"tags":{}}],["see",{"_index":34,"title":{},"content":{"29":{},"40":{},"104":{}},"tags":{}}],["select",{"_index":587,"title":{},"content":{"61":{},"62":{}},"tags":{}}],["send",{"_index":485,"title":{},"content":{"45":{}},"tags":{}}],["sensit",{"_index":92,"title":{},"content":{"39":{},"106":{}},"tags":{}}],["separ",{"_index":307,"title":{},"content":{"31":{}},"tags":{}}],["server",{"_index":192,"title":{},"content":{"12":{}},"tags":{}}],["servic",{"_index":217,"title":{"51":{}},"content":{"13":{},"14":{},"30":{},"36":{},"37":{},"39":{},"42":{},"49":{},"52":{},"53":{}},"tags":{}}],["service/${my_servic",{"_index":384,"title":{},"content":{"37":{}},"tags":{}}],["set",{"_index":288,"title":{"35":{},"44":{}},"content":{"29":{},"33":{},"35":{},"44":{},"45":{},"52":{},"53":{},"61":{}},"tags":{}}],["setup",{"_index":246,"title":{"56":{}},"content":{"14":{},"29":{},"40":{},"54":{}},"tags":{}}],["shield",{"_index":95,"title":{},"content":{"12":{},"14":{},"106":{}},"tags":{}}],["shift",{"_index":26,"title":{},"content":{"104":{}},"tags":{}}],["shim",{"_index":348,"title":{},"content":{"34":{}},"tags":{}}],["ship",{"_index":464,"title":{},"content":{"43":{}},"tags":{}}],["show",{"_index":566,"title":{},"content":{"60":{},"62":{}},"tags":{}}],["sidecar",{"_index":138,"title":{"8":{},"25":{}},"content":{"25":{},"26":{}},"tags":{}}],["signal",{"_index":466,"title":{},"content":{"43":{}},"tags":{}}],["simplifi",{"_index":101,"title":{},"content":{"14":{},"106":{}},"tags":{}}],["simul",{"_index":444,"title":{},"content":{"38":{}},"tags":{}}],["singl",{"_index":293,"title":{},"content":{"30":{},"42":{},"46":{}},"tags":{}}],["site",{"_index":549,"title":{},"content":{"53":{}},"tags":{}}],["size",{"_index":597,"title":{},"content":{"62":{}},"tags":{}}],["sku",{"_index":595,"title":{},"content":{"62":{}},"tags":{}}],["sleep",{"_index":388,"title":{},"content":{"37":{}},"tags":{}}],["socket",{"_index":198,"title":{},"content":{"12":{}},"tags":{}}],["spawn",{"_index":177,"title":{},"content":{"12":{}},"tags":{}}],["spec",{"_index":321,"title":{},"content":{"31":{},"37":{}},"tags":{}}],["specif",{"_index":273,"title":{},"content":{"14":{},"39":{}},"tags":{}}],["specifi",{"_index":317,"title":{},"content":{"31":{}},"tags":{}}],["ssh",{"_index":600,"title":{},"content":{"62":{}},"tags":{}}],["ssl",{"_index":414,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["stabl",{"_index":153,"title":{},"content":{"10":{}},"tags":{}}],["stack",{"_index":222,"title":{},"content":{"13":{}},"tags":{}}],["standard",{"_index":144,"title":{},"content":{"10":{}},"tags":{}}],["standard_dc4as_cc_v5",{"_index":598,"title":{},"content":{"62":{}},"tags":{}}],["start",{"_index":117,"title":{"54":{}},"content":{"35":{},"43":{},"107":{}},"tags":{}}],["state",{"_index":567,"title":{},"content":{"60":{}},"tags":{}}],["statement",{"_index":258,"title":{},"content":{"14":{}},"tags":{}}],["statu",{"_index":565,"title":{},"content":{"60":{},"62":{}},"tags":{}}],["step",{"_index":108,"title":{"41":{},"57":{},"107":{},"116":{}},"content":{"29":{},"34":{},"35":{},"46":{},"48":{},"54":{},"63":{}},"tags":{}}],["still",{"_index":151,"title":{},"content":{"10":{},"53":{}},"tags":{}}],["store",{"_index":510,"title":{},"content":{"47":{}},"tags":{}}],["straightforward",{"_index":248,"title":{},"content":{"14":{}},"tags":{}}],["strong",{"_index":18,"title":{},"content":{"104":{}},"tags":{}}],["subject",{"_index":392,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["submit",{"_index":445,"title":{},"content":{"38":{}},"tags":{}}],["subscript",{"_index":560,"title":{},"content":{"60":{}},"tags":{}}],["succe",{"_index":477,"title":{},"content":{"44":{},"47":{}},"tags":{}}],["success",{"_index":503,"title":{},"content":{"46":{}},"tags":{}}],["successfulli",{"_index":484,"title":{},"content":{"45":{},"47":{},"53":{}},"tags":{}}],["such",{"_index":169,"title":{},"content":{"11":{},"14":{},"60":{}},"tags":{}}],["support",{"_index":193,"title":{},"content":{"12":{},"14":{},"34":{},"40":{},"62":{}},"tags":{}}],["sure",{"_index":506,"title":{},"content":{"46":{}},"tags":{}}],["surround",{"_index":21,"title":{},"content":{"104":{}},"tags":{}}],["svc",{"_index":342,"title":{},"content":{"34":{},"37":{},"44":{},"49":{}},"tags":{}}],["switzerlandnorth",{"_index":581,"title":{},"content":{"61":{}},"tags":{}}],["system",{"_index":501,"title":{},"content":{"46":{}},"tags":{}}],["tabl",{"_index":569,"title":{},"content":{"60":{}},"tags":{}}],["take",{"_index":470,"title":{},"content":{"44":{},"60":{}},"tags":{}}],["talk",{"_index":490,"title":{},"content":{"45":{}},"tags":{}}],["tamper",{"_index":480,"title":{},"content":{"44":{}},"tags":{}}],["target",{"_index":29,"title":{},"content":{"37":{},"50":{},"104":{}},"tags":{}}],["task",{"_index":516,"title":{},"content":{"48":{}},"tags":{}}],["tcb",{"_index":51,"title":{},"content":{"105":{}},"tags":{}}],["templat",{"_index":312,"title":{},"content":{"31":{}},"tags":{}}],["tenant",{"_index":66,"title":{},"content":{"105":{}},"tags":{}}],["termin",{"_index":542,"title":{},"content":{"53":{}},"tags":{}}],["those",{"_index":454,"title":{},"content":{"39":{},"46":{}},"tags":{}}],["through",{"_index":62,"title":{},"content":{"12":{},"29":{},"38":{},"105":{}},"tags":{}}],["throw",{"_index":408,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["thu",{"_index":531,"title":{},"content":{"52":{}},"tags":{}}],["timeout",{"_index":381,"title":{},"content":{"37":{}},"tags":{}}],["tip",{"_index":33,"title":{},"content":{"104":{}},"tags":{}}],["tl",{"_index":277,"title":{},"content":{"14":{},"31":{},"35":{},"44":{},"47":{}},"tags":{}}],["togeth",{"_index":287,"title":{},"content":{"29":{}},"tags":{}}],["tool",{"_index":401,"title":{},"content":{"37":{},"50":{},"51":{}},"tags":{}}],["track",{"_index":356,"title":{},"content":{"34":{}},"tags":{}}],["traffic",{"_index":353,"title":{},"content":{"34":{},"38":{}},"tags":{}}],["transit",{"_index":500,"title":{},"content":{"46":{}},"tags":{}}],["transpar",{"_index":275,"title":{},"content":{"14":{}},"tags":{}}],["tri",{"_index":619,"title":{},"content":{"63":{}},"tags":{}}],["true",{"_index":557,"title":{},"content":{"60":{}},"tags":{}}],["trust",{"_index":50,"title":{},"content":{"37":{},"48":{},"49":{},"52":{},"105":{}},"tags":{}}],["trustworthi",{"_index":98,"title":{},"content":{"106":{}},"tags":{}}],["tunnel",{"_index":199,"title":{},"content":{"12":{}},"tags":{}}],["tutori",{"_index":428,"title":{},"content":{"38":{}},"tags":{}}],["two",{"_index":183,"title":{},"content":{"12":{},"62":{}},"tags":{}}],["type",{"_index":221,"title":{},"content":{"13":{},"37":{}},"tags":{}}],["uaenorth",{"_index":582,"title":{},"content":{"61":{}},"tags":{}}],["ui",{"_index":427,"title":{},"content":{"27":{},"28":{}},"tags":{}}],["unchang",{"_index":305,"title":{},"content":{"31":{}},"tags":{}}],["under",{"_index":146,"title":{},"content":{"10":{}},"tags":{}}],["underli",{"_index":203,"title":{},"content":{"12":{},"14":{}},"tags":{}}],["uniqu",{"_index":85,"title":{},"content":{"106":{}},"tags":{}}],["unmodifi",{"_index":24,"title":{},"content":{"104":{}},"tags":{}}],["unpack",{"_index":625,"title":{},"content":{"117":{}},"tags":{}}],["until",{"_index":339,"title":{},"content":{"33":{},"37":{}},"tags":{}}],["unzip",{"_index":627,"title":{},"content":{"117":{}},"tags":{}}],["up",{"_index":289,"title":{},"content":{"29":{},"44":{},"63":{}},"tags":{}}],["updat",{"_index":265,"title":{"50":{},"52":{},"53":{}},"content":{"14":{},"52":{},"53":{},"60":{},"62":{}},"tags":{}}],["upstream",{"_index":355,"title":{},"content":{"34":{}},"tags":{}}],["url",{"_index":551,"title":{},"content":{"54":{},"55":{},"117":{}},"tags":{}}],["us",{"_index":83,"title":{"60":{},"106":{}},"content":{"10":{},"11":{},"12":{},"14":{},"31":{},"34":{},"36":{},"37":{},"39":{},"43":{},"44":{},"45":{},"47":{},"49":{},"50":{},"53":{},"61":{},"62":{},"106":{}},"tags":{}}],["user",{"_index":364,"title":{},"content":{"36":{},"38":{},"39":{},"44":{}},"tags":{}}],["usr/local/bin/contrast",{"_index":633,"title":{},"content":{"117":{}},"tags":{}}],["usual",{"_index":167,"title":{},"content":{"11":{}},"tags":{}}],["v1.29.0",{"_index":615,"title":{},"content":{"62":{}},"tags":{}}],["v1.podspec",{"_index":327,"title":{},"content":{"31":{}},"tags":{}}],["valid",{"_index":269,"title":{},"content":{"14":{},"37":{},"38":{},"45":{},"49":{},"50":{},"53":{},"62":{}},"tags":{}}],["valu",{"_index":331,"title":{},"content":{"31":{},"32":{},"36":{},"43":{},"44":{},"47":{}},"tags":{}}],["verif",{"_index":504,"title":{},"content":{"46":{},"51":{}},"tags":{}}],["verifi",{"_index":259,"title":{"36":{},"46":{}},"content":{"14":{},"36":{},"46":{},"47":{},"48":{}},"tags":{}}],["verify/mesh",{"_index":411,"title":{},"content":{"37":{},"49":{},"50":{}},"tags":{}}],["verify_return_error",{"_index":420,"title":{},"content":{"37":{},"49":{}},"tags":{}}],["version",{"_index":489,"title":{},"content":{"45":{},"47":{},"59":{},"62":{}},"tags":{}}],["via",{"_index":354,"title":{},"content":{"34":{},"37":{},"45":{},"49":{},"50":{}},"tags":{}}],["view",{"_index":433,"title":{},"content":{"38":{}},"tags":{}}],["virtual",{"_index":195,"title":{},"content":{"12":{},"13":{}},"tags":{}}],["visit",{"_index":521,"title":{},"content":{"49":{}},"tags":{}}],["vm",{"_index":16,"title":{"2":{},"18":{}},"content":{"12":{},"13":{},"17":{},"18":{},"19":{},"20":{},"21":{},"62":{},"104":{}},"tags":{}}],["vmss000000",{"_index":611,"title":{},"content":{"62":{}},"tags":{}}],["volum",{"_index":334,"title":{},"content":{"31":{}},"tags":{}}],["volumemount",{"_index":324,"title":{},"content":{"31":{},"45":{}},"tags":{}}],["vote",{"_index":424,"title":{"28":{},"38":{}},"content":{"27":{},"38":{},"39":{},"46":{},"53":{}},"tags":{}}],["voter",{"_index":429,"title":{},"content":{"38":{},"46":{},"47":{},"48":{}},"tags":{}}],["voter'",{"_index":495,"title":{"46":{}},"content":{},"tags":{}}],["want",{"_index":304,"title":{},"content":{"31":{},"46":{},"61":{},"63":{}},"tags":{}}],["way",{"_index":537,"title":{},"content":{"52":{}},"tags":{}}],["we'r",{"_index":478,"title":{},"content":{"44":{},"45":{}},"tags":{}}],["web",{"_index":398,"title":{},"content":{"37":{},"38":{},"49":{},"50":{},"51":{}},"tags":{}}],["welcom",{"_index":1,"title":{},"content":{"104":{}},"tags":{}}],["westeurop",{"_index":583,"title":{},"content":{"61":{}},"tags":{}}],["westu",{"_index":584,"title":{},"content":{"61":{}},"tags":{}}],["whitepap",{"_index":35,"title":{},"content":{"104":{}},"tags":{}}],["wildcard",{"_index":395,"title":{},"content":{"37":{},"50":{}},"tags":{}}],["within",{"_index":245,"title":{},"content":{"14":{}},"tags":{}}],["without",{"_index":456,"title":{},"content":{"39":{}},"tags":{}}],["won't",{"_index":536,"title":{},"content":{"52":{},"53":{}},"tags":{}}],["work",{"_index":23,"title":{},"content":{"104":{}},"tags":{}}],["workflow",{"_index":71,"title":{},"content":{"105":{}},"tags":{}}],["workload",{"_index":93,"title":{"29":{},"37":{},"49":{}},"content":{"14":{},"31":{},"33":{},"35":{},"37":{},"39":{},"43":{},"45":{},"49":{},"52":{},"62":{},"106":{}},"tags":{}}],["write",{"_index":367,"title":{},"content":{"36":{},"45":{}},"tags":{}}],["written",{"_index":323,"title":{},"content":{"31":{},"36":{},"47":{},"48":{}},"tags":{}}],["yaml",{"_index":249,"title":{},"content":{"14":{},"31":{},"43":{}},"tags":{}}],["you'v",{"_index":621,"title":{},"content":{"63":{}},"tags":{}}]],"pipeline":["stemmer"]}} \ No newline at end of file diff --git a/pr-preview/pr-1071/search-index-docs-default-0.6.json b/pr-preview/pr-1071/search-index-docs-default-0.6.json deleted file mode 100644 index f6c6a2ee55..0000000000 --- a/pr-preview/pr-1071/search-index-docs-default-0.6.json +++ /dev/null @@ -1 +0,0 @@ -{"documents":[{"id":118,"pageTitle":"Contrast","sectionTitle":"Contrast","sectionRoute":"/contrast/pr-preview/pr-1071/0.6","type":"docs"},{"id":119,"pageTitle":"Contrast","sectionTitle":"Goal","sectionRoute":"/contrast/pr-preview/pr-1071/0.6#goal","type":"docs"},{"id":120,"pageTitle":"Contrast","sectionTitle":"Use Cases","sectionRoute":"/contrast/pr-preview/pr-1071/0.6#use-cases","type":"docs"},{"id":121,"pageTitle":"Contrast","sectionTitle":"Next steps","sectionRoute":"/contrast/pr-preview/pr-1071/0.6#next-steps","type":"docs"},{"id":122,"pageTitle":"About","sectionTitle":"About","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/about","type":"docs"},{"id":123,"pageTitle":"About","sectionTitle":"📄️ Telemetry","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/about","type":"docs"},{"id":124,"pageTitle":"CLI telemetry","sectionTitle":"CLI telemetry","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/about/telemetry","type":"docs"},{"id":125,"pageTitle":"Architecture","sectionTitle":"Architecture","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture","type":"docs"},{"id":126,"pageTitle":"Architecture","sectionTitle":"📄️ Attestation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture","type":"docs"},{"id":127,"pageTitle":"Architecture","sectionTitle":"📄️ Certificate authority","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture","type":"docs"},{"id":128,"pageTitle":"Attestation in Contrast","sectionTitle":"Attestation in Contrast","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation","type":"docs"},{"id":129,"pageTitle":"Attestation in Contrast","sectionTitle":"Attestation architecture","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#attestation-architecture","type":"docs"},{"id":130,"pageTitle":"Attestation in Contrast","sectionTitle":"Components of Contrast's attestation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#components-of-contrasts-attestation","type":"docs"},{"id":131,"pageTitle":"Attestation in Contrast","sectionTitle":"Attester: Application Pods","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#attester-application-pods","type":"docs"},{"id":132,"pageTitle":"Attestation in Contrast","sectionTitle":"Verifier: Coordinator and CLI","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#verifier-coordinator-and-cli","type":"docs"},{"id":133,"pageTitle":"Attestation in Contrast","sectionTitle":"Relying Party: Data owner","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#relying-party-data-owner","type":"docs"},{"id":134,"pageTitle":"Attestation in Contrast","sectionTitle":"Evidence generation and appraisal","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#evidence-generation-and-appraisal","type":"docs"},{"id":135,"pageTitle":"Attestation in Contrast","sectionTitle":"Evidence types and formats","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#evidence-types-and-formats","type":"docs"},{"id":136,"pageTitle":"Attestation in Contrast","sectionTitle":"Appraisal policies for evidence","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#appraisal-policies-for-evidence","type":"docs"},{"id":137,"pageTitle":"Attestation in Contrast","sectionTitle":"Frequently asked questions about attestation in Contrast","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#frequently-asked-questions-about-attestation-in-contrast","type":"docs"},{"id":138,"pageTitle":"Attestation in Contrast","sectionTitle":"What's the purpose of remote attestation in Contrast?","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#whats-the-purpose-of-remote-attestation-in-contrast","type":"docs"},{"id":139,"pageTitle":"Attestation in Contrast","sectionTitle":"How does Contrast ensure the security of the attestation process?","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#how-does-contrast-ensure-the-security-of-the-attestation-process","type":"docs"},{"id":140,"pageTitle":"Attestation in Contrast","sectionTitle":"What security benefits does attestation provide?","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#what-security-benefits-does-attestation-provide","type":"docs"},{"id":141,"pageTitle":"Attestation in Contrast","sectionTitle":"How can you verify the authenticity of attestation results?","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#how-can-you-verify-the-authenticity-of-attestation-results","type":"docs"},{"id":142,"pageTitle":"Attestation in Contrast","sectionTitle":"How are attestation results used by relying parties?","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#how-are-attestation-results-used-by-relying-parties","type":"docs"},{"id":143,"pageTitle":"Attestation in Contrast","sectionTitle":"Summary","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/attestation#summary","type":"docs"},{"id":144,"pageTitle":"Certificate authority","sectionTitle":"Certificate authority","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates","type":"docs"},{"id":145,"pageTitle":"Certificate authority","sectionTitle":"Public key infrastructure","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates#public-key-infrastructure","type":"docs"},{"id":146,"pageTitle":"Certificate authority","sectionTitle":"Certificate rotation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates#certificate-rotation","type":"docs"},{"id":147,"pageTitle":"Certificate authority","sectionTitle":"Usage of the different certificates","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/architecture/certificates#usage-of-the-different-certificates","type":"docs"},{"id":149,"pageTitle":"Confidential Containers","sectionTitle":"Confidential Containers","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers","type":"docs"},{"id":150,"pageTitle":"Confidential Containers","sectionTitle":"Kubernetes RuntimeClass","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers#kubernetes-runtimeclass","type":"docs"},{"id":151,"pageTitle":"Confidential Containers","sectionTitle":"Kata Containers","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers#kata-containers","type":"docs"},{"id":152,"pageTitle":"Confidential Containers","sectionTitle":"AKS CoCo preview","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/confidential-containers#aks-coco-preview","type":"docs"},{"id":153,"pageTitle":"Product features","sectionTitle":"Product features","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/features","type":"docs"},{"id":154,"pageTitle":"Contrast security overview","sectionTitle":"Contrast security overview","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits","type":"docs"},{"id":155,"pageTitle":"Contrast security overview","sectionTitle":"Confidential computing foundation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#confidential-computing-foundation","type":"docs"},{"id":156,"pageTitle":"Contrast security overview","sectionTitle":"Components of a Contrast deployment","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#components-of-a-contrast-deployment","type":"docs"},{"id":157,"pageTitle":"Contrast security overview","sectionTitle":"Personas in a Contrast deployment","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#personas-in-a-contrast-deployment","type":"docs"},{"id":158,"pageTitle":"Contrast security overview","sectionTitle":"Threat model and mitigations","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#threat-model-and-mitigations","type":"docs"},{"id":159,"pageTitle":"Contrast security overview","sectionTitle":"Possible attacks","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#possible-attacks","type":"docs"},{"id":160,"pageTitle":"Contrast security overview","sectionTitle":"Attack surfaces","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#attack-surfaces","type":"docs"},{"id":161,"pageTitle":"Contrast security overview","sectionTitle":"Threats and mitigations","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#threats-and-mitigations","type":"docs"},{"id":162,"pageTitle":"Contrast security overview","sectionTitle":"Examples of Contrast's threat model in practice","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/basics/security-benefits#examples-of-contrasts-threat-model-in-practice","type":"docs"},{"id":163,"pageTitle":"Components","sectionTitle":"Components","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components","type":"docs"},{"id":164,"pageTitle":"Components","sectionTitle":"The CLI (Command Line Interface)","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components#the-cli-command-line-interface","type":"docs"},{"id":165,"pageTitle":"Components","sectionTitle":"The Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components#the-coordinator","type":"docs"},{"id":166,"pageTitle":"Components","sectionTitle":"The Manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components#the-manifest","type":"docs"},{"id":167,"pageTitle":"Components","sectionTitle":"Runtime policies","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components#runtime-policies","type":"docs"},{"id":168,"pageTitle":"Components","sectionTitle":"The Initializer","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components#the-initializer","type":"docs"},{"id":169,"pageTitle":"Components","sectionTitle":"The Contrast runtime","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components#the-contrast-runtime","type":"docs"},{"id":170,"pageTitle":"Policies","sectionTitle":"Policies","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/policies","type":"docs"},{"id":171,"pageTitle":"Policies","sectionTitle":"Structure","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/policies#structure","type":"docs"},{"id":172,"pageTitle":"Policies","sectionTitle":"Generation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/policies#generation","type":"docs"},{"id":173,"pageTitle":"Policies","sectionTitle":"Evaluation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/policies#evaluation","type":"docs"},{"id":174,"pageTitle":"Policies","sectionTitle":"Guarantees","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/policies#guarantees","type":"docs"},{"id":175,"pageTitle":"Policies","sectionTitle":"Trust","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/policies#trust","type":"docs"},{"id":176,"pageTitle":"Contrast Runtime","sectionTitle":"Contrast Runtime","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime","type":"docs"},{"id":177,"pageTitle":"Contrast Runtime","sectionTitle":"Node-level components","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime#node-level-components","type":"docs"},{"id":178,"pageTitle":"Contrast Runtime","sectionTitle":"Containerd shim","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime#containerd-shim","type":"docs"},{"id":179,"pageTitle":"Contrast Runtime","sectionTitle":"cloud-hypervisor virtual machine manager (VMM)","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime#cloud-hypervisor-virtual-machine-manager-vmm","type":"docs"},{"id":180,"pageTitle":"Contrast Runtime","sectionTitle":"Tardev snapshotter","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime#tardev-snapshotter","type":"docs"},{"id":181,"pageTitle":"Contrast Runtime","sectionTitle":"Pod-VM image","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime#pod-vm-image","type":"docs"},{"id":182,"pageTitle":"Contrast Runtime","sectionTitle":"Node installer DaemonSet","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/runtime#node-installer-daemonset","type":"docs"},{"id":183,"pageTitle":"Service Mesh","sectionTitle":"Service Mesh","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh","type":"docs"},{"id":184,"pageTitle":"Service Mesh","sectionTitle":"Configuring the Proxy","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh#configuring-the-proxy","type":"docs"},{"id":185,"pageTitle":"Service Mesh","sectionTitle":"Ingress","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh#ingress","type":"docs"},{"id":186,"pageTitle":"Service Mesh","sectionTitle":"Egress","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/components/service-mesh#egress","type":"docs"},{"id":187,"pageTitle":"Workload deployment","sectionTitle":"Workload deployment","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment","type":"docs"},{"id":188,"pageTitle":"Workload deployment","sectionTitle":"Deploy the Contrast runtime","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#deploy-the-contrast-runtime","type":"docs"},{"id":189,"pageTitle":"Workload deployment","sectionTitle":"Deploy the Contrast Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#deploy-the-contrast-coordinator","type":"docs"},{"id":190,"pageTitle":"Workload deployment","sectionTitle":"Prepare your Kubernetes resources","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#prepare-your-kubernetes-resources","type":"docs"},{"id":191,"pageTitle":"Workload deployment","sectionTitle":"RuntimeClass and Initializer","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#runtimeclass-and-initializer","type":"docs"},{"id":192,"pageTitle":"Workload deployment","sectionTitle":"Handling TLS","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#handling-tls","type":"docs"},{"id":193,"pageTitle":"Workload deployment","sectionTitle":"Generate policy annotations and manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#generate-policy-annotations-and-manifest","type":"docs"},{"id":194,"pageTitle":"Workload deployment","sectionTitle":"Apply the resources","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#apply-the-resources","type":"docs"},{"id":195,"pageTitle":"Workload deployment","sectionTitle":"Connect to the Contrast Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#connect-to-the-contrast-coordinator","type":"docs"},{"id":196,"pageTitle":"Workload deployment","sectionTitle":"Set the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#set-the-manifest","type":"docs"},{"id":197,"pageTitle":"Workload deployment","sectionTitle":"Verify the Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#verify-the-coordinator","type":"docs"},{"id":198,"pageTitle":"Workload deployment","sectionTitle":"Communicate with workloads","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/deployment#communicate-with-workloads","type":"docs"},{"id":199,"pageTitle":"Examples","sectionTitle":"Examples","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples","type":"docs"},{"id":200,"pageTitle":"Examples","sectionTitle":"📄️ Confidential emoji voting","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples","type":"docs"},{"id":201,"pageTitle":"Confidential emoji voting","sectionTitle":"Confidential emoji voting","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto","type":"docs"},{"id":202,"pageTitle":"Confidential emoji voting","sectionTitle":"Motivation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#motivation","type":"docs"},{"id":203,"pageTitle":"Confidential emoji voting","sectionTitle":"Prerequisites","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#prerequisites","type":"docs"},{"id":204,"pageTitle":"Confidential emoji voting","sectionTitle":"Steps to deploy emojivoto with Contrast","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#steps-to-deploy-emojivoto-with-contrast","type":"docs"},{"id":205,"pageTitle":"Confidential emoji voting","sectionTitle":"Downloading the deployment","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#downloading-the-deployment","type":"docs"},{"id":206,"pageTitle":"Confidential emoji voting","sectionTitle":"Deploy the Contrast runtime","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#deploy-the-contrast-runtime","type":"docs"},{"id":207,"pageTitle":"Confidential emoji voting","sectionTitle":"Deploy the Contrast Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#deploy-the-contrast-coordinator","type":"docs"},{"id":208,"pageTitle":"Confidential emoji voting","sectionTitle":"Generate policy annotations and manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#generate-policy-annotations-and-manifest","type":"docs"},{"id":209,"pageTitle":"Confidential emoji voting","sectionTitle":"Set the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#set-the-manifest","type":"docs"},{"id":210,"pageTitle":"Confidential emoji voting","sectionTitle":"Deploy emojivoto","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#deploy-emojivoto","type":"docs"},{"id":211,"pageTitle":"Confidential emoji voting","sectionTitle":"Voter's perspective: Verifying the ballot","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#voters-perspective-verifying-the-ballot","type":"docs"},{"id":212,"pageTitle":"Confidential emoji voting","sectionTitle":"Attest the Coordinator","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#attest-the-coordinator","type":"docs"},{"id":213,"pageTitle":"Confidential emoji voting","sectionTitle":"Manifest history and artifact audit","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#manifest-history-and-artifact-audit","type":"docs"},{"id":214,"pageTitle":"Confidential emoji voting","sectionTitle":"Confidential connection to the attested workload","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#confidential-connection-to-the-attested-workload","type":"docs"},{"id":215,"pageTitle":"Confidential emoji voting","sectionTitle":"Certificate SAN and manifest update (optional)","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#certificate-san-and-manifest-update-optional","type":"docs"},{"id":216,"pageTitle":"Confidential emoji voting","sectionTitle":"Configure the service SAN in the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#configure-the-service-san-in-the-manifest","type":"docs"},{"id":217,"pageTitle":"Confidential emoji voting","sectionTitle":"Update the manifest","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#update-the-manifest","type":"docs"},{"id":218,"pageTitle":"Confidential emoji voting","sectionTitle":"Rolling out the update","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/examples/emojivoto#rolling-out-the-update","type":"docs"},{"id":219,"pageTitle":"Getting started","sectionTitle":"Getting started","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started","type":"docs"},{"id":220,"pageTitle":"Getting started","sectionTitle":"📄️ Install","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started","type":"docs"},{"id":221,"pageTitle":"Getting started","sectionTitle":"📄️ Cluster setup","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started","type":"docs"},{"id":222,"pageTitle":"Create a cluster","sectionTitle":"Create a cluster","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup","type":"docs"},{"id":223,"pageTitle":"Create a cluster","sectionTitle":"Prerequisites","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup#prerequisites","type":"docs"},{"id":224,"pageTitle":"Create a cluster","sectionTitle":"Prepare using the AKS preview","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup#prepare-using-the-aks-preview","type":"docs"},{"id":225,"pageTitle":"Create a cluster","sectionTitle":"Create resource group","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup#create-resource-group","type":"docs"},{"id":226,"pageTitle":"Create a cluster","sectionTitle":"Create AKS cluster","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup#create-aks-cluster","type":"docs"},{"id":227,"pageTitle":"Create a cluster","sectionTitle":"Cleanup","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setup#cleanup","type":"docs"},{"id":228,"pageTitle":"Installation","sectionTitle":"Installation","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/getting-started/install","type":"docs"},{"id":229,"pageTitle":"Known Limitations","sectionTitle":"Known Limitations","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/known-limitations","type":"docs"},{"id":230,"pageTitle":"Known Limitations","sectionTitle":"Availability","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/known-limitations#availability","type":"docs"},{"id":231,"pageTitle":"Known Limitations","sectionTitle":"Kubernetes Features","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/known-limitations#kubernetes-features","type":"docs"},{"id":232,"pageTitle":"Known Limitations","sectionTitle":"Runtime Policies","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/known-limitations#runtime-policies","type":"docs"},{"id":233,"pageTitle":"Known Limitations","sectionTitle":"Tooling Integration","sectionRoute":"/contrast/pr-preview/pr-1071/0.6/known-limitations#tooling-integration","type":"docs"}],"index":{"version":"2.3.9","fields":["title","content","tags"],"fieldVectors":[["title/118",[0,0.299]],["content/118",[0,0.393,1,4.629,2,2.372,3,1.746,4,1.472,5,1.508,6,0.729,7,1.74,8,3.068,9,3.197,10,2.014,11,3.246,12,1.355,13,3.068,14,2.558,15,3.068,16,2.143,17,1.261,18,4.629,19,2.372,20,3.068,21,4.629,22,1.655,23,3.727,24,4.629,25,4.629,26,4.629,27,3.727,28,2.29,29,3.246,30,2.664,31,2.783,32,2.214,33,4.629,34,3.068,35,4.086,36,2.461,37,2.29,38,2.29]],["tags/118",[]],["title/119",[39,5.064]],["content/119",[0,0.32,6,0.714,7,1.715,9,2.322,17,1.234,38,2.242,40,2.855,41,4,42,1.621,43,3.387,44,3.178,45,3.649,46,2.847,47,3.711,48,3.004,49,4,50,2.242,51,3.649,52,2.168,53,3.649,54,4,55,4.597,56,1.972,57,4.532,58,1.579,59,3.387,60,2.724,61,4.532,62,2.409,63,2.033,64,3.004,65,3.387,66,3.178,67,4.532,68,1.621,69,4.532,70,3.178,71,4.532,72,2.608,73,4,74,2.242,75,1.914,76,4,77,3.649,78,2.242,79,4.532,80,4,81,2.608,82,3.649]],["tags/119",[]],["title/120",[83,0.778,84,2.962]],["content/120",[0,0.27,4,0.968,5,0.991,17,1.412,38,3.326,42,2.405,56,2.255,58,1.806,59,3.874,83,0.858,84,3.265,85,5.184,86,2.405,87,2.756,88,3.436,89,4.174,90,5.934,91,5.184,92,3.265,93,1.09,94,5.184,95,3.635,96,3.436,97,4.174,98,3.635,99,4.575,100,3.635,101,4.174,102,4.575,103,4.174,104,4.575,105,2.479,106,5.184]],["tags/120",[]],["title/121",[107,3.515,108,2.41]],["content/121",[0,0.324,4,1.163,5,1.191,36,3.311,86,2.227,87,3.311,88,4.128,109,6.229,110,5.497,111,3.744,112,6.229,113,6.229,114,5.497,115,6.229,116,5.497,117,3.081]],["tags/121",[]],["title/122",[]],["content/122",[0,0.337,42,2.316,83,1.072,118,2.316,119,5.416,120,2.762,121,4.08,122,5.215,123,3.893,124,2.998]],["tags/122",[]],["title/123",[118,1.682,119,3.298]],["content/123",[0,0.344,42,2.363,83,1.093,119,4.634,120,2.796,121,4.163,122,5.321,123,3.973,124,3.059]],["tags/123",[]],["title/124",[119,3.298,120,1.682]],["content/124",[0,0.307,3,2.225,22,1.525,29,2.99,37,2.109,42,2.419,83,0.976,86,1.525,92,2.686,119,4.136,120,2.961,121,3.716,122,4.75,123,3.546,124,2.731,125,2.039,126,3.763,127,4.264,128,1.566,129,2.356,130,3.433,131,2.356,132,4.264,133,4.264,134,3.187,135,3.187,136,4.264,137,2.99,138,5.206,139,2.563,140,3.433,141,2.826,142,3.763,143,2.99,144,2.826,145,1.974,146,3.763,147,3.763,148,2.826,149,3.763,150,1.134,151,3.763,152,1.653,153,2.563,154,4.264,155,2.686]],["tags/124",[]],["title/125",[131,3.17]],["content/125",[0,0.301,2,2.964,93,1.216,118,2.578,131,3.196,148,3.834,156,1.365,157,3.196,158,3.075,159,2.678,160,3.643,161,3.834,162,3.834,163,3.834,164,1.963,165,3.694,166,1.275,167,3.477,168,2.594]],["tags/125",[]],["title/126",[118,1.682,156,0.817]],["content/126",[0,0.334,2,3.286,131,3.543,148,4.25,156,1.334,157,3.543,158,3.409,159,2.969,160,4.039,161,4.25,162,4.25,163,4.25]],["tags/126",[]],["title/127",[118,1.425,164,1.085,165,2.041]],["content/127",[93,1.448,164,1.876,165,3.53,166,1.518,167,4.141,168,3.09]],["tags/127",[]],["title/128",[0,0.245,156,0.817]],["content/128",[0,0.281,2,3.537,52,2.582,86,1.931,88,3.579,128,1.983,131,3.814,148,3.579,156,1.393,157,2.983,158,2.87,159,2.499,160,3.401,161,3.579,162,3.579,163,3.579,169,5.4,170,3.107,171,4.765,172,2.87,173,4.347,174,5.4,175,5.4,176,5.4,177,4.765,178,5.4,179,5.4]],["tags/128",[]],["title/129",[131,2.598,156,0.817]],["content/129",[0,0.179,17,0.934,52,1.641,62,2.684,68,1.227,83,0.568,98,2.405,105,3.37,128,1.26,131,2.79,141,2.274,145,2.338,150,1.758,156,1.358,158,1.823,161,2.274,162,2.274,163,2.274,165,1.758,180,2.405,181,2.564,182,2.321,183,4.438,184,2.762,185,2.564,186,3.431,187,3.431,188,5.05,189,4.202,190,2.762,191,1.448,192,3.514,193,3.431,194,5.05,195,2.684,196,1.539,197,3.027,198,5.05,199,2.79,200,4.438,201,1.294,202,3.973,203,3.186,204,3.431,205,3.431,206,3.027,207,2.161,208,2.062,209,4.457,210,1.641,211,1.08,212,2.405,213,2.762,214,3.027,215,2.161]],["tags/129",[]],["title/130",[156,0.692,172,2.118,216,1.682]],["content/130",[0,0.351,145,3.123,156,1.172,170,3.883,216,2.848,217,3.457,218,5.042,219,5.954]],["tags/130",[]],["title/131",[12,1.166,156,0.692,220,2.041]],["content/131",[0,0.129,3,1.488,4,1.138,5,1.068,6,0.621,7,0.693,9,1.273,10,1.081,12,1.898,14,1.373,16,2.586,17,1.074,19,1.273,22,1.998,28,1.229,37,1.229,48,1.647,52,2.346,68,0.889,77,2.001,82,2.001,111,1.494,150,1.808,156,1.059,160,1.565,162,1.647,163,1.647,170,1.43,172,2.097,182,0.782,184,2.001,192,3.749,200,1.565,201,1.85,211,0.782,216,1.049,219,2.193,221,1.857,222,2.193,223,1.647,224,2.969,225,3.44,226,4.498,227,2.001,228,2.193,229,1.57,230,2.485,231,1.647,232,1.229,233,2.823,234,2.766,235,1.618,236,1.43,237,2.001,238,1.529,239,2.001,240,1.857,241,2.193,242,2.193,243,1.15,244,1.494,245,1.565,246,3.666,247,2.193,248,3.945,249,2.949,250,1.742,251,1.647,252,1.019,253,2.948,254,2.001,255,3.251,256,2.71,257,1.647,258,2.485,259,1.857,260,2.193,261,1.565,262,2.485,263,2.18,264,2.485,265,1.15,266,1.565,267,0.889,268,2.001,269,1.857,270,1.857,271,1.647,272,2.485,273,3.176,274,2.27,275,1.565,276,2.001,277,1.742,278,1.742,279,2.001,280,2.193]],["tags/131",[]],["title/132",[120,1.425,166,0.878,182,1.255]],["content/132",[0,0.31,4,0.634,5,0.958,6,1.104,9,2.568,12,1.743,17,0.924,19,3.052,58,1.183,78,1.679,93,0.714,120,1.792,138,2.996,145,1.571,150,1.333,156,1.035,161,2.25,162,2.25,163,2.25,166,1.546,167,3.012,181,2.537,182,2.071,184,2.733,192,3.166,195,3.166,196,2.672,197,4.422,200,3.156,201,1.28,211,1.069,232,2.479,233,1.954,263,1.875,281,1.431,282,2.664,283,4.035,284,2.537,285,4.035,286,3.395,287,3.395,288,2.996,289,2.537,290,3.395,291,2.996,292,6.577,293,5.295,294,3.395,295,2.884,296,3.395,297,3.395,298,3.395,299,3.395,300,2.537,301,1.804,302,3.745,303,3.395,304,2.537]],["tags/132",[]],["title/133",[42,1.236,105,1.653,183,2.177,203,1.837]],["content/133",[0,0.281,42,1.931,62,2.87,63,3.096,83,1.142,105,3.639,120,1.931,156,0.938,164,1.88,168,3.096,172,2.87,183,4.792,202,4.149,203,2.87,213,4.347,220,3.537,305,3.786,306,4.765,307,4.765,308,2.671,309,2.499,310,2.093]],["tags/133",[]],["title/134",[192,2.118,200,2.509,201,1.503]],["content/134",[]],["tags/134",[]],["title/135",[192,2.118,241,3.516,311,3.208]],["content/135",[0,0.169,5,1.109,10,1.41,17,0.883,19,3.295,22,1.159,37,2.396,42,1.159,48,2.149,52,2.772,68,1.732,124,2.242,129,1.791,150,1.288,152,1.257,153,1.949,156,1.195,170,1.866,182,1.021,192,1.723,196,1.454,201,1.827,210,2.316,216,1.369,217,1.661,224,3.081,225,3.396,226,2.61,229,0.785,232,1.604,234,2.273,235,1.33,236,1.866,238,1.257,246,3.619,247,2.861,249,4.136,250,3.396,251,3.21,252,1.33,253,2.423,255,3.842,256,1.791,264,2.042,265,1.501,272,4.547,274,1.866,295,1.866,308,1.604,312,3.242,313,3.242,314,2.423,315,2.61,316,3.242,317,3.242,318,2.042,319,2.042,320,2.861,321,2.861,322,2.149,323,3.242,324,2.423,325,2.61,326,2.61,327,2.861,328,2.861,329,2.61,330,3.242,331,3.242,332,3.242,333,2.61,334,3.242,335,1.661,336,1.866,337,2.861,338,2.861,339,2.149,340,2.861]],["tags/135",[]],["title/136",[150,1.059,192,2.118,200,2.509]],["content/136",[0,0.212,6,0.642,12,1.193,19,2.929,52,1.95,62,2.167,68,1.458,72,2.346,83,0.674,96,2.702,120,1.458,125,1.95,141,2.702,144,2.702,145,1.887,150,2.004,152,1.58,156,0.993,166,0.898,192,2.167,195,3.039,196,2.961,200,3.601,212,2.859,216,2.414,225,2.859,229,1.384,233,2.346,249,2.451,252,1.672,255,2.702,272,4.159,281,1.165,300,3.047,302,3.047,304,4.273,318,2.568,335,2.929,337,3.598,341,4.077,342,2.451,343,3.282,344,4.077,345,2.089,346,4.077,347,3.159,348,4.077,349,4.077,350,3.598,351,2.252,352,3.047,353,3.598,354,2.346,355,2.568]],["tags/136",[]],["title/137",[0,0.159,156,0.53,177,2.693,356,3.051,357,2.693]],["content/137",[]],["tags/137",[]],["title/138",[0,0.159,147,2.693,156,0.53,159,1.412,358,3.051]],["content/138",[0,0.352,3,2.549,4,0.976,6,0.823,20,3.463,22,2.417,38,2.585,44,3.664,68,1.869,78,2.585,86,1.869,98,3.664,123,3.141,145,2.419,150,1.39,156,0.908,159,2.419,223,3.463,229,1.265,232,3.344,236,3.007,252,2.772,261,3.291,308,2.585,359,5.442,360,5.226,361,4.612,362,2.678,363,3.905,364,3.664]],["tags/138",[]],["title/139",[0,0.159,86,1.091,145,1.412,156,0.53,252,1.251]],["content/139",[0,0.361,6,0.857,12,1.593,19,2.79,28,2.693,86,1.947,87,2.894,150,1.448,165,2.79,180,3.818,182,1.715,192,3.689,200,3.429,201,2.054,210,2.604,211,1.715,221,4.069,223,3.609,224,2.894,265,2.52,268,4.384,269,4.069,270,4.069,282,2.894,355,3.429,365,5.445,366,3.273,367,4.384,368,3.008]],["tags/139",[]],["title/140",[17,0.941,86,1.236,88,2.29,156,0.6]],["content/140",[14,2.576,17,1.27,22,1.667,36,2.478,42,1.667,45,3.754,52,2.23,56,2.028,64,3.09,65,3.485,66,3.269,68,2.242,78,3.101,81,2.683,86,1.667,88,3.09,93,1.489,156,1.089,170,2.683,181,3.485,183,2.937,208,2.803,229,1.517,231,3.09,308,2.306,315,3.754,355,2.937,361,5.533,368,2.576,369,3.09,370,4.663,371,4.115,372,3.754,373,4.155,374,3.485,375,2.576,376,4.663,377,4.663,378,2.803,379,2.683,380,3.09,381,4.663,382,4.115]],["tags/140",[]],["title/141",[156,0.6,182,1.088,202,2.077,308,1.709]],["content/141",[0,0.27,19,3.445,50,2.564,83,0.858,96,4.456,141,3.436,156,1.168,172,2.756,182,2.117,192,2.756,201,1.955,202,4.042,217,2.656,221,3.874,252,2.126,285,4.174,300,3.874,302,3.874,308,2.564,322,3.436,354,2.983,364,3.635,383,5.184,384,5.934,385,3.635,386,2.756,387,3.874,388,5.184,389,5.184,390,4.174,391,4.174]],["tags/141",[]],["title/142",[83,0.505,105,1.459,156,0.53,183,1.922,202,1.834]],["content/142",[17,1.47,27,4.347,37,2.671,42,1.931,46,2.499,68,1.931,83,1.142,86,2.468,92,3.401,105,2.582,125,2.582,156,1.199,164,1.47,168,2.422,172,2.87,182,1.7,183,3.401,202,3.246,207,3.401,209,4.765,210,2.582,220,2.767,267,1.931,309,2.499,310,2.093,392,5.4,393,5.4,394,4.765,395,3.107]],["tags/142",[]],["title/143",[279,4.62]],["content/143",[0,0.293,6,0.887,17,1.534,27,4.536,86,2.536,98,3.95,125,2.694,148,3.734,156,0.979,161,3.734,172,2.995,215,3.549,216,2.379,252,2.31,279,4.536,321,4.972,347,3.113,354,3.242,396,4.536,397,5.634,398,3.113,399,5.634,400,4.972,401,3.734,402,4.972,403,2.887]],["tags/143",[]],["title/144",[164,1.281,165,2.41]],["content/144",[6,0.694,63,1.978,83,1.139,93,1.63,105,2.887,156,0.766,164,2.273,165,2.259,166,1.517,167,2.65,168,3.087,172,2.344,182,2.167,280,3.891,281,1.26,282,2.344,309,2.041,310,2.34,351,2.436,384,3.891,404,3.092,405,2.789,406,3.295,407,2.65,408,3.092,409,2.922,410,3.55,411,3.55,412,3.092,413,1.26,414,2.65,415,3.295,416,2.65]],["tags/144",[]],["title/145",[47,2.118,217,2.041,386,2.118]],["content/145",[5,0.805,47,2.237,83,0.696,93,0.885,152,1.632,164,2.355,166,1.288,168,3.759,217,3.907,224,3.107,281,1.67,322,3.874,324,5.423,386,2.237,405,2.528,414,2.53,416,2.53,417,3.389,418,4.209,419,2.951,420,5.534,421,4.209,422,3.715,423,3.146,424,4.209,425,3.146,426,3.146,427,2.325]],["tags/145",[]],["title/146",[164,1.281,426,3.515]],["content/146",[5,0.678,6,0.558,9,1.815,42,1.267,50,2.558,64,2.348,83,0.855,93,1.659,105,1.694,117,1.753,125,1.694,137,2.484,164,1.944,166,1.345,168,3.011,182,1.923,203,3.795,211,1.116,213,4.163,217,2.649,243,1.64,252,1.453,281,2.199,282,1.883,310,1.373,322,2.348,324,3.864,352,2.648,355,2.231,378,2.13,403,2.649,405,2.487,413,1.744,416,2.13,420,4.281,425,3.864,426,2.648,428,2.348,429,2.648,430,3.128,431,2.648,432,3.127,433,3.543,434,3.127,435,3.127,436,3.543,437,2.484,438,3.127,439,3.543,440,3.127]],["tags/146",[]],["title/147",[164,1.085,409,2.64,441,3.984]],["content/147",[2,1.457,5,0.544,12,0.832,37,1.407,42,2.15,50,1.407,72,1.637,81,1.637,83,0.995,84,1.791,93,1.504,152,1.103,156,0.494,164,2.352,166,1.512,168,3.398,182,2.386,189,1.994,203,3.453,224,2.844,233,1.637,235,1.166,265,2.03,281,1.718,307,2.51,322,1.885,404,1.994,405,2.926,413,1.528,416,1.71,420,1.994,427,3.322,430,2.247,437,3.075,442,3.999,443,2.126,444,2.126,445,1.317,446,2.51,447,2.844,448,2.906,449,3.87,450,2.523,451,2.51,452,1.71,453,1.994,454,2.51,455,2.51]],["tags/147",[]],["title/149",[4,0.878,5,0.899]],["content/149",[0,0.352,4,1.262,5,0.999,7,1.457,11,4.739,12,1.529,17,1.423,30,3.89,36,2.778,38,2.585,83,1.118,87,2.778,89,4.207,229,1.265,304,3.905,400,4.612,401,4.48,408,3.664,456,4.207,457,5.226,458,4.612,459,4.612,460,4.612,461,4.207,462,4.207,463,5.226,464,4.207,465,5.226,466,5.226,467,5.226]],["tags/149",[]],["title/150",[7,1.312,468,2.827]],["content/150",[4,0.931,5,1.401,7,1.39,9,2.554,10,2.168,12,1.459,36,2.65,38,2.466,63,2.236,74,2.466,83,0.825,84,3.14,139,3.94,210,2.384,229,1.883,271,3.304,278,3.495,336,2.869,468,4.401,469,4.985,470,4.399,471,3.725,472,4.399,473,2.869,474,4.985,475,3.495,476,4.985,477,4.985,478,4.014,479,4.014,480,4.985,481,4.985,482,4.985,483,3.304]],["tags/150",[]],["title/151",[5,0.899,10,2.046]],["content/151",[3,2.226,4,0.925,5,1.248,7,1.382,10,2.567,12,2.04,16,3.669,17,0.91,20,2.215,40,2.105,47,1.777,52,1.598,56,2.155,62,1.777,72,1.923,74,1.653,83,0.553,95,2.343,124,1.547,140,2.691,145,1.547,150,1.57,156,0.581,158,1.777,159,2.293,165,1.712,191,2.091,211,1.052,229,1.199,238,1.296,243,1.547,244,2.977,255,3.283,256,3.606,264,4.39,267,1.195,272,2.105,335,1.712,336,2.851,342,2.009,391,4.752,395,2.851,406,2.498,475,2.343,478,2.691,484,3.342,485,2.95,486,2.95,487,1.598,488,3.342,489,3.342,490,1.846,491,2.95,492,2.215,493,3.342,494,3.342,495,3.342,496,2.215,497,2.691,498,2.691,499,2.343,500,3.342,501,2.95,502,3.988,503,2.95]],["tags/151",[]],["title/152",[30,2.293,31,2.395,32,1.905]],["content/152",[0,0.279,6,0.843,7,1.493,16,3.178,17,1.458,30,4.362,31,3.219,32,3.284,58,1.866,75,2.261,100,3.755,180,3.755,244,3.219,311,4.312,367,4.312,375,3.793,413,1.53,483,3.549,487,3.284,491,4.726,498,4.312,504,5.131,505,5.528,506,4.726,507,4.002]],["tags/152",[]],["title/153",[87,2.5,508,4.703]],["content/153",[0,0.366,4,0.97,5,1.122,6,1.001,7,1.773,8,1.798,12,0.794,17,1.151,22,0.97,32,1.298,40,1.709,42,0.97,47,2.247,56,1.18,58,1.473,68,1.857,70,3.642,73,3.731,74,2.569,75,1.146,76,2.395,77,2.185,78,2.091,80,2.395,83,0.449,86,2.273,87,1.442,88,1.798,93,0.889,95,1.903,100,1.903,101,2.185,105,1.298,110,2.395,128,0.996,131,1.499,156,0.734,159,1.256,164,0.739,182,0.854,201,1.023,208,1.631,210,1.298,211,0.854,216,1.146,217,2.166,220,2.166,232,2.091,235,1.113,252,1.734,271,1.798,295,1.562,308,1.342,309,1.256,310,1.052,319,1.709,362,1.39,369,1.798,375,1.499,380,1.798,386,1.442,395,1.562,405,0.945,413,1.208,414,1.631,415,2.028,417,2.185,430,1.39,431,2.028,490,1.499,499,1.903,504,2.028,509,2.713,510,2.395,511,3.404,512,2.713,513,2.185,514,2.713,515,2.713,516,1.562,517,2.713,518,2.713,519,2.713,520,2.713,521,2.713,522,2.713,523,2.713,524,1.709,525,2.185,526,2.713,527,2.028,528,2.395,529,2.395,530,2.395,531,2.713,532,2.395,533,2.185,534,2.395,535,2.028,536,2.713,537,2.395,538,2.185,539,2.713,540,1.631,541,1.798,542,2.713,543,2.713,544,2.028,545,2.185]],["tags/153",[]],["title/154",[0,0.207,86,1.425,546,3.516]],["content/154",[0,0.35,2,2.157,4,0.786,6,0.663,7,1.174,9,2.157,17,1.146,19,2.157,37,2.892,40,2.651,42,1.505,47,3.107,50,2.082,56,3.157,74,2.082,78,2.082,86,2.091,92,3.682,93,0.885,95,2.951,103,3.389,125,2.013,189,2.951,210,2.013,220,2.157,225,2.951,295,2.422,318,2.651,375,2.325,379,2.422,386,2.237,413,1.202,414,2.53,462,3.389,483,2.79,499,2.951,547,3.389,548,4.209,549,3.715,550,5.159,551,4.209,552,4.209,553,5.159,554,4.209,555,4.209,556,3.715,557,3.715,558,3.715,559,4.209,560,4.209,561,3.389,562,2.79,563,4.209,564,4.209,565,2.951]],["tags/154",[]],["title/155",[4,0.744,38,1.971,566,3.984]],["content/155",[0,0.286,3,1.706,4,1.147,12,0.866,13,1.962,17,1.231,19,2.317,20,3.636,22,2.196,34,1.962,35,2.613,36,1.574,38,2.714,42,1.962,44,3.847,45,3.641,46,2.093,47,1.574,50,1.465,66,2.076,68,1.617,78,2.237,83,0.49,86,1.617,87,1.574,93,1.466,97,2.384,104,2.613,123,1.78,125,1.416,131,1.636,145,2.54,150,0.787,156,1.26,157,1.636,159,2.093,170,2.603,172,1.574,180,2.076,182,0.932,202,1.78,203,1.574,207,1.865,211,0.932,215,1.865,218,2.213,229,1.601,233,2.603,235,1.214,236,1.704,238,1.148,252,1.214,282,1.574,315,2.384,319,1.865,342,1.78,347,1.636,351,1.636,363,2.213,364,2.076,367,3.641,371,2.613,372,2.384,374,2.213,378,3.298,380,1.962,403,1.517,419,2.076,444,2.213,448,1.962,541,1.962,567,2.961,568,2.613,569,2.961,570,2.076,571,2.961,572,2.961,573,2.613,574,5.487,575,2.613,576,2.613,577,2.961]],["tags/155",[]],["title/156",[0,0.207,6,0.627,216,1.682]],["content/156",[0,0.232,3,1.323,4,1.328,5,1.446,6,0.891,7,1.432,9,2.278,11,1.506,12,1.301,15,2.947,16,2.058,17,1.211,19,1.797,20,2.325,22,2.023,38,1.735,47,1.142,49,1.895,50,1.735,51,5.379,52,1.678,53,1.729,56,0.934,58,1.222,60,1.291,62,1.142,68,1.254,83,0.736,87,1.142,93,1.079,118,0.768,128,1.288,130,1.729,150,1.365,156,0.983,159,2.058,160,1.353,166,0.773,167,1.291,180,1.506,182,1.4,195,1.865,196,1.573,202,1.291,208,1.291,210,1.678,211,0.676,215,1.353,216,2.167,220,1.1,226,3.58,228,1.895,229,1.469,231,1.423,232,1.735,233,1.236,235,0.881,238,0.833,249,1.291,261,1.353,264,2.21,265,1.624,268,1.729,269,1.605,275,1.353,281,1.616,282,1.142,295,2.019,320,3.096,335,1.1,345,1.1,347,1.187,380,1.423,387,1.605,403,1.1,405,0.748,413,1.27,516,1.236,533,1.729,535,1.605,570,1.506,575,1.895,578,2.148,579,2.148,580,1.729,581,2.148,582,2.148,583,3.508,584,1.506,585,1.895,586,1.506,587,1.506,588,1.729,589,2.148,590,2.148,591,3.508,592,2.148,593,2.148,594,2.148,595,2.148,596,2.148,597,2.148,598,2.148,599,2.148,600,1.142,601,2.148,602,1.895,603,1.291,604,1.729,605,3.096]],["tags/156",[]],["title/157",[0,0.207,6,0.627,606,3.516]],["content/157",[0,0.279,3,1.405,4,0.696,5,1.202,6,0.989,7,1.496,17,1.46,22,1.332,42,2.604,46,2.483,50,1.843,52,1.782,55,2.784,56,1.621,58,1.868,59,2.784,68,1.332,74,1.843,78,3.603,83,0.616,93,1.445,105,3.005,123,2.24,128,1.368,156,0.647,166,0.821,182,1.173,191,1.573,203,3.34,210,1.782,216,1.573,220,1.909,229,0.902,238,2.436,267,1.332,306,3.288,326,3,336,2.144,354,2.144,369,2.469,378,3.223,413,1.064,419,2.613,431,2.784,487,1.782,490,2.058,496,2.469,499,2.613,565,2.613,585,3.288,586,2.613,607,3.726,608,3,609,2.058,610,2.469,611,3.726,612,2.784,613,2.784,614,3.726]],["tags/157",[]],["title/158",[379,2.293,613,2.977,615,2.977]],["content/158",[0,0.272,2,2.678,4,0.976,19,2.678,38,2.585,46,2.419,60,5.051,96,3.463,111,3.141,128,1.919,157,2.887,210,3.583,220,2.678,379,3.007,385,3.664,413,1.493,450,3.007,507,3.905,587,3.664,615,3.905,616,4.612,617,4.612,618,5.226,619,5.226,620,4.612,621,4.207,622,2.778,623,4.612,624,4.207]],["tags/158",[]],["title/159",[60,2.827,625,4.15]],["content/159",[0,0.125,4,0.449,5,1.048,6,0.378,7,1.338,14,3.028,17,1.306,22,0.859,40,1.513,42,1.373,46,3.326,47,2.041,48,2.545,53,1.934,54,2.12,56,2.918,59,1.795,60,3.841,63,2.458,64,5.157,65,1.795,66,2.693,78,2.964,81,2.21,93,1.152,97,1.934,105,1.149,121,1.513,129,1.327,156,0.667,210,1.149,220,1.231,229,0.929,232,1.188,236,2.21,237,1.934,238,1.489,245,1.513,267,0.859,275,3.022,293,1.934,301,1.277,305,2.693,310,0.931,319,1.513,355,1.513,373,1.592,379,2.21,380,1.592,385,1.684,395,1.382,401,1.592,403,1.231,407,1.444,408,1.684,413,1.097,414,1.444,427,1.327,434,2.12,450,1.382,452,1.444,492,2.545,496,1.592,499,1.684,549,2.12,562,1.592,570,3.364,580,1.934,584,1.684,587,1.684,600,1.277,608,3.862,610,1.592,616,2.12,625,2.12,626,2.402,627,2.402,628,2.12,629,2.402,630,2.402,631,2.402,632,1.684,633,3.389,634,2.87,635,1.934,636,1.934,637,2.402,638,2.402,639,2.12,640,2.12,641,2.402,642,1.513,643,2.402,644,2.12,645,2.402,646,2.12,647,2.402,648,2.402,649,2.12,650,2.402,651,2.402,652,2.402,653,2.402,654,3.84,655,2.402,656,1.795,657,1.934,658,2.402,659,2.12]],["tags/159",[]],["title/160",[60,2.827,584,3.298]],["content/160",[4,1.238,5,1.498,6,0.412,7,1.145,14,3.662,17,0.712,22,0.935,29,1.834,52,1.251,56,3.351,60,4.316,63,1.173,78,3.279,81,1.505,83,0.433,93,1.725,128,0.96,153,1.572,156,1.085,157,1.445,166,0.576,210,1.251,229,0.994,232,2.032,236,2.364,238,1.592,301,1.39,310,1.014,336,1.505,339,1.733,340,2.308,351,1.445,407,1.572,413,1.449,444,1.954,452,1.572,496,2.722,537,2.308,556,2.308,570,2.88,584,2.88,587,4.03,588,3.307,622,1.39,634,4.295,635,2.105,646,5.512,656,1.954,659,2.308,660,1.954,661,2.308,662,2.615,663,3.556,664,4.107,665,4.107,666,3.307,667,1.647,668,2.615,669,2.615,670,1.39,671,2.615,672,1.733,673,2.615,674,2.308,675,2.105,676,2.615,677,2.615,678,2.615,679,2.308,680,2.308,681,2.615,682,2.615]],["tags/160",[]],["title/161",[379,2.706,615,3.515]],["content/161",[0,0.218,4,0.569,5,1.114,6,0.358,7,0.634,8,0.855,19,0.661,22,1.997,28,0.638,42,0.813,44,2.576,46,0.597,60,4.496,64,0.855,68,0.813,81,1.308,83,0.376,86,0.461,93,1.409,95,0.904,96,0.855,114,1.138,128,0.474,129,1.256,137,0.904,139,1.832,145,1.411,150,1.229,156,1.225,157,2.03,160,0.812,164,0.351,166,1.284,172,0.686,182,0.406,191,0.545,192,0.686,203,0.686,208,1.366,211,0.716,214,1.138,216,0.545,217,0.661,222,1.138,225,0.904,229,1.55,231,0.855,232,2.883,236,1.308,238,2.342,243,0.597,250,0.904,251,0.855,252,0.529,254,1.83,263,0.713,267,0.461,272,0.812,285,1.039,291,1.138,301,0.686,302,0.964,308,0.638,309,1.411,310,1.935,335,0.661,339,0.855,342,0.775,343,1.039,350,1.138,351,2.03,353,2.69,355,2.314,362,1.165,368,0.713,369,0.855,372,1.039,373,2.02,374,0.964,378,2.518,379,3.686,387,0.964,390,1.039,396,2.454,405,1.062,411,1.039,413,1.595,419,0.904,425,0.964,427,0.713,430,0.661,443,1.699,445,1.052,448,0.855,450,0.742,485,2.006,490,0.713,496,2.777,513,1.039,541,0.855,570,0.904,584,2.137,587,2.576,588,1.83,609,1.684,615,5.19,617,1.138,622,0.686,623,1.138,624,1.039,633,3.242,634,2.278,635,2.958,656,1.699,660,2.745,661,2.006,663,2.137,667,1.432,672,0.855,675,1.83,683,1.29,684,1.29,685,0.855,686,1.29,687,2.006,688,1.29,689,1.29,690,1.138,691,0.904,692,0.812,693,1.29,694,1.29,695,1.29,696,2.137,697,0.812,698,1.138,699,1.29,700,0.904,701,1.138,702,1.29,703,4.19,704,1.83,705,1.29,706,1.138,707,1.29,708,1.29,709,1.29,710,1.699,711,1.29,712,1.29,713,2.273,714,1.29,715,1.29,716,1.29,717,1.29,718,1.138,719,0.964,720,0.964,721,1.29,722,1.29,723,1.29,724,1.29,725,1.29,726,1.83,727,1.29,728,1.29,729,1.29]],["tags/161",[]],["title/162",[63,1.369,172,1.622,379,1.756,394,2.693,613,2.28]],["content/162",[0,0.11,2,1.079,4,0.393,6,0.543,9,1.769,11,2.421,14,1.164,17,0.573,20,2.288,22,1.234,36,1.119,39,1.859,40,1.326,42,2.688,46,1.598,47,1.835,52,1.651,56,2.616,63,1.548,64,2.288,65,1.574,66,1.477,74,2.17,78,3.28,83,0.571,84,2.174,86,1.234,90,1.859,92,2.174,93,1.394,98,2.421,99,3.046,100,1.477,101,1.696,102,1.859,103,3.532,105,2.098,125,1.007,128,0.773,139,1.266,145,0.975,149,1.859,155,1.326,156,0.366,157,1.164,167,1.266,182,0.663,183,2.763,189,1.477,203,2.332,207,1.326,215,1.326,216,0.889,218,1.574,220,1.079,231,1.396,233,1.212,238,0.816,243,0.975,252,1.799,278,1.477,282,1.119,283,1.696,288,1.859,305,3.557,347,1.164,359,1.696,368,1.164,379,2.524,382,1.859,396,1.696,407,1.266,408,2.421,411,1.696,419,2.421,445,0.975,459,1.859,483,2.288,506,1.859,510,1.859,516,1.212,550,3.871,553,1.859,562,1.396,573,1.859,606,1.859,609,1.164,613,3.278,649,1.859,660,1.574,680,1.859,720,1.574,730,1.859,731,4.387,732,3.452,733,3.452,734,3.452,735,3.046,736,2.106,737,2.106,738,2.106,739,2.106,740,1.696,741,2.106,742,2.106,743,1.266,744,2.106,745,2.106,746,2.106,747,2.106,748,3.452,749,2.106,750,1.477,751,3.452,752,2.106,753,3.046,754,1.696,755,2.106,756,3.452,757,1.859,758,4.387,759,2.106,760,2.106,761,3.452,762,2.106,763,1.859,764,1.859,765,2.106,766,2.106,767,2.106,768,1.859,769,2.106,770,2.106,771,2.106,772,2.106,773,2.106]],["tags/162",[]],["title/163",[216,2.423]],["content/163",[0,0.375,4,1.08,5,1.106,6,0.911,7,1.613,8,3.834,17,1.575,22,2.069,23,4.657,74,3.566,89,4.657,216,3.044,217,2.964,231,3.834,232,2.861,314,4.323,327,5.105,328,5.105,546,5.105,774,5.785,775,5.105]],["tags/163",[]],["title/164",[120,1.236,124,1.6,329,2.782,471,2.583]],["content/164",[0,0.397,6,1.057,7,1.174,17,1.146,40,2.651,58,1.466,62,2.237,68,1.505,72,2.422,74,2.892,75,2.468,78,2.082,120,2.595,125,2.013,150,1.555,156,1.016,159,1.948,166,1.288,182,1.325,201,2.737,211,2.115,229,1.415,232,2.082,243,1.948,263,2.325,281,1.67,283,3.389,295,2.422,308,2.082,314,3.146,345,2.157,354,2.422,403,2.995,410,3.389,524,2.651,525,3.389,604,3.389,743,3.514,764,3.715,776,4.209,777,3.389,778,2.951,779,4.209]],["tags/164",[]],["title/165",[166,1.264]],["content/165",[0,0.301,3,1.217,4,0.901,5,1.105,6,1.176,8,2.138,9,1.653,12,1.691,14,3.193,17,0.878,44,2.262,58,1.124,68,2.067,83,0.798,86,1.154,93,1.014,100,2.262,105,1.543,148,2.138,156,1.252,159,2.969,160,2.032,164,1.747,165,1.653,166,1.588,168,1.447,182,2.162,195,1.715,196,1.447,207,2.032,211,1.519,224,1.715,233,1.856,252,1.323,263,1.782,281,1.651,289,2.411,295,1.856,345,1.653,351,1.782,369,3.198,395,1.856,402,2.847,413,0.921,414,1.939,427,1.782,444,2.411,445,1.493,533,2.597,534,4.258,540,1.939,541,2.138,621,2.597,628,2.847,704,2.597,740,2.597,780,3.226,781,3.226,782,3.226,783,3.226,784,2.032,785,2.847,786,3.383,787,3.226,788,2.411,789,3.226,790,2.847,791,3.226]],["tags/165",[]],["title/166",[281,1.639]],["content/166",[0,0.245,4,1.176,6,0.992,10,2.043,12,1.843,15,3.113,16,2.174,22,1.679,28,2.323,72,2.703,83,0.777,93,0.987,120,1.679,128,1.724,150,1.675,156,0.816,159,2.174,166,1.035,195,3.349,196,2.826,201,1.771,211,1.479,217,2.406,229,1.525,249,2.823,265,2.174,281,1.8,282,2.496,308,2.323,325,3.781,326,3.781,345,2.406,369,3.113,386,2.496,398,2.595,412,3.293,430,2.406,656,3.51,792,4.696,793,4.696,794,4.145,795,4.696]],["tags/166",[]],["title/167",[150,1.251,229,1.138]],["content/167",[0,0.223,4,1.267,5,1.133,6,1.069,7,1.893,9,2.199,10,1.867,14,2.372,15,2.845,16,1.987,17,1.169,22,1.535,68,2.119,83,0.71,120,1.535,125,2.053,140,3.456,150,2.111,167,2.58,215,3.733,229,1.642,252,1.76,256,3.274,261,3.733,282,2.282,333,4.771,336,2.47,345,2.199,375,2.372,412,3.01,432,3.788,452,2.58,501,5.989,527,4.429,532,3.788,743,2.58,796,5.926,797,5.23,798,3.788]],["tags/167",[]],["title/168",[235,2.353]],["content/168",[0,0.293,3,2.125,5,1.356,17,1.931,93,1.765,117,2.787,155,3.549,156,0.979,159,2.608,164,1.931,235,2.908,405,1.963,413,1.609,541,3.734,603,3.386,620,4.972,799,3.95,800,4.972,801,4.21]],["tags/168",[]],["title/169",[0,0.245,229,1.138]],["content/169",[0,0.281,7,1.506,17,1.47,56,2.349,58,1.881,74,2.671,75,3.213,229,1.941,238,2.093,240,4.035,244,3.246,245,3.401,259,4.035,260,4.765,275,3.401,398,2.983,428,3.579,473,3.107,487,3.301,778,4.84,802,3.579,803,4.347,804,5.4,805,5.4,806,5.4]],["tags/169",[]],["title/170",[150,1.526]],["content/170",[0,0.341,4,1.368,5,0.953,6,0.785,7,1.39,10,2.168,12,1.918,16,2.308,31,2.996,32,2.384,68,1.783,93,1.54,150,1.947,164,1.357,166,1.098,167,2.996,211,1.57,229,1.206,234,3.495,265,2.308,281,1.872,318,3.14,335,2.554,354,2.869,368,2.754,404,3.495,453,3.495,561,4.014,794,4.399,807,4.399,808,3.725,809,4.985,810,4.985]],["tags/170",[]],["title/171",[811,5.738]],["content/171",[3,1.71,4,0.846,10,3.037,15,3.004,16,2.098,37,2.242,42,2.199,51,3.649,111,3.697,141,3.004,150,1.991,229,1.489,256,2.504,265,2.098,333,3.649,342,2.724,347,2.504,355,2.855,366,2.724,373,3.004,398,2.504,413,1.757,445,2.098,452,2.724,475,4.313,610,4.076,612,3.387,667,2.855,692,3.874,784,2.855,797,4,799,3.178,812,3.387,813,4.532,814,5.428,815,4.532,816,4,817,3.387,818,4,819,4.532,820,4,821,4]],["tags/171",[]],["title/172",[201,2.164]],["content/172",[0,0.215,5,1.103,7,1.609,10,1.796,12,1.945,17,1.124,22,1.476,37,2.042,42,2.063,48,2.736,68,1.476,83,0.683,120,2.377,124,1.911,150,1.098,152,1.601,153,2.482,158,2.195,201,2.176,221,3.086,229,1.396,238,2.577,250,2.895,251,2.736,256,2.281,276,4.644,281,1.648,329,3.324,342,2.482,347,2.281,362,2.115,366,2.482,478,4.644,502,5.352,503,5.09,610,2.736,612,3.086,639,3.644,696,2.895,697,2.601,719,3.086,740,3.324,818,3.644,821,3.644,822,4.129,823,4.129,824,4.129,825,4.129,826,3.644,827,3.324,828,3.644,829,4.129]],["tags/172",[]],["title/173",[830,4.62]],["content/173",[2,3.292,4,0.903,10,2.104,12,1.415,15,3.205,16,2.974,83,0.8,137,3.391,150,2.187,158,2.571,199,2.672,201,1.824,229,1.555,234,3.391,256,2.672,266,4.047,270,3.614,273,5.173,277,3.391,443,3.614,452,2.907,475,3.391,502,5.173,608,3.894,814,4.268,817,3.614,831,4.836,832,4.836,833,4.836,834,4.836,835,4.836,836,4.836,837,4.268,838,4.836,839,4.836]],["tags/173",[]],["title/174",[368,3.17]],["content/174",[5,1.373,12,1.201,13,2.719,17,1.117,22,2.054,28,2.029,42,1.467,48,3.806,68,1.467,93,0.863,117,2.029,121,2.584,124,1.899,128,1.506,139,2.466,145,1.899,150,1.908,152,1.59,153,3.452,201,2.166,224,2.181,234,2.877,238,2.226,239,3.303,254,3.303,267,1.467,295,2.361,335,2.102,339,2.719,366,3.452,368,2.267,435,3.621,460,3.621,516,3.305,538,3.303,557,3.621,609,3.173,696,2.877,784,2.584,827,3.303,828,3.621,830,3.303,840,4.103,841,4.103,842,4.103,843,3.303,844,4.103,845,5.742,846,4.103,847,3.621,848,3.621,849,3.303,850,3.303,851,3.621,852,4.103]],["tags/174",[]],["title/175",[50,2.839]],["content/175",[0,0.391,4,0.981,5,0.693,7,1.01,10,2.951,12,1.985,38,1.792,52,1.732,83,0.599,93,0.761,108,2.692,117,2.599,120,1.879,121,2.281,128,1.33,150,1.915,152,2.037,156,0.629,158,1.925,164,1.431,166,1.362,182,1.947,191,1.529,201,1.366,229,1.642,235,1.485,249,2.177,256,2.001,272,2.281,273,4.978,274,2.084,276,4.23,277,3.684,281,1.035,325,4.23,335,1.856,357,3.196,363,2.707,364,2.54,404,2.54,405,1.831,422,3.196,458,3.196,473,2.084,487,1.732,498,2.916,692,2.281,798,4.637,817,2.707,837,3.196,843,2.916,853,3.622,854,3.622,855,3.196,856,3.196,857,3.622]],["tags/175",[]],["title/176",[0,0.245,229,1.138]],["content/176",[0,0.39,4,0.973,5,0.997,6,0.564,7,0.999,12,2.098,23,2.884,83,1.186,117,1.772,118,2.676,134,3.895,139,2.153,190,2.884,229,1.869,244,2.153,245,2.256,265,1.658,267,1.281,274,3,282,1.904,318,2.256,416,2.153,445,1.658,468,3.133,471,2.677,473,3.536,479,2.884,778,5.028,784,3.283,808,2.677,858,3.454,859,3.582,860,3.457,861,2.677,862,4.947,863,4.197,864,3.582,865,2.884,866,4.592,867,3.536,868,6.144,869,2.677,870,2.512,871,3.582]],["tags/176",[]],["title/177",[216,1.682,401,2.64,487,1.905]],["content/177",[75,3.384,211,1.906,216,2.556,229,1.465,269,4.525,270,4.525,359,4.875,375,3.345,398,3.345,412,4.245,445,2.803,487,3.546,516,3.484,672,4.013,802,4.013,872,4.875]],["tags/177",[]],["title/178",[473,2.706,873,3.298]],["content/178",[0,0.286,2,2.813,7,1.531,36,2.919,83,0.908,139,3.3,141,3.639,157,3.034,170,3.16,274,3.16,468,3.3,473,4.644,475,3.85,479,4.421,675,4.421,750,3.85,803,4.421,855,4.846,862,4.421,867,3.16,869,4.104,870,3.85,873,4.892,874,4.421,875,4.846,876,4.421]],["tags/178",[]],["title/179",[56,1.188,74,1.351,244,1.642,245,1.72,275,1.72,877,2.411]],["content/179",[4,1.131,12,1.772,56,3.226,75,3.131,83,1.002,190,4.875,191,2.556,243,2.803,244,3.639,245,3.813,275,4.671,473,3.484,487,3.546,690,5.343,873,4.245]],["tags/179",[]],["title/180",[878,4.15,879,4.15]],["content/180",[0,0.307,5,1.516,10,1.855,12,1.248,16,1.974,17,1.161,36,2.267,37,2.109,68,1.525,83,1.119,93,0.897,125,2.039,150,1.799,156,0.741,216,2.491,229,1.032,238,3.072,246,3.187,249,2.563,250,4.136,251,3.91,255,2.826,256,2.356,261,2.686,264,2.686,265,2.731,284,3.187,293,3.433,335,2.185,339,2.826,375,2.356,378,2.563,398,2.356,456,3.433,473,2.454,663,2.99,784,2.686,878,5.206,879,5.969,880,4.264,881,4.264,882,3.763]],["tags/180",[]],["title/181",[12,1.166,16,1.844,238,1.544]],["content/181",[5,1.285,10,1.831,12,2.309,16,3.359,68,1.505,74,2.082,83,0.696,93,0.885,117,2.082,123,2.53,157,2.325,208,2.53,224,3.857,229,1.019,235,1.726,236,2.422,237,3.389,238,2.956,240,4.369,246,4.369,251,2.79,253,5.423,255,2.79,256,2.325,339,2.79,345,2.995,368,2.325,398,3.23,403,2.157,416,2.53,644,3.715,663,2.951,691,2.951,698,5.159,801,3.146,869,3.146,883,3.715,884,4.209,885,4.209,886,4.209,887,4.209]],["tags/181",[]],["title/182",[75,1.682,487,1.905,802,2.64]],["content/182",[0,0.371,6,0.634,7,1.581,12,1.658,16,2.623,56,1.751,74,1.992,75,3.375,108,2.063,128,1.478,207,2.536,224,2.14,229,1.372,238,1.561,239,3.242,240,3.009,244,2.42,245,2.536,253,3.009,267,1.44,271,2.669,274,2.317,275,2.536,301,2.14,336,2.317,345,2.063,347,2.224,401,2.669,427,2.224,450,2.317,468,3.406,473,4.096,487,3.136,634,3.009,657,3.242,663,2.823,672,2.669,778,3.974,802,2.669,803,4.563,808,3.009,862,3.242,867,2.317,873,3.974,875,3.553,877,3.553,888,4.026,889,3.553,890,4.026,891,3.553,892,3.553]],["tags/182",[]],["title/183",[405,1.639,413,1.343]],["content/183",[0,0.243,5,1.355,9,3.212,12,1.364,14,2.576,86,1.667,93,0.98,117,2.306,152,1.807,164,1.27,166,1.027,211,1.468,265,2.158,271,3.09,309,2.902,310,2.43,354,2.683,375,2.576,395,2.683,405,2.639,412,3.269,413,2.164,414,2.803,415,3.485,417,3.754,429,3.485,431,3.485,437,3.269,496,3.09,497,3.754,544,3.485,603,2.803,610,3.09,632,3.269,826,4.115,893,4.115,894,3.09,895,4.663,896,4.115,897,3.485]],["tags/183",[]],["title/184",[211,1.481,545,3.786]],["content/184",[5,1.277,22,2.388,83,1.105,153,4.013,211,2.103,405,2.326,413,1.907,898,5.376,899,5.376]],["tags/184",[]],["title/185",[900,4.62]],["content/185",[0,0.111,5,0.669,6,0.698,22,0.766,37,1.731,43,1.6,55,1.6,63,0.96,72,1.232,83,0.354,92,1.348,93,1.077,105,1.024,118,1.251,128,0.786,134,1.6,144,1.419,151,3.088,152,0.83,153,1.287,164,1.88,166,0.472,168,1.99,171,1.889,173,1.724,182,0.674,185,1.6,196,1.569,227,1.724,235,0.878,238,1.72,243,1.619,263,1.183,274,1.232,308,1.059,309,3.288,310,0.83,318,1.348,322,2.319,385,1.501,403,1.097,405,1.968,406,3.316,407,2.103,413,1.267,416,1.287,420,1.501,425,1.6,448,2.94,449,3.088,450,2.013,464,2.817,483,1.419,492,1.419,544,2.615,558,1.889,562,1.419,565,1.501,600,1.138,603,1.287,609,1.183,701,1.889,784,1.348,799,2.453,812,3.829,816,1.889,856,1.889,858,2.319,860,3.869,863,1.724,865,1.724,866,1.6,867,1.232,870,1.501,894,1.419,897,1.6,898,2.817,900,1.724,901,3.088,902,1.889,903,2.141,904,2.141,905,2.141,906,2.141,907,2.141,908,2.817,909,1.889,910,2.141,911,1.889,912,1.501,913,1.889,914,1.889,915,4.017,916,1.889,917,2.141,918,2.141,919,3.557,920,3.088,921,3.915,922,3.499,923,2.141,924,1.889,925,1.6,926,1.724,927,1.6,928,1.889,929,2.615,930,1.724,931,3.111,932,3.592,933,3.316,934,3.316,935,1.724,936,1.889,937,1.724,938,2.141,939,1.889,940,1.724,941,1.889,942,1.501,943,2.141,944,3.499,945,1.724]],["tags/185",[]],["title/186",[946,5.064]],["content/186",[0,0.129,4,0.462,5,0.473,6,0.619,12,0.724,14,1.368,43,1.85,55,1.85,62,1.316,63,1.11,83,0.651,93,1.172,118,1.407,128,0.909,134,1.85,143,3.431,144,3.243,152,0.96,159,1.146,164,1.763,166,0.545,168,1.764,182,0.78,185,1.85,196,1.764,211,1.239,227,1.993,235,1.015,238,1.897,265,1.146,278,1.736,309,3.142,310,1.897,318,1.559,342,1.488,362,1.268,405,1.705,407,1.488,409,1.641,413,0.707,420,1.736,437,2.758,448,2.607,461,3.167,483,1.641,492,1.641,544,3.657,565,1.736,600,1.316,603,1.488,609,1.368,785,2.185,858,2.607,860,3.889,863,1.993,865,1.993,866,1.85,867,1.425,894,2.607,899,3.167,900,1.993,902,2.185,908,1.993,909,2.185,911,2.185,912,1.736,913,3.471,914,2.185,915,4.031,916,2.185,919,1.559,924,2.185,925,1.85,926,1.993,927,1.85,928,2.185,929,2.939,930,1.993,931,3.431,932,3.909,933,3.657,934,3.657,935,1.993,936,2.185,937,1.993,939,2.185,940,1.993,941,2.185,945,1.993,946,3.471,947,2.475,948,2.475,949,2.475,950,2.475,951,2.475,952,2.475,953,2.475,954,2.475,955,3.471,956,2.475,957,4.894,958,2.475,959,2.475,960,2.475,961,2.475,962,2.475,963,2.475]],["tags/186",[]],["title/187",[6,0.74,93,0.989]],["content/187",[0,0.301,3,2.182,4,1.08,6,1.135,7,1.613,30,3.329,34,3.834,58,2.015,62,3.075,70,4.056,108,2.964,128,2.124,145,2.678,152,2.242,207,3.643,243,2.678,375,3.196,524,3.643,632,4.056,775,5.105,874,4.657,964,5.805]],["tags/187",[]],["title/188",[0,0.207,6,0.627,229,0.964]],["content/188",[0,0.39,4,0.976,6,0.823,7,1.457,58,1.821,75,2.854,93,1.099,108,2.678,129,2.887,166,1.151,199,2.887,229,1.265,243,2.419,267,1.869,347,2.887,351,2.887,398,2.887,423,3.905,428,3.463,445,2.419,468,4.063,487,2.499,670,2.778,672,3.463,750,3.664,802,3.463,867,3.007,872,4.207,965,4.612,966,4.612,967,3.463,968,4.612]],["tags/188",[]],["title/189",[0,0.207,6,0.627,166,0.878]],["content/189",[0,0.324,6,0.981,58,2.17,75,2.63,166,1.372,199,3.441,301,3.311,413,1.779,670,3.311,788,4.655,925,4.655,967,4.128,969,4.128,970,5.497,971,4.367,972,5.497]],["tags/189",[]],["title/190",[7,1.111,267,1.425,973,3.516]],["content/190",[3,2.395,4,1.186,5,1.215,7,1.771,62,3.376,81,3.655,111,3.817,145,2.94,267,2.271,374,4.746,445,2.94,547,5.113,777,5.113,964,5.113]],["tags/190",[]],["title/191",[235,1.929,468,2.827]],["content/191",[0,0.336,4,0.608,5,0.623,6,0.765,7,0.909,12,1.701,41,2.876,83,0.539,93,1.222,118,2.305,129,1.8,150,0.866,158,1.732,164,0.887,166,0.718,196,1.461,201,1.833,211,1.026,235,1.993,238,1.263,266,2.052,267,2.079,304,2.435,309,2.984,345,3.303,391,2.623,497,2.623,516,1.875,527,2.435,528,5.131,529,2.876,530,5.131,565,2.285,600,3.09,609,1.8,667,2.052,784,2.052,858,3.222,860,3.706,866,4.345,867,2.797,926,3.914,927,3.633,929,2.435,930,2.623,931,3.408,932,4.077,933,2.435,934,2.435,945,2.623,974,2.435,975,3.258,976,4.861,977,2.435,978,4.861,979,4.861,980,4.861,981,3.258,982,3.258,983,3.258,984,3.258,985,3.258,986,3.258,987,3.258,988,2.876,989,3.258]],["tags/191",[]],["title/192",[309,2.177,799,3.298]],["content/192",[0,0.177,2,1.058,3,0.779,4,0.386,5,0.828,7,0.576,34,1.369,36,1.098,37,1.022,43,1.544,46,0.956,63,1.524,68,0.739,81,1.189,83,0.716,93,1.054,111,1.242,118,2.572,128,1.841,135,1.544,137,1.448,158,1.098,164,1.856,165,1.058,168,0.927,170,1.955,196,1.524,211,1.579,220,2.839,235,0.847,238,0.801,243,2.321,252,0.847,305,1.448,308,2.948,309,2.916,310,1.317,343,1.663,385,1.448,405,2.195,406,1.544,407,3.331,413,1.583,423,1.544,428,1.369,437,2.382,454,1.823,507,1.544,513,1.663,524,1.301,535,1.544,568,1.823,586,1.448,600,1.098,603,3.014,609,1.141,685,1.369,750,1.448,786,4.179,799,2.382,820,1.823,850,1.663,858,1.369,860,2.569,882,1.823,893,1.823,898,1.663,899,1.663,901,2.999,915,2.252,920,1.823,921,1.823,927,1.544,929,1.544,931,1.448,932,3.035,933,1.544,934,1.544,935,1.663,937,1.663,988,1.823,990,2.066,991,2.066,992,2.066,993,2.066,994,2.066,995,2.066,996,2.066,997,2.066,998,2.066,999,2.066,1000,2.066,1001,2.066,1002,2.066,1003,2.066,1004,2.066,1005,1.823,1006,2.066,1007,2.066,1008,2.726,1009,3.398,1010,2.066,1011,2.066,1012,2.066,1013,4.454,1014,3.398,1015,5.014,1016,3.398,1017,3.398,1018,3.398,1019,3.398,1020,3.398,1021,3.398,1022,3.398,1023,3.398,1024,3.398,1025,2.066,1026,2.066,1027,2.066,1028,2.066]],["tags/192",[]],["title/193",[150,0.919,201,1.303,266,2.177,281,0.987]],["content/193",[0,0.27,3,1.955,5,0.991,6,1.059,13,3.436,28,3.326,34,3.436,36,2.756,63,2.325,117,2.564,124,2.4,150,1.788,170,2.983,191,2.189,195,2.756,196,2.325,201,2.815,229,1.255,266,3.265,267,1.854,345,2.656,368,2.864,600,2.756,642,3.265,710,3.874,847,4.575,848,4.575,849,4.174,892,4.575,1029,4.575,1030,4.575,1031,4.575]],["tags/193",[]],["title/194",[199,2.598,267,1.682]],["content/194",[58,2.191,93,1.322,152,2.438,166,1.386,199,4.193,235,2.579,267,2.714,281,1.796,456,5.063,576,5.55,670,3.343,967,4.168,1032,6.289]],["tags/194",[]],["title/195",[0,0.207,166,0.878,310,1.544]],["content/195",[4,0.829,5,1.16,6,0.699,10,1.931,12,1.299,30,2.555,46,2.055,52,2.123,83,1.143,107,3.318,108,2.275,158,2.36,166,1.522,229,1.074,263,2.453,267,1.588,301,2.36,310,1.721,386,2.36,445,2.055,471,3.318,472,3.918,490,2.453,540,2.668,670,3.224,691,3.113,700,3.113,710,3.318,817,3.318,873,3.113,876,3.574,894,2.942,915,5.15,942,3.113,971,3.113,1033,3.918,1034,3.318,1035,6.858,1036,3.318,1037,4.439,1038,4.439,1039,4.439,1040,4.439,1041,4.439]],["tags/195",[]],["title/196",[152,1.823,281,1.343]],["content/196",[0,0.304,5,1.116,93,1.658,108,2.99,117,3.586,152,2.81,156,1.014,164,1.589,166,1.597,257,3.868,267,2.087,281,1.667,309,2.702,540,3.508,800,5.151,801,4.362,932,4.093,1042,4.093]],["tags/196",[]],["title/197",[166,1.036,182,1.481]],["content/197",[0,0.35,6,0.816,42,1.854,83,1.112,120,2.405,124,2.4,150,1.379,156,0.901,164,1.412,166,1.142,173,4.174,182,2.487,195,2.756,196,2.325,203,2.756,212,3.635,224,2.756,257,3.436,281,1.921,403,2.656,405,1.806,413,1.481,516,2.983,666,4.174,667,3.265,861,3.874,977,5.025,1042,3.635,1043,4.174]],["tags/197",[]],["title/198",[93,0.989,395,2.706]],["content/198",[5,0.591,29,2.165,46,1.429,50,1.527,63,1.385,83,0.931,86,1.104,93,0.649,118,1.67,128,1.134,135,2.308,143,4.725,144,2.046,164,2.004,168,2.094,263,2.579,264,1.945,274,1.777,277,2.165,289,2.308,310,2.182,311,2.486,362,2.392,366,1.856,386,1.641,405,2.186,413,1.608,429,2.308,540,1.856,636,2.486,670,2.482,700,2.165,743,1.856,812,2.308,858,2.046,860,3.215,870,2.165,912,3.947,919,1.945,942,3.274,971,3.947,1008,3.952,1013,2.308,1034,2.308,1036,2.308,1044,2.725,1045,4.669,1046,3.088,1047,3.088,1048,3.088,1049,3.088,1050,3.088,1051,3.088,1052,2.486,1053,3.088,1054,4.968,1055,4.968,1056,2.725,1057,2.486,1058,1.945,1059,2.486,1060,4.159,1061,3.274,1062,2.725,1063,2.725,1064,3.759,1065,2.486,1066,2.725,1067,2.725,1068,2.486,1069,4.12,1070,2.725,1071,2.725,1072,2.725,1073,2.725,1074,2.725]],["tags/198",[]],["title/199",[63,2.574]],["content/199",[4,1.273,118,2.438,1075,5.095,1076,4.098,1077,6.016,1078,4.098,1079,6.016]],["tags/199",[]],["title/200",[4,0.645,118,1.236,1075,2.583,1076,2.077]],["content/200",[1077,6.28,1078,4.277,1079,6.28]],["tags/200",[]],["title/201",[4,0.744,1075,2.977,1076,2.395]],["content/201",[0,0.245,4,0.877,6,1.119,62,2.496,63,2.106,125,2.246,131,2.595,362,2.406,398,2.595,403,3.228,409,3.113,511,3.781,622,2.496,679,4.145,692,2.958,768,4.145,786,3.293,894,3.113,919,3.968,955,4.145,964,3.781,1005,5.56,1058,3.968,1075,5.313,1076,4.903,1078,3.787,1080,4.696,1081,3.51,1082,4.696,1083,6.3,1084,6.3,1085,4.696,1086,4.145,1087,4.696]],["tags/201",[]],["title/202",[1088,5.738]],["content/202",[3,1.91,4,0.945,17,1.379,22,1.81,38,2.504,42,1.81,83,1.095,92,3.189,93,1.392,145,2.344,156,0.88,203,2.691,208,3.043,243,3.065,319,3.189,352,3.784,378,3.043,403,3.392,413,1.446,535,3.784,562,3.355,696,3.55,786,3.55,1076,4.704,1089,5.063,1090,5.063,1091,5.843,1092,6.621,1093,4.468,1094,5.063,1095,5.063]],["tags/202",[]],["title/203",[1096,4.288]],["content/203",[0,0.318,3,2.305,4,1.141,5,1.169,34,4.05,58,2.804,75,3.149,120,2.185,128,2.244,191,2.58,490,3.376,524,3.849,874,6.005,1031,5.393]],["tags/203",[]],["title/204",[0,0.18,6,0.544,108,1.771,1078,2.077]],["content/204",[]],["tags/204",[]],["title/205",[6,0.74,697,2.962]],["content/205",[0,0.296,3,2.144,6,1.227,265,2.631,301,3.021,345,3.992,697,3.58,969,3.767,977,4.247,1060,3.767,1078,4.683,1097,5.683,1098,5.016,1099,5.683,1100,7.792,1101,7.13,1102,5.683]],["tags/205",[]],["title/206",[0,0.207,6,0.627,229,0.964]],["content/206",[0,0.39,4,0.976,6,0.823,7,1.457,58,1.821,75,2.854,93,1.099,108,2.678,129,2.887,166,1.151,199,2.887,229,1.265,243,2.419,267,1.869,347,2.887,351,2.887,398,2.887,423,3.905,428,3.463,445,2.419,468,4.063,487,2.499,670,2.778,672,3.463,750,3.664,802,3.463,867,3.007,872,4.207,965,4.612,966,4.612,967,3.463,968,4.612]],["tags/206",[]],["title/207",[0,0.207,6,0.627,166,0.878]],["content/207",[0,0.331,6,1.202,58,2.213,166,1.399,199,3.508,413,1.814,670,3.376,788,4.746,925,4.746,967,4.209,970,5.604,971,4.453,972,5.604]],["tags/207",[]],["title/208",[150,0.919,201,1.303,266,2.177,281,0.987]],["content/208",[0,0.389,3,2.119,4,0.743,5,1.075,6,1.176,12,1.164,13,2.636,17,1.083,83,0.658,93,1.181,117,1.967,124,1.841,150,1.058,155,2.505,156,0.691,164,1.083,191,1.679,195,2.114,196,1.784,201,2.457,211,2.051,216,1.679,229,1.36,235,2.304,266,2.505,271,3.724,284,2.972,345,2.879,351,2.197,378,2.39,390,3.202,395,2.289,405,1.957,409,2.636,413,1.605,516,2.289,525,3.202,527,4.199,541,2.636,545,3.202,600,2.114,602,3.51,778,3.939,801,2.972,867,2.289,889,3.51,1029,3.51,1059,3.202,1078,2.39,1103,3.202,1104,3.977,1105,3.977]],["tags/208",[]],["title/209",[152,1.823,281,1.343]],["content/209",[0,0.331,6,1.127,83,0.788,120,1.704,152,1.847,156,0.828,166,1.805,191,2.012,195,2.533,196,2.137,211,1.501,212,3.341,233,2.742,252,1.954,257,3.158,259,3.561,281,1.361,309,2.206,310,1.847,336,2.742,363,3.561,364,3.341,403,2.442,622,3.381,632,3.341,700,3.341,942,3.341,1033,4.205,1034,3.561,1036,3.561,1042,3.341,1052,3.837,1106,4.205,1107,4.205,1108,4.765,1109,4.765,1110,4.765,1111,4.205,1112,4.765]],["tags/209",[]],["title/210",[6,0.74,1078,2.827]],["content/210",[0,0.219,6,1.242,83,1.111,86,1.505,93,1.229,121,2.651,125,2.013,152,1.632,156,0.731,164,1.976,166,1.48,199,2.325,211,1.325,217,2.157,220,2.157,235,1.726,265,1.948,272,2.651,281,1.202,282,2.237,308,2.082,324,3.146,362,2.157,386,2.237,395,3.865,405,2.34,407,2.53,413,1.202,415,3.146,442,3.146,446,3.715,453,2.951,492,2.79,540,2.53,562,2.79,603,2.53,605,3.715,666,3.389,670,2.237,931,4.099,967,2.79,1058,2.651,1076,2.53,1078,2.53,1113,4.209,1114,5.846,1115,3.715]],["tags/210",[]],["title/211",[182,1.088,511,2.782,1091,3.05,1116,3.456]],["content/211",[0,0.26,4,0.931,6,1.153,8,3.304,108,2.554,123,2.996,155,3.14,156,1.351,159,3.034,166,1.614,182,2.306,206,4.399,211,1.57,261,3.14,281,1.424,352,3.725,354,2.869,443,3.725,445,2.308,561,4.014,624,4.014,704,4.014,763,4.399,788,3.725,974,3.725,1076,2.996,1081,3.725,1093,4.399,1103,4.014,1117,4.985,1118,4.985,1119,4.985]],["tags/211",[]],["title/212",[156,0.817,166,1.036]],["content/212",[0,0.311,3,1.641,4,0.812,6,0.942,22,1.556,37,2.152,38,2.152,83,0.989,96,2.883,120,2.139,124,2.768,129,2.403,146,3.839,150,1.157,156,0.756,164,1.185,166,1.506,182,2.43,195,2.312,196,1.951,211,1.37,212,3.05,224,2.312,257,2.883,281,1.708,309,2.014,335,3.064,373,2.883,405,2.084,414,2.615,416,2.615,442,3.251,453,3.05,492,2.883,516,2.503,621,3.502,667,2.74,860,2.229,861,3.251,977,4.47,1008,2.74,1042,3.05,1043,4.815,1081,3.251,1111,3.839]],["tags/212",[]],["title/213",[281,0.987,718,3.05,720,2.583,1043,2.782]],["content/213",[50,2.995,107,4.525,108,3.102,124,2.803,150,1.61,166,1.334,182,1.906,189,4.245,211,1.906,281,1.729,373,4.013,445,2.803,667,3.813,719,4.525,720,4.525,861,4.525,1081,4.525,1120,6.054,1121,6.054]],["tags/213",[]],["title/214",[4,0.645,93,0.727,156,0.6,310,1.34]],["content/214",[46,2.113,50,2.258,83,1.022,86,1.632,93,0.96,118,1.632,143,3.2,144,3.025,164,1.683,166,1.006,168,2.047,211,1.437,252,1.872,263,2.522,289,3.411,310,2.396,335,2.339,362,2.339,386,2.426,405,2.153,413,2.001,622,2.426,812,3.411,919,3.892,942,4.333,971,3.2,1008,4.413,1034,3.411,1052,3.675,1058,3.892,1064,3.675,1069,5.454,1070,4.028,1071,4.028,1072,4.028,1073,4.028,1074,4.028,1122,4.564,1123,4.564,1124,4.564,1125,4.564,1126,4.564]],["tags/214",[]],["title/215",[164,0.831,281,0.872,430,1.563,486,2.693,1061,2.139]],["content/215",[5,0.826,29,3.03,46,2,63,1.938,83,0.715,118,1.545,128,1.587,135,3.229,143,4.775,164,2.096,168,1.938,263,2.387,264,2.722,274,2.487,277,3.03,310,1.675,362,2.214,366,2.597,405,2.074,540,2.597,636,3.479,700,3.03,743,2.597,860,3.49,870,3.03,912,4.775,919,2.722,1008,2.722,1013,3.229,1036,3.229,1054,5.254,1055,5.254,1056,3.814,1057,3.479,1058,2.722,1059,3.479,1060,4.864,1061,4.174,1062,3.814,1063,3.814,1064,3.479,1065,3.479,1066,3.814,1067,3.814,1068,3.479]],["tags/215",[]],["title/216",[211,1.088,281,0.987,413,0.987,1061,2.423]],["content/216",[5,0.976,111,3.067,118,3.084,150,2.087,164,1.389,249,3.067,281,1.458,354,2.936,375,2.819,600,2.712,692,4.192,730,4.503,743,3.067,912,3.578,919,4.665,1057,4.108,1058,3.214,1060,3.382,1061,3.578,1068,4.108,1103,4.108,1127,5.102,1128,5.102,1129,5.102,1130,5.102,1131,5.102]],["tags/216",[]],["title/217",[281,1.343,430,2.41]],["content/217",[0,0.352,6,1.149,50,2.109,81,2.454,86,1.525,93,0.897,107,3.187,152,2.287,155,2.686,164,2.158,165,2.185,166,1.3,168,3.033,252,1.749,257,2.826,265,3.131,281,1.932,380,2.826,401,2.826,404,4.136,405,2.055,410,3.433,413,1.218,426,3.187,427,3.259,430,3.739,448,3.91,540,4.065,640,3.763,843,3.433,1008,2.686,1042,2.99,1044,3.763,1132,5.206,1133,4.264,1134,3.763]],["tags/217",[]],["title/218",[430,2.041,450,2.293,1135,3.516]],["content/218",[0,0.219,2,2.157,5,0.805,82,3.389,83,1.111,152,1.632,156,0.731,164,1.829,165,2.157,166,0.927,235,2.397,281,1.67,284,3.146,310,1.632,362,2.157,405,1.466,409,2.79,413,1.202,427,3.23,430,3.441,440,6.404,442,3.146,450,3.364,453,2.951,464,3.389,670,3.857,786,2.951,891,6.404,897,3.146,1008,2.651,1013,3.146,1058,2.651,1060,3.874,1065,3.389,1076,2.53,1086,3.715,1132,3.715,1134,3.715,1135,5.159,1136,4.209,1137,5.846,1138,4.209,1139,4.209,1140,4.209]],["tags/218",[]],["title/219",[116,4.15,117,2.326]],["content/219",[0,0.341,58,2.279,75,2.762,118,2.779,120,2.34,301,3.478,524,4.121,697,4.121,969,4.336,1096,4.889]],["tags/219",[]],["title/220",[75,1.986,118,1.682]],["content/220",[0,0.363,120,2.49,301,3.702,697,4.386,969,4.615]],["tags/220",[]],["title/221",[58,1.388,118,1.425,524,2.509]],["content/221",[1096,5.438]],["tags/221",[]],["title/222",[58,1.639,191,1.986]],["content/222",[]],["tags/222",[]],["title/223",[1096,4.288]],["content/223",[13,4.168,32,3.008,58,2.191,75,2.655,120,2.249,129,3.474,191,2.655,445,2.911,504,4.7,612,4.7,969,4.168,1141,7.589,1142,6.289,1143,4.41]],["tags/223",[]],["title/224",[31,2.077,32,1.653,83,0.572,973,3.05]],["content/224",[17,1.431,28,1.792,30,2.084,31,4.515,32,2.957,46,1.677,58,1.262,78,1.792,87,3.287,118,2.939,120,1.295,124,2.432,125,2.957,128,1.929,191,1.529,210,1.732,223,2.4,243,1.677,259,2.707,366,2.177,386,1.925,430,1.856,445,1.677,455,5.986,586,3.684,600,2.793,660,2.707,808,5.069,860,3.475,940,4.23,1106,3.196,1107,3.196,1143,5.267,1144,3.622,1145,3.622,1146,6.183,1147,6.183,1148,5.254,1149,6.183,1150,3.196,1151,3.622,1152,3.622,1153,3.622,1154,3.622]],["tags/224",[]],["title/225",[191,1.682,267,1.425,685,2.64]],["content/225",[28,2.357,30,2.742,31,2.864,32,2.279,70,3.341,83,1.052,118,2.561,124,2.206,128,2.336,152,1.847,191,2.686,267,2.275,278,3.341,427,2.633,622,2.533,657,3.837,685,4.746,692,3.001,754,3.837,860,3.26,974,3.561,1143,3.341,1155,7.161,1156,4.765,1157,4.765,1158,4.765,1159,4.765,1160,4.765,1161,4.765,1162,4.765,1163,4.765,1164,4.765,1165,4.765,1166,4.765,1167,4.765,1168,3.837,1169,4.765]],["tags/225",[]],["title/226",[32,1.905,58,1.388,191,1.682]],["content/226",[7,0.841,16,2.123,30,1.736,32,3.492,46,1.396,58,2.16,83,0.499,93,0.634,118,3.033,129,2.534,130,3.692,181,2.254,185,3.427,191,1.936,201,1.138,217,1.545,229,0.73,267,1.984,342,1.813,362,1.545,429,2.254,430,1.545,487,3.598,490,1.666,505,2.428,580,3.692,586,2.115,600,2.438,622,1.603,670,2.438,685,3.678,692,1.9,754,2.428,860,3.599,1115,4.047,1143,3.891,1150,2.662,1168,4.468,1170,3.016,1171,4.897,1172,3.016,1173,4.586,1174,4.586,1175,4.586,1176,4.586,1177,3.016,1178,3.016,1179,3.016,1180,4.586,1181,3.016,1182,3.016,1183,3.016,1184,3.016,1185,3.016,1186,3.016,1187,4.586,1188,4.586,1189,4.586,1190,3.016,1191,4.586,1192,3.016,1193,3.016]],["tags/226",[]],["title/227",[1194,5.064]],["content/227",[0,0.25,3,1.811,32,3.057,56,2.088,58,2.227,84,3.024,108,2.46,118,2.57,191,2.699,267,2.854,427,2.652,450,2.763,487,2.296,505,3.865,632,3.366,685,5.29,687,4.237,860,3.276,974,3.588,1143,4.483,1168,5.147,1171,4.237,1194,4.237,1195,4.801,1196,4.801,1197,4.801,1198,7.981]],["tags/227",[]],["title/228",[75,2.423]],["content/228",[0,0.432,75,3.095,120,2.622,301,3.159,697,3.744,969,3.939,1060,3.939,1098,5.245,1199,5.943,1200,5.943,1201,5.943,1202,5.943,1203,5.943,1204,5.943,1205,5.943,1206,5.943]],["tags/228",[]],["title/229",[642,2.962,1207,4.15]],["content/229",[0,0.301,11,4.056,17,1.575,28,3.566,72,3.329,111,3.477,126,5.105,223,3.834,300,4.323,314,4.323,335,2.964,408,5.055,461,4.657,462,4.657,547,4.657,642,3.643,757,5.105,790,5.105,1207,5.105,1208,5.785,1209,5.785,1210,5.785]],["tags/229",[]],["title/230",[622,3.05]],["content/230",[0,0.307,4,1.1,5,1.126,31,3.54,32,3.487,47,3.131,56,2.562,319,4.592,490,4.028,504,4.401,622,3.875,735,5.198,753,5.198,777,4.742,908,4.742,1211,5.89,1212,5.89,1213,5.89]],["tags/230",[]],["title/231",[7,1.312,87,2.5]],["content/231",[4,0.976,5,1.433,6,0.823,10,2.273,28,3.344,32,2.499,70,3.664,83,0.865,87,2.778,199,2.887,218,3.905,232,2.585,236,3.89,267,1.869,452,3.141,490,3.734,609,2.887,642,4.719,691,3.664,726,4.207,869,3.905,915,4.48,1035,5.965,1214,6.759,1215,5.226,1216,5.226]],["tags/231",[]],["title/232",[150,1.251,229,1.138]],["content/232",[0,0.165,3,1.193,5,1.215,6,0.498,12,0.926,22,1.131,28,2.825,68,1.7,72,1.82,84,1.992,86,1.131,93,1.335,117,1.565,139,1.901,142,2.791,150,1.689,153,1.901,155,2.994,201,1.193,208,1.901,210,2.274,215,1.992,223,2.096,232,1.565,242,2.791,243,1.464,252,2.342,261,2.994,295,1.82,305,2.218,309,2.201,310,1.843,336,1.82,338,2.791,351,1.747,366,2.858,368,2.627,387,2.364,405,2.213,413,1.814,438,2.791,451,2.791,452,1.901,470,2.791,490,1.747,507,2.364,538,2.547,603,3.433,604,2.547,609,2.627,610,2.096,642,1.992,674,2.791,691,2.218,696,2.218,706,2.791,710,3.553,719,2.364,726,2.547,807,2.791,827,2.547,830,2.547,849,4.599,850,2.547,851,4.196,894,2.096,896,2.791,897,2.364,1030,2.791,1217,3.163,1218,4.754,1219,3.163,1220,6.352,1221,3.163,1222,3.163,1223,2.791,1224,3.163,1225,3.163,1226,3.163]],["tags/232",[]],["title/233",[68,1.682,743,2.827]],["content/233",[28,3.111,120,2.714,319,3.961,428,4.168,622,4.034,642,3.961,743,3.78,876,5.063,883,5.55,915,4.168,1223,5.55,1227,6.289,1228,6.289]],["tags/233",[]]],"invertedIndex":[["",{"_index":118,"title":{"123":{},"126":{},"127":{},"200":{},"220":{},"221":{}},"content":{"122":{},"125":{},"156":{},"176":{},"185":{},"186":{},"191":{},"192":{},"198":{},"199":{},"214":{},"215":{},"216":{},"219":{},"224":{},"225":{},"226":{},"227":{}},"tags":{}}],["1",{"_index":185,"title":{},"content":{"129":{},"185":{},"186":{},"226":{}},"tags":{}}],["1.29",{"_index":1172,"title":{},"content":{"226":{}},"tags":{}}],["127.0.0.0/8",{"_index":947,"title":{},"content":{"186":{}},"tags":{}}],["127.0.0.2:4001",{"_index":1003,"title":{},"content":{"192":{}},"tags":{}}],["2",{"_index":77,"title":{},"content":{"119":{},"131":{},"153":{}},"tags":{}}],["203.0.113.34",{"_index":1068,"title":{},"content":{"198":{},"215":{},"216":{}},"tags":{}}],["3",{"_index":299,"title":{},"content":{"132":{}},"tags":{}}],["32049705",{"_index":1186,"title":{},"content":{"226":{}},"tags":{}}],["32238657",{"_index":1192,"title":{},"content":{"226":{}},"tags":{}}],["3rd",{"_index":923,"title":{},"content":{"185":{}},"tags":{}}],["45",{"_index":1193,"title":{},"content":{"226":{}},"tags":{}}],["60",{"_index":1066,"title":{},"content":{"198":{},"215":{}},"tags":{}}],["7890",{"_index":922,"title":{},"content":{"185":{}},"tags":{}}],["8001",{"_index":996,"title":{},"content":{"192":{}},"tags":{}}],["8080",{"_index":920,"title":{},"content":{"185":{},"192":{}},"tags":{}}],["9334",{"_index":163,"title":{},"content":{"125":{},"126":{},"128":{},"129":{},"131":{},"132":{}},"tags":{}}],["99dd77cbd7fe2c4e1f29511014c14054a21a376f7d58a48d50e9e036f4522f6b",{"_index":1131,"title":{},"content":{"216":{}},"tags":{}}],["9m47",{"_index":1190,"title":{},"content":{"226":{}},"tags":{}}],["_",{"_index":1015,"title":{},"content":{"192":{}},"tags":{}}],["abcdef",{"_index":868,"title":{},"content":{"176":{}},"tags":{}}],["abov",{"_index":657,"title":{},"content":{"159":{},"182":{},"225":{}},"tags":{}}],["absenc",{"_index":1222,"title":{},"content":{"232":{}},"tags":{}}],["accept",{"_index":485,"title":{},"content":{"151":{},"161":{}},"tags":{}}],["access",{"_index":46,"title":{},"content":{"119":{},"142":{},"155":{},"157":{},"158":{},"159":{},"161":{},"162":{},"192":{},"195":{},"198":{},"214":{},"215":{},"224":{},"226":{}},"tags":{}}],["accommod",{"_index":522,"title":{},"content":{"153":{}},"tags":{}}],["accompani",{"_index":599,"title":{},"content":{"156":{}},"tags":{}}],["account",{"_index":1142,"title":{},"content":{"223":{}},"tags":{}}],["accur",{"_index":388,"title":{},"content":{"141":{}},"tags":{}}],["achiev",{"_index":751,"title":{},"content":{"162":{}},"tags":{}}],["acknowledg",{"_index":729,"title":{},"content":{"161":{}},"tags":{}}],["acquir",{"_index":205,"title":{},"content":{"129":{}},"tags":{}}],["act",{"_index":167,"title":{},"content":{"125":{},"127":{},"132":{},"144":{},"156":{},"162":{},"167":{},"170":{}},"tags":{}}],["action",{"_index":114,"title":{},"content":{"121":{},"161":{}},"tags":{}}],["activ",{"_index":462,"title":{},"content":{"149":{},"154":{},"229":{}},"tags":{}}],["actual",{"_index":602,"title":{},"content":{"156":{},"208":{}},"tags":{}}],["ad",{"_index":271,"title":{},"content":{"131":{},"150":{},"153":{},"182":{},"183":{},"208":{}},"tags":{}}],["adapt",{"_index":779,"title":{},"content":{"164":{}},"tags":{}}],["add",{"_index":600,"title":{},"content":{"156":{},"159":{},"185":{},"186":{},"191":{},"192":{},"193":{},"208":{},"216":{},"224":{},"226":{}},"tags":{}}],["addit",{"_index":516,"title":{},"content":{"153":{},"156":{},"162":{},"174":{},"177":{},"191":{},"197":{},"208":{},"212":{}},"tags":{}}],["addition",{"_index":886,"title":{},"content":{"181":{}},"tags":{}}],["address",{"_index":144,"title":{},"content":{"124":{},"136":{},"185":{},"186":{},"198":{},"214":{}},"tags":{}}],["adher",{"_index":148,"title":{},"content":{"124":{},"125":{},"126":{},"128":{},"143":{},"165":{}},"tags":{}}],["admin",{"_index":57,"title":{},"content":{"119":{}},"tags":{}}],["administr",{"_index":59,"title":{},"content":{"119":{},"120":{},"157":{},"159":{}},"tags":{}}],["adopt",{"_index":564,"title":{},"content":{"154":{}},"tags":{}}],["advanc",{"_index":649,"title":{},"content":{"159":{},"162":{}},"tags":{}}],["affect",{"_index":1226,"title":{},"content":{"232":{}},"tags":{}}],["aforement",{"_index":683,"title":{},"content":{"161":{}},"tags":{}}],["afterward",{"_index":1152,"title":{},"content":{"224":{}},"tags":{}}],["ag",{"_index":1184,"title":{},"content":{"226":{}},"tags":{}}],["against",{"_index":355,"title":{},"content":{"136":{},"139":{},"140":{},"146":{},"159":{},"161":{},"171":{}},"tags":{}}],["agent",{"_index":256,"title":{},"content":{"131":{},"135":{},"151":{},"167":{},"171":{},"172":{},"173":{},"175":{},"180":{},"181":{}},"tags":{}}],["agent'",{"_index":836,"title":{},"content":{"173":{}},"tags":{}}],["agentservic",{"_index":814,"title":{},"content":{"171":{},"173":{}},"tags":{}}],["aim",{"_index":459,"title":{},"content":{"149":{},"162":{}},"tags":{}}],["ak",{"_index":32,"title":{"152":{},"224":{},"226":{}},"content":{"118":{},"152":{},"153":{},"170":{},"223":{},"224":{},"225":{},"226":{},"227":{},"230":{},"231":{}},"tags":{}}],["algorithm",{"_index":739,"title":{},"content":{"162":{}},"tags":{}}],["align",{"_index":346,"title":{},"content":{"136":{}},"tags":{}}],["allow",{"_index":125,"title":{},"content":{"124":{},"136":{},"142":{},"143":{},"146":{},"154":{},"155":{},"162":{},"164":{},"167":{},"180":{},"201":{},"210":{},"224":{}},"tags":{}}],["along",{"_index":593,"title":{},"content":{"156":{}},"tags":{}}],["alreadi",{"_index":1103,"title":{},"content":{"208":{},"211":{},"216":{}},"tags":{}}],["altern",{"_index":1055,"title":{},"content":{"198":{},"215":{}},"tags":{}}],["altogeth",{"_index":917,"title":{},"content":{"185":{}},"tags":{}}],["alway",{"_index":43,"title":{},"content":{"119":{},"185":{},"186":{},"192":{}},"tags":{}}],["amd",{"_index":268,"title":{},"content":{"131":{},"139":{},"156":{}},"tags":{}}],["amidst",{"_index":746,"title":{},"content":{"162":{}},"tags":{}}],["analog",{"_index":654,"title":{},"content":{"159":{}},"tags":{}}],["analyt",{"_index":761,"title":{},"content":{"162":{}},"tags":{}}],["annot",{"_index":266,"title":{"193":{},"208":{}},"content":{"131":{},"173":{},"191":{},"193":{},"208":{}},"tags":{}}],["anoth",{"_index":640,"title":{},"content":{"159":{},"217":{}},"tags":{}}],["answer",{"_index":175,"title":{},"content":{"128":{}},"tags":{}}],["anyth",{"_index":664,"title":{},"content":{"160":{}},"tags":{}}],["api",{"_index":336,"title":{},"content":{"135":{},"150":{},"151":{},"157":{},"160":{},"167":{},"182":{},"209":{},"232":{}},"tags":{}}],["apiserv",{"_index":859,"title":{},"content":{"176":{}},"tags":{}}],["apivers",{"_index":863,"title":{},"content":{"176":{},"185":{},"186":{}},"tags":{}}],["app",{"_index":786,"title":{},"content":{"165":{},"192":{},"201":{},"202":{},"218":{}},"tags":{}}],["app'",{"_index":791,"title":{},"content":{"165":{}},"tags":{}}],["appli",{"_index":199,"title":{"194":{}},"content":{"129":{},"173":{},"188":{},"189":{},"194":{},"206":{},"207":{},"210":{},"231":{}},"tags":{}}],["applic",{"_index":220,"title":{"131":{}},"content":{"133":{},"142":{},"153":{},"154":{},"156":{},"157":{},"158":{},"159":{},"162":{},"192":{},"210":{}},"tags":{}}],["apprais",{"_index":200,"title":{"134":{},"136":{}},"content":{"129":{},"131":{},"132":{},"136":{},"139":{}},"tags":{}}],["approach",{"_index":27,"title":{},"content":{"118":{},"142":{},"143":{}},"tags":{}}],["appropri",{"_index":476,"title":{},"content":{"150":{}},"tags":{}}],["approv",{"_index":573,"title":{},"content":{"155":{},"162":{}},"tags":{}}],["apps/v1",{"_index":924,"title":{},"content":{"185":{},"186":{}},"tags":{}}],["architectur",{"_index":131,"title":{"125":{},"129":{}},"content":{"124":{},"125":{},"126":{},"128":{},"129":{},"153":{},"155":{},"201":{}},"tags":{}}],["aren't",{"_index":387,"title":{},"content":{"141":{},"156":{},"161":{},"232":{}},"tags":{}}],["argument",{"_index":828,"title":{},"content":{"172":{},"174":{}},"tags":{}}],["aris",{"_index":1227,"title":{},"content":{"233":{}},"tags":{}}],["around",{"_index":313,"title":{},"content":{"135":{}},"tags":{}}],["artifact",{"_index":718,"title":{"213":{}},"content":{"161":{}},"tags":{}}],["ask",{"_index":357,"title":{"137":{}},"content":{"175":{}},"tags":{}}],["aspect",{"_index":598,"title":{},"content":{"156":{}},"tags":{}}],["assess",{"_index":198,"title":{},"content":{"129":{}},"tags":{}}],["assign",{"_index":188,"title":{},"content":{"129":{}},"tags":{}}],["associ",{"_index":773,"title":{},"content":{"162":{}},"tags":{}}],["assum",{"_index":693,"title":{},"content":{"161":{}},"tags":{}}],["assur",{"_index":402,"title":{},"content":{"143":{},"165":{}},"tags":{}}],["attach",{"_index":853,"title":{},"content":{"175":{}},"tags":{}}],["attack",{"_index":60,"title":{"159":{},"160":{}},"content":{"119":{},"156":{},"158":{},"159":{},"160":{},"161":{}},"tags":{}}],["attacker'",{"_index":665,"title":{},"content":{"160":{}},"tags":{}}],["attempt",{"_index":636,"title":{},"content":{"159":{},"198":{},"215":{}},"tags":{}}],["attest",{"_index":156,"title":{"126":{},"128":{},"129":{},"130":{},"131":{},"137":{},"138":{},"139":{},"140":{},"141":{},"142":{},"212":{},"214":{}},"content":{"125":{},"126":{},"128":{},"129":{},"130":{},"131":{},"132":{},"133":{},"135":{},"136":{},"138":{},"140":{},"141":{},"142":{},"143":{},"144":{},"147":{},"151":{},"153":{},"155":{},"156":{},"157":{},"159":{},"160":{},"161":{},"162":{},"164":{},"165":{},"166":{},"168":{},"175":{},"180":{},"196":{},"197":{},"202":{},"208":{},"209":{},"210":{},"211":{},"212":{},"218":{}},"tags":{}}],["attestation’",{"_index":539,"title":{},"content":{"153":{}},"tags":{}}],["attribut",{"_index":669,"title":{},"content":{"160":{}},"tags":{}}],["audit",{"_index":720,"title":{"213":{}},"content":{"161":{},"162":{},"213":{}},"tags":{}}],["authent",{"_index":308,"title":{"141":{}},"content":{"133":{},"135":{},"138":{},"140":{},"141":{},"153":{},"161":{},"164":{},"166":{},"185":{},"192":{},"210":{}},"tags":{}}],["author",{"_index":165,"title":{"127":{},"144":{}},"content":{"125":{},"127":{},"129":{},"139":{},"144":{},"151":{},"165":{},"192":{},"217":{},"218":{}},"tags":{}}],["automat",{"_index":412,"title":{},"content":{"144":{},"166":{},"167":{},"177":{},"183":{}},"tags":{}}],["avail",{"_index":622,"title":{"230":{}},"content":{"158":{},"160":{},"161":{},"201":{},"209":{},"214":{},"225":{},"226":{},"230":{},"233":{}},"tags":{}}],["aw",{"_index":517,"title":{},"content":{"153":{}},"tags":{}}],["awar",{"_index":892,"title":{},"content":{"182":{},"193":{}},"tags":{}}],["az",{"_index":1143,"title":{},"content":{"223":{},"224":{},"225":{},"226":{},"227":{}},"tags":{}}],["azclusternam",{"_index":1171,"title":{},"content":{"226":{},"227":{}},"tags":{}}],["azclustername=\"contrastdemo",{"_index":1170,"title":{},"content":{"226":{}},"tags":{}}],["azloc",{"_index":1169,"title":{},"content":{"225":{}},"tags":{}}],["azlocation=\"westu",{"_index":1167,"title":{},"content":{"225":{}},"tags":{}}],["azresourcegroup",{"_index":1168,"title":{},"content":{"225":{},"226":{},"227":{}},"tags":{}}],["azresourcegroup=\"contrastdemo",{"_index":1166,"title":{},"content":{"225":{}},"tags":{}}],["azur",{"_index":504,"title":{},"content":{"152":{},"153":{},"223":{},"230":{}},"tags":{}}],["azurelinux",{"_index":1174,"title":{},"content":{"226":{}},"tags":{}}],["b",{"_index":230,"title":{},"content":{"131":{}},"tags":{}}],["backdoor",{"_index":682,"title":{},"content":{"160":{}},"tags":{}}],["backend",{"_index":1005,"title":{},"content":{"192":{},"201":{}},"tags":{}}],["backend#127.0.0.2:4001#backend.default:4001",{"_index":1002,"title":{},"content":{"192":{}},"tags":{}}],["backend.default:4001",{"_index":999,"title":{},"content":{"192":{}},"tags":{}}],["balanc",{"_index":1036,"title":{},"content":{"195":{},"198":{},"209":{},"215":{}},"tags":{}}],["ballot",{"_index":1091,"title":{"211":{}},"content":{"202":{}},"tags":{}}],["bare",{"_index":488,"title":{},"content":{"151":{}},"tags":{}}],["base",{"_index":9,"title":{},"content":{"118":{},"119":{},"131":{},"132":{},"146":{},"150":{},"154":{},"156":{},"162":{},"165":{},"167":{},"183":{}},"tags":{}}],["base64",{"_index":831,"title":{},"content":{"173":{}},"tags":{}}],["basi",{"_index":826,"title":{},"content":{"172":{},"183":{}},"tags":{}}],["be",{"_index":1108,"title":{},"content":{"209":{}},"tags":{}}],["becom",{"_index":601,"title":{},"content":{"156":{}},"tags":{}}],["befor",{"_index":155,"title":{},"content":{"124":{},"162":{},"168":{},"208":{},"211":{},"217":{},"232":{}},"tags":{}}],["begin",{"_index":521,"title":{},"content":{"153":{}},"tags":{}}],["below",{"_index":219,"title":{},"content":{"130":{},"131":{}},"tags":{}}],["benefici",{"_index":558,"title":{},"content":{"154":{},"185":{}},"tags":{}}],["benefit",{"_index":88,"title":{"140":{}},"content":{"120":{},"121":{},"128":{},"140":{},"153":{}},"tags":{}}],["between",{"_index":351,"title":{},"content":{"136":{},"144":{},"155":{},"160":{},"161":{},"165":{},"188":{},"206":{},"208":{},"232":{}},"tags":{}}],["beyond",{"_index":514,"title":{},"content":{"153":{}},"tags":{}}],["bill",{"_index":956,"title":{},"content":{"186":{}},"tags":{}}],["billing#127.137.0.1:8081#bil",{"_index":959,"title":{},"content":{"186":{}},"tags":{}}],["binari",{"_index":690,"title":{},"content":{"161":{},"179":{}},"tags":{}}],["blind",{"_index":847,"title":{},"content":{"174":{},"193":{}},"tags":{}}],["block",{"_index":456,"title":{},"content":{"149":{},"180":{},"194":{}},"tags":{}}],["board",{"_index":1084,"title":{},"content":{"201":{}},"tags":{}}],["bot",{"_index":1086,"title":{},"content":{"201":{},"218":{}},"tags":{}}],["both",{"_index":535,"title":{},"content":{"153":{},"156":{},"192":{},"202":{}},"tags":{}}],["bound",{"_index":307,"title":{},"content":{"133":{},"147":{}},"tags":{}}],["breach",{"_index":749,"title":{},"content":{"162":{}},"tags":{}}],["break",{"_index":647,"title":{},"content":{"159":{}},"tags":{}}],["bring",{"_index":721,"title":{},"content":{"161":{}},"tags":{}}],["browser",{"_index":1126,"title":{},"content":{"214":{}},"tags":{}}],["bug",{"_index":1215,"title":{},"content":{"231":{}},"tags":{}}],["build",{"_index":304,"title":{},"content":{"132":{},"136":{},"149":{},"191":{}},"tags":{}}],["built",{"_index":300,"title":{},"content":{"132":{},"136":{},"141":{},"229":{}},"tags":{}}],["c",{"_index":257,"title":{},"content":{"131":{},"196":{},"197":{},"209":{},"212":{},"217":{}},"tags":{}}],["ca",{"_index":168,"title":{},"content":{"125":{},"127":{},"133":{},"142":{},"144":{},"145":{},"146":{},"147":{},"165":{},"185":{},"186":{},"192":{},"198":{},"214":{},"215":{},"217":{}},"tags":{}}],["ca.pem",{"_index":1008,"title":{},"content":{"192":{},"198":{},"212":{},"214":{},"215":{},"217":{},"218":{}},"tags":{}}],["cacert",{"_index":1013,"title":{},"content":{"192":{},"198":{},"215":{},"218":{}},"tags":{}}],["cacerts.appendcertsfrompem(cacert",{"_index":1018,"title":{},"content":{"192":{}},"tags":{}}],["cafil",{"_index":1071,"title":{},"content":{"198":{},"214":{}},"tags":{}}],["calcul",{"_index":834,"title":{},"content":{"173":{}},"tags":{}}],["call",{"_index":475,"title":{},"content":{"150":{},"151":{},"171":{},"173":{},"178":{}},"tags":{}}],["can't",{"_index":710,"title":{},"content":{"161":{},"193":{},"195":{},"232":{}},"tags":{}}],["capabl",{"_index":483,"title":{},"content":{"150":{},"152":{},"154":{},"162":{},"185":{},"186":{}},"tags":{}}],["care",{"_index":260,"title":{},"content":{"131":{},"169":{}},"tags":{}}],["carri",{"_index":888,"title":{},"content":{"182":{}},"tags":{}}],["cart",{"_index":958,"title":{},"content":{"186":{}},"tags":{}}],["case",{"_index":84,"title":{"120":{}},"content":{"120":{},"147":{},"150":{},"162":{},"227":{},"232":{}},"tags":{}}],["categori",{"_index":686,"title":{},"content":{"161":{}},"tags":{}}],["cc",{"_index":867,"title":{},"content":{"176":{},"178":{},"182":{},"185":{},"186":{},"188":{},"191":{},"206":{},"208":{}},"tags":{}}],["central",{"_index":780,"title":{},"content":{"165":{}},"tags":{}}],["centralindia",{"_index":1156,"title":{},"content":{"225":{}},"tags":{}}],["cert",{"_index":932,"title":{},"content":{"185":{},"186":{},"191":{},"192":{},"196":{}},"tags":{}}],["certain",{"_index":1223,"title":{},"content":{"232":{},"233":{}},"tags":{}}],["certchain.pem",{"_index":1007,"title":{},"content":{"192":{}},"tags":{}}],["certif",{"_index":164,"title":{"127":{},"144":{},"146":{},"147":{},"215":{}},"content":{"125":{},"127":{},"133":{},"142":{},"144":{},"145":{},"146":{},"147":{},"153":{},"161":{},"165":{},"168":{},"170":{},"175":{},"183":{},"185":{},"186":{},"191":{},"192":{},"196":{},"197":{},"198":{},"208":{},"210":{},"212":{},"214":{},"215":{},"216":{},"217":{},"218":{}},"tags":{}}],["certifi",{"_index":360,"title":{},"content":{"138":{}},"tags":{}}],["cfg",{"_index":1022,"title":{},"content":{"192":{}},"tags":{}}],["chain",{"_index":448,"title":{},"content":{"147":{},"155":{},"161":{},"185":{},"186":{},"217":{}},"tags":{}}],["challeng",{"_index":556,"title":{},"content":{"154":{},"160":{}},"tags":{}}],["chang",{"_index":81,"title":{},"content":{"119":{},"140":{},"147":{},"159":{},"160":{},"161":{},"190":{},"192":{},"217":{}},"tags":{}}],["channel",{"_index":621,"title":{},"content":{"158":{},"165":{},"212":{}},"tags":{}}],["chapter",{"_index":882,"title":{},"content":{"180":{},"192":{}},"tags":{}}],["chart",{"_index":529,"title":{},"content":{"153":{},"191":{}},"tags":{}}],["chart_nam",{"_index":982,"title":{},"content":{"191":{}},"tags":{}}],["check",{"_index":366,"title":{},"content":{"139":{},"171":{},"172":{},"174":{},"198":{},"215":{},"224":{},"232":{}},"tags":{}}],["checksum",{"_index":502,"title":{},"content":{"151":{},"172":{},"173":{}},"tags":{}}],["chip",{"_index":317,"title":{},"content":{"135":{}},"tags":{}}],["choos",{"_index":913,"title":{},"content":{"185":{},"186":{}},"tags":{}}],["cidr",{"_index":948,"title":{},"content":{"186":{}},"tags":{}}],["claim",{"_index":286,"title":{},"content":{"132":{}},"tags":{}}],["clariti",{"_index":1012,"title":{},"content":{"192":{}},"tags":{}}],["class",{"_index":778,"title":{},"content":{"164":{},"169":{},"176":{},"182":{},"208":{}},"tags":{}}],["clean",{"_index":1196,"title":{},"content":{"227":{}},"tags":{}}],["cleanup",{"_index":1194,"title":{"227":{}},"content":{"227":{}},"tags":{}}],["clear",{"_index":1210,"title":{},"content":{"229":{}},"tags":{}}],["cli",{"_index":120,"title":{"124":{},"132":{},"164":{}},"content":{"122":{},"123":{},"124":{},"132":{},"133":{},"136":{},"164":{},"166":{},"167":{},"172":{},"175":{},"197":{},"203":{},"209":{},"212":{},"219":{},"220":{},"223":{},"224":{},"228":{},"233":{}},"tags":{}}],["cli'",{"_index":348,"title":{},"content":{"136":{}},"tags":{}}],["client",{"_index":407,"title":{},"content":{"144":{},"159":{},"160":{},"162":{},"185":{},"186":{},"192":{},"210":{}},"tags":{}}],["clientauth",{"_index":1026,"title":{},"content":{"192":{}},"tags":{}}],["clientca",{"_index":1028,"title":{},"content":{"192":{}},"tags":{}}],["cloud",{"_index":56,"title":{"179":{}},"content":{"119":{},"120":{},"140":{},"151":{},"153":{},"154":{},"156":{},"157":{},"159":{},"160":{},"162":{},"169":{},"179":{},"182":{},"227":{},"230":{}},"tags":{}}],["cluster",{"_index":58,"title":{"221":{},"222":{},"226":{}},"content":{"119":{},"120":{},"132":{},"152":{},"153":{},"156":{},"157":{},"164":{},"165":{},"169":{},"187":{},"188":{},"189":{},"194":{},"203":{},"206":{},"207":{},"219":{},"223":{},"224":{},"226":{},"227":{}},"tags":{}}],["cmdline",{"_index":248,"title":{},"content":{"131":{}},"tags":{}}],["cncf",{"_index":457,"title":{},"content":{"149":{}},"tags":{}}],["co",{"_index":65,"title":{},"content":{"119":{},"140":{},"159":{},"162":{}},"tags":{}}],["coco",{"_index":30,"title":{"152":{}},"content":{"118":{},"149":{},"152":{},"187":{},"195":{},"224":{},"225":{},"226":{}},"tags":{}}],["coco'",{"_index":482,"title":{},"content":{"150":{}},"tags":{}}],["code",{"_index":96,"title":{},"content":{"120":{},"136":{},"141":{},"158":{},"161":{},"212":{}},"tags":{}}],["collabor",{"_index":106,"title":{},"content":{"120":{}},"tags":{}}],["collect",{"_index":138,"title":{},"content":{"124":{},"132":{}},"tags":{}}],["combin",{"_index":740,"title":{},"content":{"162":{},"165":{},"172":{}},"tags":{}}],["come",{"_index":61,"title":{},"content":{"119":{}},"tags":{}}],["command",{"_index":124,"title":{"164":{}},"content":{"122":{},"123":{},"124":{},"135":{},"151":{},"172":{},"174":{},"193":{},"197":{},"208":{},"212":{},"213":{},"224":{},"225":{}},"tags":{}}],["commandlin",{"_index":885,"title":{},"content":{"181":{}},"tags":{}}],["common",{"_index":176,"title":{},"content":{"128":{}},"tags":{}}],["commun",{"_index":395,"title":{"198":{}},"content":{"142":{},"151":{},"153":{},"159":{},"165":{},"183":{},"208":{},"210":{}},"tags":{}}],["compani",{"_index":742,"title":{},"content":{"162":{}},"tags":{}}],["compat",{"_index":73,"title":{},"content":{"119":{},"153":{}},"tags":{}}],["complex",{"_index":676,"title":{},"content":{"160":{}},"tags":{}}],["complianc",{"_index":103,"title":{},"content":{"120":{},"154":{},"162":{}},"tags":{}}],["compon",{"_index":216,"title":{"130":{},"156":{},"163":{},"177":{}},"content":{"130":{},"131":{},"135":{},"136":{},"143":{},"153":{},"156":{},"157":{},"161":{},"162":{},"163":{},"177":{},"180":{},"208":{}},"tags":{}}],["compos",{"_index":774,"title":{},"content":{"163":{}},"tags":{}}],["composit",{"_index":292,"title":{},"content":{"132":{}},"tags":{}}],["comprehens",{"_index":321,"title":{},"content":{"135":{},"143":{}},"tags":{}}],["compris",{"_index":970,"title":{},"content":{"189":{},"207":{}},"tags":{}}],["compromis",{"_index":380,"title":{},"content":{"140":{},"153":{},"155":{},"156":{},"159":{},"217":{}},"tags":{}}],["comput",{"_index":38,"title":{"155":{}},"content":{"118":{},"119":{},"120":{},"138":{},"149":{},"150":{},"155":{},"156":{},"158":{},"175":{},"202":{},"212":{}},"tags":{}}],["concept",{"_index":110,"title":{},"content":{"121":{},"153":{}},"tags":{}}],["conceptu",{"_index":186,"title":{},"content":{"129":{}},"tags":{}}],["concern",{"_index":748,"title":{},"content":{"162":{}},"tags":{}}],["concis",{"_index":533,"title":{},"content":{"153":{},"156":{},"165":{}},"tags":{}}],["concret",{"_index":684,"title":{},"content":{"161":{}},"tags":{}}],["confidenti",{"_index":4,"title":{"149":{},"155":{},"200":{},"201":{},"214":{}},"content":{"118":{},"120":{},"121":{},"131":{},"132":{},"138":{},"149":{},"150":{},"151":{},"153":{},"154":{},"155":{},"156":{},"157":{},"158":{},"159":{},"160":{},"161":{},"162":{},"163":{},"165":{},"166":{},"167":{},"170":{},"171":{},"173":{},"175":{},"176":{},"179":{},"186":{},"187":{},"188":{},"190":{},"191":{},"192":{},"195":{},"199":{},"201":{},"202":{},"203":{},"206":{},"208":{},"211":{},"212":{},"230":{},"231":{}},"tags":{}}],["config",{"_index":934,"title":{},"content":{"185":{},"186":{},"191":{},"192":{}},"tags":{}}],["config/certchain.pem",{"_index":1020,"title":{},"content":{"192":{}},"tags":{}}],["config/key.pem",{"_index":1021,"title":{},"content":{"192":{}},"tags":{}}],["config/mesh",{"_index":1017,"title":{},"content":{"192":{}},"tags":{}}],["configmap",{"_index":827,"title":{},"content":{"172":{},"174":{},"232":{}},"tags":{}}],["configur",{"_index":211,"title":{"184":{},"216":{}},"content":{"129":{},"131":{},"132":{},"139":{},"146":{},"151":{},"153":{},"155":{},"156":{},"161":{},"164":{},"165":{},"166":{},"170":{},"177":{},"183":{},"184":{},"186":{},"191":{},"192":{},"208":{},"209":{},"210":{},"211":{},"212":{},"213":{},"214":{}},"tags":{}}],["confin",{"_index":766,"title":{},"content":{"162":{}},"tags":{}}],["confirm",{"_index":361,"title":{},"content":{"138":{},"140":{}},"tags":{}}],["connect",{"_index":310,"title":{"195":{},"214":{}},"content":{"133":{},"142":{},"144":{},"146":{},"153":{},"159":{},"160":{},"161":{},"183":{},"185":{},"186":{},"192":{},"195":{},"198":{},"209":{},"214":{},"215":{},"218":{},"232":{}},"tags":{}}],["consequ",{"_index":438,"title":{},"content":{"146":{},"232":{}},"tags":{}}],["consid",{"_index":1089,"title":{},"content":{"202":{}},"tags":{}}],["consist",{"_index":398,"title":{},"content":{"143":{},"166":{},"169":{},"171":{},"177":{},"180":{},"181":{},"188":{},"201":{},"206":{}},"tags":{}}],["constitut",{"_index":829,"title":{},"content":{"172":{}},"tags":{}}],["constrain",{"_index":641,"title":{},"content":{"159":{}},"tags":{}}],["contain",{"_index":5,"title":{"149":{},"151":{}},"content":{"118":{},"120":{},"121":{},"131":{},"132":{},"135":{},"145":{},"146":{},"147":{},"149":{},"150":{},"151":{},"153":{},"156":{},"157":{},"159":{},"160":{},"161":{},"163":{},"165":{},"167":{},"168":{},"170":{},"172":{},"174":{},"175":{},"176":{},"180":{},"181":{},"183":{},"184":{},"185":{},"186":{},"190":{},"191":{},"192":{},"193":{},"195":{},"196":{},"198":{},"203":{},"208":{},"215":{},"216":{},"218":{},"230":{},"231":{},"232":{}},"tags":{}}],["container'",{"_index":254,"title":{},"content":{"131":{},"161":{},"174":{}},"tags":{}}],["containerd",{"_index":473,"title":{"178":{}},"content":{"150":{},"169":{},"175":{},"176":{},"178":{},"179":{},"180":{},"182":{}},"tags":{}}],["containerport",{"_index":944,"title":{},"content":{"185":{}},"tags":{}}],["containers/issues/1693",{"_index":1041,"title":{},"content":{"195":{}},"tags":{}}],["containers/kata",{"_index":1040,"title":{},"content":{"195":{}},"tags":{}}],["containerservic",{"_index":1154,"title":{},"content":{"224":{}},"tags":{}}],["contamin",{"_index":572,"title":{},"content":{"155":{}},"tags":{}}],["content",{"_index":237,"title":{},"content":{"131":{},"159":{},"181":{}},"tags":{}}],["context",{"_index":590,"title":{},"content":{"156":{}},"tags":{}}],["contractor",{"_index":629,"title":{},"content":{"159":{}},"tags":{}}],["contrast",{"_index":0,"title":{"118":{},"128":{},"137":{},"138":{},"139":{},"154":{},"156":{},"157":{},"169":{},"176":{},"188":{},"189":{},"195":{},"204":{},"206":{},"207":{}},"content":{"118":{},"119":{},"120":{},"121":{},"122":{},"123":{},"124":{},"125":{},"126":{},"128":{},"129":{},"130":{},"131":{},"132":{},"133":{},"135":{},"136":{},"138":{},"139":{},"141":{},"143":{},"149":{},"152":{},"153":{},"154":{},"155":{},"156":{},"157":{},"158":{},"159":{},"161":{},"162":{},"163":{},"164":{},"165":{},"166":{},"167":{},"168":{},"169":{},"170":{},"172":{},"175":{},"176":{},"178":{},"180":{},"182":{},"183":{},"185":{},"186":{},"187":{},"188":{},"189":{},"191":{},"192":{},"193":{},"196":{},"197":{},"201":{},"203":{},"205":{},"206":{},"207":{},"208":{},"209":{},"210":{},"211":{},"212":{},"217":{},"218":{},"219":{},"220":{},"227":{},"228":{},"229":{},"230":{},"232":{}},"tags":{}}],["contrast'",{"_index":172,"title":{"130":{},"162":{}},"content":{"128":{},"131":{},"133":{},"141":{},"142":{},"143":{},"144":{},"155":{},"161":{}},"tags":{}}],["control",{"_index":587,"title":{},"content":{"156":{},"158":{},"159":{},"160":{},"161":{}},"tags":{}}],["convers",{"_index":962,"title":{},"content":{"186":{}},"tags":{}}],["convey",{"_index":296,"title":{},"content":{"132":{}},"tags":{}}],["coordin",{"_index":166,"title":{"132":{},"165":{},"189":{},"195":{},"197":{},"207":{},"212":{}},"content":{"125":{},"127":{},"132":{},"136":{},"144":{},"145":{},"146":{},"147":{},"156":{},"157":{},"160":{},"161":{},"164":{},"165":{},"166":{},"170":{},"175":{},"183":{},"185":{},"186":{},"188":{},"189":{},"191":{},"194":{},"195":{},"196":{},"197":{},"206":{},"207":{},"209":{},"210":{},"211":{},"212":{},"213":{},"214":{},"217":{},"218":{}},"tags":{}}],["coordinator'",{"_index":289,"title":{},"content":{"132":{},"165":{},"198":{},"214":{}},"tags":{}}],["coordinator:1313",{"_index":1109,"title":{},"content":{"209":{}},"tags":{}}],["coordinator=$(kubectl",{"_index":1033,"title":{},"content":{"195":{},"209":{}},"tags":{}}],["coordinator_host",{"_index":930,"title":{},"content":{"185":{},"186":{},"191":{}},"tags":{}}],["coordinator}:1313",{"_index":1042,"title":{},"content":{"196":{},"197":{},"209":{},"212":{},"217":{}},"tags":{}}],["coordinator’",{"_index":349,"title":{},"content":{"136":{}},"tags":{}}],["copi",{"_index":976,"title":{},"content":{"191":{}},"tags":{}}],["core",{"_index":89,"title":{},"content":{"120":{},"149":{},"163":{}},"tags":{}}],["correct",{"_index":840,"title":{},"content":{"174":{}},"tags":{}}],["correspond",{"_index":239,"title":{},"content":{"131":{},"174":{},"182":{}},"tags":{}}],["count",{"_index":1176,"title":{},"content":{"226":{}},"tags":{}}],["counter",{"_index":548,"title":{},"content":{"154":{}},"tags":{}}],["cover",{"_index":1218,"title":{},"content":{"232":{}},"tags":{}}],["coverag",{"_index":1217,"title":{},"content":{"232":{}},"tags":{}}],["cp",{"_index":983,"title":{},"content":{"191":{}},"tags":{}}],["cpu",{"_index":226,"title":{},"content":{"131":{},"135":{},"156":{}},"tags":{}}],["cpu'",{"_index":323,"title":{},"content":{"135":{}},"tags":{}}],["creat",{"_index":191,"title":{"222":{},"225":{},"226":{}},"content":{"129":{},"151":{},"157":{},"161":{},"175":{},"179":{},"193":{},"203":{},"208":{},"209":{},"223":{},"224":{},"225":{},"226":{},"227":{}},"tags":{}}],["credenti",{"_index":1115,"title":{},"content":{"210":{},"226":{}},"tags":{}}],["cri",{"_index":472,"title":{},"content":{"150":{},"195":{}},"tags":{}}],["critic",{"_index":315,"title":{},"content":{"135":{},"140":{},"155":{}},"tags":{}}],["cross",{"_index":571,"title":{},"content":{"155":{}},"tags":{}}],["crucial",{"_index":338,"title":{},"content":{"135":{},"232":{}},"tags":{}}],["crun",{"_index":481,"title":{},"content":{"150":{}},"tags":{}}],["crypto",{"_index":677,"title":{},"content":{"160":{}},"tags":{}}],["cryptograph",{"_index":221,"title":{},"content":{"131":{},"139":{},"141":{},"172":{}},"tags":{}}],["csp",{"_index":630,"title":{},"content":{"159":{}},"tags":{}}],["curl",{"_index":1060,"title":{},"content":{"198":{},"205":{},"215":{},"216":{},"218":{},"228":{}},"tags":{}}],["currenc",{"_index":961,"title":{},"content":{"186":{}},"tags":{}}],["current",{"_index":28,"title":{},"content":{"118":{},"131":{},"139":{},"161":{},"166":{},"174":{},"193":{},"224":{},"225":{},"229":{},"231":{},"232":{},"233":{}},"tags":{}}],["custom",{"_index":750,"title":{},"content":{"162":{},"178":{},"188":{},"192":{},"206":{}},"tags":{}}],["cvm",{"_index":498,"title":{},"content":{"151":{},"152":{},"175":{}},"tags":{}}],["daemonset",{"_index":802,"title":{"182":{}},"content":{"169":{},"177":{},"182":{},"188":{},"206":{}},"tags":{}}],["data",{"_index":42,"title":{"133":{}},"content":{"119":{},"120":{},"122":{},"123":{},"124":{},"133":{},"135":{},"140":{},"142":{},"146":{},"147":{},"153":{},"154":{},"155":{},"157":{},"159":{},"161":{},"162":{},"171":{},"172":{},"174":{},"197":{},"202":{}},"tags":{}}],["datacent",{"_index":53,"title":{},"content":{"119":{},"156":{},"159":{}},"tags":{}}],["day",{"_index":76,"title":{},"content":{"119":{},"153":{}},"tags":{}}],["decid",{"_index":763,"title":{},"content":{"162":{},"211":{}},"tags":{}}],["decis",{"_index":209,"title":{},"content":{"129":{},"142":{}},"tags":{}}],["decreas",{"_index":579,"title":{},"content":{"156":{}},"tags":{}}],["default",{"_index":870,"title":{},"content":{"176":{},"178":{},"185":{},"198":{},"215":{}},"tags":{}}],["defend",{"_index":626,"title":{},"content":{"159":{}},"tags":{}}],["defens",{"_index":680,"title":{},"content":{"160":{},"162":{}},"tags":{}}],["defin",{"_index":282,"title":{},"content":{"132":{},"139":{},"144":{},"146":{},"155":{},"156":{},"162":{},"166":{},"167":{},"176":{},"210":{}},"tags":{}}],["definit",{"_index":158,"title":{},"content":{"125":{},"126":{},"128":{},"129":{},"151":{},"172":{},"173":{},"175":{},"191":{},"192":{},"195":{}},"tags":{}}],["deleg",{"_index":1120,"title":{},"content":{"213":{}},"tags":{}}],["delet",{"_index":1198,"title":{},"content":{"227":{}},"tags":{}}],["demand",{"_index":760,"title":{},"content":{"162":{}},"tags":{}}],["demo",{"_index":1059,"title":{},"content":{"198":{},"208":{},"215":{}},"tags":{}}],["demo.zip",{"_index":1100,"title":{},"content":{"205":{}},"tags":{}}],["denial",{"_index":623,"title":{},"content":{"158":{},"161":{}},"tags":{}}],["depend",{"_index":428,"title":{},"content":{"146":{},"169":{},"188":{},"192":{},"206":{},"233":{}},"tags":{}}],["depict",{"_index":591,"title":{},"content":{"156":{}},"tags":{}}],["deploy",{"_index":6,"title":{"156":{},"157":{},"187":{},"188":{},"189":{},"204":{},"205":{},"206":{},"207":{},"210":{}},"content":{"118":{},"119":{},"131":{},"132":{},"136":{},"138":{},"139":{},"143":{},"144":{},"146":{},"152":{},"153":{},"154":{},"156":{},"157":{},"159":{},"160":{},"161":{},"162":{},"163":{},"164":{},"165":{},"166":{},"167":{},"170":{},"176":{},"182":{},"185":{},"186":{},"187":{},"188":{},"189":{},"191":{},"193":{},"195":{},"197":{},"201":{},"205":{},"206":{},"207":{},"208":{},"209":{},"210":{},"211":{},"212":{},"217":{},"231":{},"232":{}},"tags":{}}],["deployment'",{"_index":782,"title":{},"content":{"165":{}},"tags":{}}],["deployment/emoji",{"_index":1136,"title":{},"content":{"218":{}},"tags":{}}],["deployment/vot",{"_index":1137,"title":{},"content":{"218":{}},"tags":{}}],["deployment/web",{"_index":1138,"title":{},"content":{"218":{}},"tags":{}}],["depth",{"_index":736,"title":{},"content":{"162":{}},"tags":{}}],["deriv",{"_index":503,"title":{},"content":{"151":{},"172":{}},"tags":{}}],["describ",{"_index":157,"title":{},"content":{"125":{},"126":{},"128":{},"155":{},"158":{},"160":{},"161":{},"162":{},"178":{},"181":{}},"tags":{}}],["descript",{"_index":171,"title":{},"content":{"128":{},"185":{}},"tags":{}}],["design",{"_index":40,"title":{},"content":{"119":{},"151":{},"153":{},"154":{},"159":{},"162":{},"164":{}},"tags":{}}],["destin",{"_index":904,"title":{},"content":{"185":{}},"tags":{}}],["detail",{"_index":170,"title":{},"content":{"128":{},"130":{},"131":{},"135":{},"140":{},"155":{},"178":{},"192":{},"193":{}},"tags":{}}],["detect",{"_index":372,"title":{},"content":{"140":{},"155":{},"161":{}},"tags":{}}],["dev/nul",{"_index":1074,"title":{},"content":{"198":{},"214":{}},"tags":{}}],["develop",{"_index":408,"title":{},"content":{"144":{},"149":{},"159":{},"162":{},"229":{}},"tags":{}}],["devic",{"_index":293,"title":{},"content":{"132":{},"159":{},"180":{}},"tags":{}}],["diagram",{"_index":585,"title":{},"content":{"156":{},"157":{}},"tags":{}}],["dictat",{"_index":334,"title":{},"content":{"135":{}},"tags":{}}],["differ",{"_index":409,"title":{"147":{}},"content":{"144":{},"186":{},"201":{},"208":{},"218":{}},"tags":{}}],["digest",{"_index":325,"title":{},"content":{"135":{},"166":{},"175":{}},"tags":{}}],["direct",{"_index":772,"title":{},"content":{"162":{}},"tags":{}}],["directli",{"_index":507,"title":{},"content":{"152":{},"158":{},"192":{},"232":{}},"tags":{}}],["directori",{"_index":977,"title":{},"content":{"191":{},"197":{},"205":{},"212":{}},"tags":{}}],["disabl",{"_index":151,"title":{},"content":{"124":{},"185":{}},"tags":{}}],["discrep",{"_index":350,"title":{},"content":{"136":{},"161":{}},"tags":{}}],["disk",{"_index":634,"title":{},"content":{"159":{},"160":{},"161":{},"182":{}},"tags":{}}],["dispatch",{"_index":474,"title":{},"content":{"150":{}},"tags":{}}],["distribut",{"_index":704,"title":{},"content":{"161":{},"165":{},"211":{}},"tags":{}}],["distrust",{"_index":614,"title":{},"content":{"157":{}},"tags":{}}],["dm",{"_index":250,"title":{},"content":{"131":{},"135":{},"161":{},"172":{},"180":{}},"tags":{}}],["dn",{"_index":1057,"title":{},"content":{"198":{},"215":{},"216":{}},"tags":{}}],["do",{"_index":624,"title":{},"content":{"158":{},"161":{},"211":{}},"tags":{}}],["do_not_track=1",{"_index":154,"title":{},"content":{"124":{}},"tags":{}}],["document",{"_index":2,"title":{},"content":{"118":{},"125":{},"126":{},"128":{},"147":{},"154":{},"158":{},"162":{},"173":{},"178":{},"192":{},"218":{}},"tags":{}}],["doesn't",{"_index":137,"title":{},"content":{"124":{},"146":{},"161":{},"173":{},"192":{}},"tags":{}}],["don't",{"_index":538,"title":{},"content":{"153":{},"174":{},"232":{}},"tags":{}}],["done",{"_index":542,"title":{},"content":{"153":{}},"tags":{}}],["down",{"_index":722,"title":{},"content":{"161":{}},"tags":{}}],["download",{"_index":697,"title":{"205":{}},"content":{"161":{},"172":{},"205":{},"219":{},"220":{},"228":{}},"tags":{}}],["drop",{"_index":992,"title":{},"content":{"192":{}},"tags":{}}],["dual",{"_index":290,"title":{},"content":{"132":{}},"tags":{}}],["dump",{"_index":662,"title":{},"content":{"160":{}},"tags":{}}],["dure",{"_index":233,"title":{},"content":{"131":{},"132":{},"136":{},"147":{},"155":{},"156":{},"162":{},"165":{},"209":{}},"tags":{}}],["e.g",{"_index":1204,"title":{},"content":{"228":{}},"tags":{}}],["each",{"_index":347,"title":{},"content":{"136":{},"143":{},"155":{},"156":{},"162":{},"171":{},"172":{},"182":{},"188":{},"206":{}},"tags":{}}],["earli",{"_index":1208,"title":{},"content":{"229":{}},"tags":{}}],["easi",{"_index":789,"title":{},"content":{"165":{}},"tags":{}}],["easili",{"_index":724,"title":{},"content":{"161":{}},"tags":{}}],["eastu",{"_index":1157,"title":{},"content":{"225":{}},"tags":{}}],["eastus2euap",{"_index":1158,"title":{},"content":{"225":{}},"tags":{}}],["eavesdrop",{"_index":709,"title":{},"content":{"161":{}},"tags":{}}],["echo",{"_index":1052,"title":{},"content":{"198":{},"209":{},"214":{}},"tags":{}}],["edg",{"_index":1219,"title":{},"content":{"232":{}},"tags":{}}],["edg_egress_proxy_config",{"_index":899,"title":{},"content":{"184":{},"186":{},"192":{}},"tags":{}}],["edg_ingress_proxy_config",{"_index":898,"title":{},"content":{"184":{},"185":{},"192":{}},"tags":{}}],["edgeless",{"_index":122,"title":{},"content":{"122":{},"123":{},"124":{}},"tags":{}}],["edit",{"_index":1127,"title":{},"content":{"216":{}},"tags":{}}],["editor",{"_index":1129,"title":{},"content":{"216":{}},"tags":{}}],["effect",{"_index":231,"title":{},"content":{"131":{},"140":{},"156":{},"161":{},"162":{},"163":{}},"tags":{}}],["egress",{"_index":946,"title":{"186":{}},"content":{"186":{}},"tags":{}}],["ek",{"_index":518,"title":{},"content":{"153":{}},"tags":{}}],["element",{"_index":582,"title":{},"content":{"156":{}},"tags":{}}],["embed",{"_index":212,"title":{},"content":{"129":{},"136":{},"197":{},"209":{},"212":{}},"tags":{}}],["emoji",{"_index":1075,"title":{"200":{},"201":{}},"content":{"199":{},"201":{}},"tags":{}}],["emojivoto",{"_index":1078,"title":{"204":{},"210":{}},"content":{"199":{},"200":{},"201":{},"205":{},"208":{},"210":{}},"tags":{}}],["employ",{"_index":512,"title":{},"content":{"153":{}},"tags":{}}],["employe",{"_index":54,"title":{},"content":{"119":{},"159":{}},"tags":{}}],["emptydir",{"_index":945,"title":{},"content":{"185":{},"186":{},"191":{}},"tags":{}}],["enabl",{"_index":375,"title":{},"content":{"140":{},"152":{},"153":{},"154":{},"167":{},"177":{},"180":{},"183":{},"187":{},"216":{}},"tags":{}}],["encapsul",{"_index":242,"title":{},"content":{"131":{},"232":{}},"tags":{}}],["encod",{"_index":832,"title":{},"content":{"173":{}},"tags":{}}],["encompass",{"_index":337,"title":{},"content":{"135":{},"136":{}},"tags":{}}],["encrypt",{"_index":44,"title":{},"content":{"119":{},"138":{},"155":{},"161":{},"165":{}},"tags":{}}],["end",{"_index":173,"title":{},"content":{"128":{},"185":{},"197":{}},"tags":{}}],["endors",{"_index":197,"title":{},"content":{"129":{},"132":{}},"tags":{}}],["endpoint",{"_index":437,"title":{},"content":{"146":{},"147":{},"183":{},"186":{},"192":{}},"tags":{}}],["enforc",{"_index":261,"title":{},"content":{"131":{},"138":{},"156":{},"167":{},"180":{},"211":{},"232":{}},"tags":{}}],["engin",{"_index":715,"title":{},"content":{"161":{}},"tags":{}}],["enhanc",{"_index":735,"title":{},"content":{"162":{},"230":{}},"tags":{}}],["ensur",{"_index":252,"title":{"139":{}},"content":{"131":{},"135":{},"136":{},"138":{},"141":{},"143":{},"146":{},"153":{},"155":{},"161":{},"162":{},"165":{},"167":{},"192":{},"209":{},"214":{},"217":{},"232":{}},"tags":{}}],["entir",{"_index":295,"title":{},"content":{"132":{},"135":{},"153":{},"154":{},"156":{},"164":{},"165":{},"174":{},"232":{}},"tags":{}}],["entiti",{"_index":189,"title":{},"content":{"129":{},"147":{},"154":{},"162":{},"213":{}},"tags":{}}],["entri",{"_index":912,"title":{},"content":{"185":{},"186":{},"198":{},"215":{},"216":{}},"tags":{}}],["env",{"_index":929,"title":{},"content":{"185":{},"186":{},"191":{},"192":{}},"tags":{}}],["environ",{"_index":22,"title":{},"content":{"118":{},"124":{},"131":{},"135":{},"138":{},"140":{},"153":{},"155":{},"156":{},"157":{},"159":{},"160":{},"161":{},"162":{},"163":{},"166":{},"167":{},"172":{},"174":{},"184":{},"185":{},"202":{},"212":{},"232":{}},"tags":{}}],["envoy",{"_index":544,"title":{},"content":{"153":{},"183":{},"185":{},"186":{}},"tags":{}}],["equip",{"_index":771,"title":{},"content":{"162":{}},"tags":{}}],["error",{"_index":135,"title":{},"content":{"124":{},"192":{},"198":{},"215":{}},"tags":{}}],["escal",{"_index":67,"title":{},"content":{"119":{}},"tags":{}}],["especi",{"_index":737,"title":{},"content":{"162":{}},"tags":{}}],["essenti",{"_index":328,"title":{},"content":{"135":{},"163":{}},"tags":{}}],["establish",{"_index":414,"title":{},"content":{"144":{},"145":{},"153":{},"154":{},"159":{},"165":{},"183":{},"212":{}},"tags":{}}],["etc",{"_index":985,"title":{},"content":{"191":{}},"tags":{}}],["evalu",{"_index":830,"title":{"173":{}},"content":{"174":{},"232":{}},"tags":{}}],["even",{"_index":97,"title":{},"content":{"120":{},"155":{},"159":{}},"tags":{}}],["event",{"_index":1220,"title":{},"content":{"232":{}},"tags":{}}],["everyon",{"_index":695,"title":{},"content":{"161":{}},"tags":{}}],["everyth",{"_index":655,"title":{},"content":{"159":{}},"tags":{}}],["evid",{"_index":192,"title":{"134":{},"135":{},"136":{}},"content":{"129":{},"131":{},"132":{},"135":{},"136":{},"139":{},"141":{},"161":{}},"tags":{}}],["exampl",{"_index":63,"title":{"162":{},"199":{}},"content":{"119":{},"133":{},"144":{},"150":{},"159":{},"160":{},"162":{},"185":{},"186":{},"192":{},"193":{},"198":{},"201":{},"215":{}},"tags":{}}],["exclus",{"_index":753,"title":{},"content":{"162":{},"230":{}},"tags":{}}],["exec",{"_index":671,"title":{},"content":{"160":{}},"tags":{}}],["execut",{"_index":13,"title":{},"content":{"118":{},"155":{},"174":{},"193":{},"208":{},"223":{}},"tags":{}}],["exist",{"_index":70,"title":{},"content":{"119":{},"153":{},"187":{},"225":{},"231":{}},"tags":{}}],["expand",{"_index":637,"title":{},"content":{"159":{}},"tags":{}}],["expans",{"_index":1211,"title":{},"content":{"230":{}},"tags":{}}],["expect",{"_index":335,"title":{},"content":{"135":{},"136":{},"151":{},"156":{},"161":{},"170":{},"174":{},"175":{},"180":{},"212":{},"214":{},"229":{}},"tags":{}}],["explain",{"_index":991,"title":{},"content":{"192":{}},"tags":{}}],["explicitli",{"_index":728,"title":{},"content":{"161":{}},"tags":{}}],["exploit",{"_index":712,"title":{},"content":{"161":{}},"tags":{}}],["expos",{"_index":812,"title":{},"content":{"171":{},"185":{},"198":{},"214":{}},"tags":{}}],["extend",{"_index":469,"title":{},"content":{"150":{}},"tags":{}}],["extens",{"_index":455,"title":{},"content":{"147":{},"224":{}},"tags":{}}],["extern",{"_index":537,"title":{},"content":{"153":{},"160":{}},"tags":{}}],["extract",{"_index":1102,"title":{},"content":{"205":{}},"tags":{}}],["f",{"_index":967,"title":{},"content":{"188":{},"189":{},"194":{},"206":{},"207":{},"210":{}},"tags":{}}],["face",{"_index":605,"title":{},"content":{"156":{},"210":{}},"tags":{}}],["facilit",{"_index":525,"title":{},"content":{"153":{},"164":{},"208":{}},"tags":{}}],["fail",{"_index":1062,"title":{},"content":{"198":{},"215":{}},"tags":{}}],["fair",{"_index":1093,"title":{},"content":{"202":{},"211":{}},"tags":{}}],["faq",{"_index":174,"title":{},"content":{"128":{}},"tags":{}}],["favorit",{"_index":1128,"title":{},"content":{"216":{}},"tags":{}}],["featur",{"_index":87,"title":{"153":{},"231":{}},"content":{"120":{},"121":{},"139":{},"149":{},"153":{},"155":{},"156":{},"224":{},"231":{}},"tags":{}}],["fetch",{"_index":800,"title":{},"content":{"168":{},"196":{}},"tags":{}}],["few",{"_index":1106,"title":{},"content":{"209":{},"224":{}},"tags":{}}],["field",{"_index":274,"title":{},"content":{"131":{},"135":{},"175":{},"176":{},"178":{},"182":{},"185":{},"198":{},"215":{}},"tags":{}}],["figur",{"_index":184,"title":{},"content":{"129":{},"131":{},"132":{}},"tags":{}}],["file",{"_index":345,"title":{},"content":{"136":{},"156":{},"164":{},"165":{},"166":{},"167":{},"181":{},"182":{},"191":{},"193":{},"205":{},"208":{}},"tags":{}}],["filesystem",{"_index":253,"title":{},"content":{"131":{},"135":{},"181":{},"182":{}},"tags":{}}],["filesystem'",{"_index":332,"title":{},"content":{"135":{}},"tags":{}}],["final",{"_index":1182,"title":{},"content":{"226":{}},"tags":{}}],["find",{"_index":1006,"title":{},"content":{"192":{}},"tags":{}}],["firewal",{"_index":645,"title":{},"content":{"159":{}},"tags":{}}],["firm",{"_index":734,"title":{},"content":{"162":{}},"tags":{}}],["first",{"_index":429,"title":{},"content":{"146":{},"183":{},"198":{},"226":{}},"tags":{}}],["fit",{"_index":1122,"title":{},"content":{"214":{}},"tags":{}}],["five",{"_index":627,"title":{},"content":{"159":{}},"tags":{}}],["flag",{"_index":1144,"title":{},"content":{"224":{}},"tags":{}}],["flo",{"_index":1098,"title":{},"content":{"205":{},"228":{}},"tags":{}}],["flow",{"_index":82,"title":{},"content":{"119":{},"131":{},"218":{}},"tags":{}}],["fluentli",{"_index":69,"title":{},"content":{"119":{}},"tags":{}}],["flux",{"_index":465,"title":{},"content":{"149":{}},"tags":{}}],["follow",{"_index":128,"title":{},"content":{"124":{},"128":{},"129":{},"153":{},"156":{},"157":{},"158":{},"160":{},"161":{},"162":{},"166":{},"174":{},"175":{},"182":{},"185":{},"186":{},"187":{},"192":{},"198":{},"203":{},"215":{},"224":{},"225":{}},"tags":{}}],["foothold",{"_index":651,"title":{},"content":{"159":{}},"tags":{}}],["for=jsonpath='{.status.loadbalancer.ingress",{"_index":1049,"title":{},"content":{"198":{}},"tags":{}}],["form",{"_index":752,"title":{},"content":{"162":{}},"tags":{}}],["format",{"_index":241,"title":{"135":{}},"content":{"131":{}},"tags":{}}],["forward",{"_index":1035,"title":{},"content":{"195":{},"231":{}},"tags":{}}],["found",{"_index":381,"title":{},"content":{"140":{}},"tags":{}}],["foundat",{"_index":566,"title":{"155":{}},"content":{},"tags":{}}],["frequent",{"_index":356,"title":{"137":{}},"content":{},"tags":{}}],["fresh",{"_index":439,"title":{},"content":{"146":{}},"tags":{}}],["frontend",{"_index":1058,"title":{},"content":{"198":{},"201":{},"210":{},"214":{},"215":{},"216":{},"218":{}},"tags":{}}],["frontendip",{"_index":1130,"title":{},"content":{"216":{}},"tags":{}}],["frontendip=$(kubectl",{"_index":1123,"title":{},"content":{"214":{}},"tags":{}}],["frontendip}:443",{"_index":1073,"title":{},"content":{"198":{},"214":{}},"tags":{}}],["full",{"_index":608,"title":{},"content":{"157":{},"159":{},"173":{}},"tags":{}}],["fulli",{"_index":706,"title":{},"content":{"161":{},"232":{}},"tags":{}}],["function",{"_index":604,"title":{},"content":{"156":{},"164":{},"232":{}},"tags":{}}],["further",{"_index":390,"title":{},"content":{"141":{},"161":{},"208":{}},"tags":{}}],["furthermor",{"_index":954,"title":{},"content":{"186":{}},"tags":{}}],["futur",{"_index":443,"title":{},"content":{"147":{},"161":{},"173":{},"211":{}},"tags":{}}],["gener",{"_index":201,"title":{"134":{},"172":{},"193":{},"208":{}},"content":{"129":{},"131":{},"132":{},"135":{},"139":{},"141":{},"153":{},"164":{},"166":{},"172":{},"173":{},"174":{},"175":{},"191":{},"193":{},"208":{},"226":{},"232":{}},"tags":{}}],["germanywestcentr",{"_index":1159,"title":{},"content":{"225":{}},"tags":{}}],["get",{"_index":116,"title":{"219":{}},"content":{"121":{}},"tags":{}}],["ghcr.io/edgelesssys/contrast/initializer:latest",{"_index":989,"title":{},"content":{"191":{}},"tags":{}}],["ghcr.io/edgelesssys/contrast/initializer@sha256",{"_index":928,"title":{},"content":{"185":{},"186":{}},"tags":{}}],["ghcr.io/edgelesssys/contrast/servic",{"_index":935,"title":{},"content":{"185":{},"186":{},"192":{}},"tags":{}}],["ghcr.io/edgelesssys/conversion:v1.2.3",{"_index":963,"title":{},"content":{"186":{}},"tags":{}}],["ghcr.io/edgelesssys/frontend:v1.2.3",{"_index":943,"title":{},"content":{"185":{}},"tags":{}}],["give",{"_index":169,"title":{},"content":{"128":{}},"tags":{}}],["given",{"_index":227,"title":{},"content":{"131":{},"185":{},"186":{}},"tags":{}}],["gke",{"_index":520,"title":{},"content":{"153":{}},"tags":{}}],["go",{"_index":513,"title":{},"content":{"153":{},"161":{},"192":{}},"tags":{}}],["goal",{"_index":39,"title":{"119":{}},"content":{"162":{}},"tags":{}}],["goarch",{"_index":133,"title":{},"content":{"124":{}},"tags":{}}],["goe",{"_index":631,"title":{},"content":{"159":{}},"tags":{}}],["golang",{"_index":1011,"title":{},"content":{"192":{}},"tags":{}}],["goo",{"_index":132,"title":{},"content":{"124":{}},"tags":{}}],["googl",{"_index":519,"title":{},"content":{"153":{}},"tags":{}}],["govern",{"_index":341,"title":{},"content":{"136":{}},"tags":{}}],["grant",{"_index":767,"title":{},"content":{"162":{}},"tags":{}}],["graphic",{"_index":228,"title":{},"content":{"131":{},"156":{}},"tags":{}}],["green",{"_index":592,"title":{},"content":{"156":{}},"tags":{}}],["group",{"_index":685,"title":{"225":{}},"content":{"161":{},"192":{},"225":{},"226":{},"227":{}},"tags":{}}],["grow",{"_index":747,"title":{},"content":{"162":{}},"tags":{}}],["grpc",{"_index":1085,"title":{},"content":{"201":{}},"tags":{}}],["guarante",{"_index":368,"title":{"174":{}},"content":{"139":{},"140":{},"161":{},"162":{},"170":{},"174":{},"181":{},"193":{},"232":{}},"tags":{}}],["guest",{"_index":255,"title":{},"content":{"131":{},"135":{},"136":{},"151":{},"180":{},"181":{}},"tags":{}}],["guest'",{"_index":643,"title":{},"content":{"159":{}},"tags":{}}],["guid",{"_index":964,"title":{},"content":{"187":{},"190":{},"201":{}},"tags":{}}],["guidelin",{"_index":397,"title":{},"content":{"143":{}},"tags":{}}],["hacker",{"_index":646,"title":{},"content":{"159":{},"160":{}},"tags":{}}],["hand",{"_index":449,"title":{},"content":{"147":{},"185":{}},"tags":{}}],["handl",{"_index":799,"title":{"192":{}},"content":{"168":{},"171":{},"185":{},"192":{}},"tags":{}}],["handler",{"_index":862,"title":{},"content":{"176":{},"178":{},"182":{}},"tags":{}}],["handov",{"_index":769,"title":{},"content":{"162":{}},"tags":{}}],["handshak",{"_index":1110,"title":{},"content":{"209":{}},"tags":{}}],["happen",{"_index":1224,"title":{},"content":{"232":{}},"tags":{}}],["har",{"_index":543,"title":{},"content":{"153":{}},"tags":{}}],["hard",{"_index":993,"title":{},"content":{"192":{}},"tags":{}}],["hardwar",{"_index":19,"title":{},"content":{"118":{},"131":{},"132":{},"135":{},"136":{},"139":{},"141":{},"154":{},"155":{},"156":{},"158":{},"161":{}},"tags":{}}],["harm",{"_index":659,"title":{},"content":{"159":{},"160":{}},"tags":{}}],["hash",{"_index":249,"title":{},"content":{"131":{},"135":{},"136":{},"156":{},"166":{},"175":{},"180":{},"216":{}},"tags":{}}],["hasn't",{"_index":363,"title":{},"content":{"138":{},"155":{},"175":{},"209":{}},"tags":{}}],["have",{"_index":703,"title":{},"content":{"161":{}},"tags":{}}],["haven't",{"_index":1228,"title":{},"content":{"233":{}},"tags":{}}],["head",{"_index":115,"title":{},"content":{"121":{}},"tags":{}}],["healthcar",{"_index":765,"title":{},"content":{"162":{}},"tags":{}}],["healthsecur",{"_index":756,"title":{},"content":{"162":{}},"tags":{}}],["heavi",{"_index":678,"title":{},"content":{"160":{}},"tags":{}}],["heavili",{"_index":995,"title":{},"content":{"192":{}},"tags":{}}],["helm",{"_index":528,"title":{},"content":{"153":{},"191":{}},"tags":{}}],["help",{"_index":617,"title":{},"content":{"158":{},"161":{}},"tags":{}}],["henc",{"_index":755,"title":{},"content":{"162":{}},"tags":{}}],["here",{"_index":382,"title":{},"content":{"140":{},"162":{}},"tags":{}}],["high",{"_index":400,"title":{},"content":{"143":{},"149":{}},"tags":{}}],["highli",{"_index":1090,"title":{},"content":{"202":{}},"tags":{}}],["hijack",{"_index":702,"title":{},"content":{"161":{}},"tags":{}}],["hindsight",{"_index":179,"title":{},"content":{"128":{}},"tags":{}}],["histori",{"_index":1043,"title":{"213":{}},"content":{"197":{},"212":{}},"tags":{}}],["hold",{"_index":418,"title":{},"content":{"145":{}},"tags":{}}],["host",{"_index":264,"title":{},"content":{"131":{},"135":{},"151":{},"156":{},"180":{},"198":{},"215":{}},"tags":{}}],["hostdata",{"_index":273,"title":{},"content":{"131":{},"173":{},"175":{}},"tags":{}}],["hostnam",{"_index":952,"title":{},"content":{"186":{}},"tags":{}}],["html",{"_index":1139,"title":{},"content":{"218":{}},"tags":{}}],["http",{"_index":1200,"title":{},"content":{"228":{}},"tags":{}}],["https://$frontendip",{"_index":1124,"title":{},"content":{"214":{}},"tags":{}}],["https://${frontendip}:443",{"_index":1065,"title":{},"content":{"198":{},"215":{},"218":{}},"tags":{}}],["https://github.com/edgelesssys/contrast/releases/latest/download/contrast",{"_index":1202,"title":{},"content":{"228":{}},"tags":{}}],["https://github.com/edgelesssys/contrast/releases/latest/download/coordinator.yml",{"_index":972,"title":{},"content":{"189":{},"207":{}},"tags":{}}],["https://github.com/edgelesssys/contrast/releases/latest/download/emojivoto",{"_index":1099,"title":{},"content":{"205":{}},"tags":{}}],["https://github.com/edgelesssys/contrast/releases/latest/download/runtime.yml",{"_index":968,"title":{},"content":{"188":{},"206":{}},"tags":{}}],["https://github.com/kata",{"_index":1039,"title":{},"content":{"195":{}},"tags":{}}],["hypervisor",{"_index":275,"title":{"179":{}},"content":{"131":{},"156":{},"159":{},"169":{},"179":{},"182":{}},"tags":{}}],["ident",{"_index":369,"title":{},"content":{"140":{},"153":{},"157":{},"161":{},"165":{},"166":{}},"tags":{}}],["identifi",{"_index":318,"title":{},"content":{"135":{},"136":{},"154":{},"170":{},"176":{},"185":{},"186":{}},"tags":{}}],["igvm",{"_index":240,"title":{},"content":{"131":{},"169":{},"181":{},"182":{}},"tags":{}}],["imag",{"_index":238,"title":{"181":{}},"content":{"131":{},"135":{},"151":{},"155":{},"156":{},"157":{},"159":{},"160":{},"161":{},"162":{},"169":{},"172":{},"174":{},"180":{},"181":{},"182":{},"185":{},"186":{},"191":{},"192":{}},"tags":{}}],["imperson",{"_index":711,"title":{},"content":{"161":{}},"tags":{}}],["implement",{"_index":139,"title":{},"content":{"124":{},"150":{},"161":{},"162":{},"174":{},"176":{},"178":{},"232":{}},"tags":{}}],["impli",{"_index":596,"title":{},"content":{"156":{}},"tags":{}}],["import",{"_index":824,"title":{},"content":{"172":{}},"tags":{}}],["impos",{"_index":79,"title":{},"content":{"119":{}},"tags":{}}],["improv",{"_index":127,"title":{},"content":{"124":{}},"tags":{}}],["inaccess",{"_index":569,"title":{},"content":{"155":{}},"tags":{}}],["inc",{"_index":733,"title":{},"content":{"162":{}},"tags":{}}],["includ",{"_index":52,"title":{},"content":{"119":{},"128":{},"129":{},"131":{},"135":{},"136":{},"140":{},"151":{},"156":{},"157":{},"160":{},"162":{},"175":{},"195":{}},"tags":{}}],["incom",{"_index":856,"title":{},"content":{"175":{},"185":{}},"tags":{}}],["incorpor",{"_index":331,"title":{},"content":{"135":{}},"tags":{}}],["incorrectli",{"_index":1216,"title":{},"content":{"231":{}},"tags":{}}],["increas",{"_index":90,"title":{},"content":{"120":{},"162":{}},"tags":{}}],["individu",{"_index":515,"title":{},"content":{"153":{}},"tags":{}}],["infect",{"_index":1133,"title":{},"content":{"217":{}},"tags":{}}],["inform",{"_index":37,"title":{},"content":{"118":{},"124":{},"131":{},"135":{},"142":{},"147":{},"154":{},"171":{},"172":{},"180":{},"185":{},"192":{},"212":{}},"tags":{}}],["infrastructur",{"_index":47,"title":{"145":{}},"content":{"119":{},"145":{},"151":{},"153":{},"154":{},"155":{},"156":{},"159":{},"162":{},"230":{}},"tags":{}}],["ingress",{"_index":900,"title":{"185":{}},"content":{"185":{},"186":{}},"tags":{}}],["init",{"_index":801,"title":{},"content":{"168":{},"181":{},"196":{},"208":{}},"tags":{}}],["initcontain",{"_index":927,"title":{},"content":{"185":{},"186":{},"191":{},"192":{}},"tags":{}}],["initi",{"_index":235,"title":{"168":{},"191":{}},"content":{"131":{},"135":{},"147":{},"153":{},"155":{},"156":{},"168":{},"175":{},"181":{},"185":{},"186":{},"191":{},"192":{},"194":{},"208":{},"210":{},"218":{}},"tags":{}}],["initramf",{"_index":247,"title":{},"content":{"131":{},"135":{}},"tags":{}}],["initrd",{"_index":884,"title":{},"content":{"181":{}},"tags":{}}],["input",{"_index":846,"title":{},"content":{"174":{}},"tags":{}}],["insid",{"_index":14,"title":{},"content":{"118":{},"131":{},"140":{},"159":{},"160":{},"162":{},"165":{},"167":{},"183":{},"186":{}},"tags":{}}],["inspect",{"_index":719,"title":{},"content":{"161":{},"172":{},"213":{},"232":{}},"tags":{}}],["instal",{"_index":75,"title":{"182":{},"220":{},"228":{}},"content":{"119":{},"152":{},"153":{},"164":{},"169":{},"177":{},"179":{},"182":{},"188":{},"189":{},"203":{},"206":{},"219":{},"223":{},"228":{}},"tags":{}}],["instanc",{"_index":444,"title":{},"content":{"147":{},"155":{},"160":{},"165":{}},"tags":{}}],["instanti",{"_index":844,"title":{},"content":{"174":{}},"tags":{}}],["instead",{"_index":869,"title":{},"content":{"176":{},"178":{},"181":{},"231":{}},"tags":{}}],["instruct",{"_index":874,"title":{},"content":{"178":{},"187":{},"203":{}},"tags":{}}],["insuffici",{"_index":619,"title":{},"content":{"158":{}},"tags":{}}],["integr",{"_index":68,"title":{"233":{}},"content":{"119":{},"129":{},"131":{},"135":{},"136":{},"138":{},"140":{},"142":{},"153":{},"155":{},"156":{},"157":{},"161":{},"164":{},"165":{},"167":{},"170":{},"172":{},"174":{},"180":{},"181":{},"192":{},"232":{}},"tags":{}}],["intel",{"_index":594,"title":{},"content":{"156":{}},"tags":{}}],["inter",{"_index":1114,"title":{},"content":{"210":{}},"tags":{}}],["interact",{"_index":306,"title":{},"content":{"133":{},"157":{}},"tags":{}}],["intercept",{"_index":635,"title":{},"content":{"159":{},"160":{},"161":{}},"tags":{}}],["interest",{"_index":1092,"title":{},"content":{"202":{}},"tags":{}}],["interfac",{"_index":471,"title":{"164":{}},"content":{"150":{},"176":{},"195":{}},"tags":{}}],["intermedi",{"_index":420,"title":{},"content":{"145":{},"146":{},"147":{},"185":{},"186":{}},"tags":{}}],["intern",{"_index":536,"title":{},"content":{"153":{}},"tags":{}}],["intra",{"_index":673,"title":{},"content":{"160":{}},"tags":{}}],["introduc",{"_index":434,"title":{},"content":{"146":{},"159":{}},"tags":{}}],["invok",{"_index":855,"title":{},"content":{"175":{},"178":{}},"tags":{}}],["involv",{"_index":218,"title":{},"content":{"130":{},"155":{},"162":{},"231":{}},"tags":{}}],["ip",{"_index":143,"title":{},"content":{"124":{},"186":{},"198":{},"214":{},"215":{}},"tags":{}}],["ip>::###fals",{"_index":910,"title":{},"content":{"185":{}},"tags":{}}],["name>##tru",{"_index":918,"title":{},"content":{"185":{}},"tags":{}}],["namespac",{"_index":1146,"title":{},"content":{"224":{}},"tags":{}}],["nativ",{"_index":531,"title":{},"content":{"153":{}},"tags":{}}],["necessari",{"_index":777,"title":{},"content":{"164":{},"190":{},"230":{}},"tags":{}}],["need",{"_index":445,"title":{},"content":{"147":{},"161":{},"162":{},"165":{},"171":{},"176":{},"177":{},"188":{},"190":{},"195":{},"206":{},"211":{},"213":{},"223":{},"224":{}},"tags":{}}],["nest",{"_index":491,"title":{},"content":{"151":{},"152":{}},"tags":{}}],["net_admin",{"_index":941,"title":{},"content":{"185":{},"186":{}},"tags":{}}],["network",{"_index":496,"title":{},"content":{"151":{},"157":{},"159":{},"160":{},"161":{},"183":{}},"tags":{}}],["new",{"_index":427,"title":{},"content":{"145":{},"147":{},"159":{},"161":{},"165":{},"182":{},"217":{},"218":{},"225":{},"227":{}},"tags":{}}],["next",{"_index":107,"title":{"121":{}},"content":{"195":{},"213":{},"217":{}},"tags":{}}],["node",{"_index":487,"title":{"177":{},"182":{}},"content":{"151":{},"152":{},"157":{},"169":{},"175":{},"177":{},"179":{},"182":{},"188":{},"206":{},"226":{},"227":{}},"tags":{}}],["node.k8s.io/v1",{"_index":864,"title":{},"content":{"176":{}},"tags":{}}],["nodepool",{"_index":1179,"title":{},"content":{"226":{}},"tags":{}}],["nodepool1",{"_index":1185,"title":{},"content":{"226":{}},"tags":{}}],["nodepool2",{"_index":1180,"title":{},"content":{"226":{}},"tags":{}}],["non",{"_index":701,"title":{},"content":{"161":{},"185":{}},"tags":{}}],["none",{"_index":1189,"title":{},"content":{"226":{}},"tags":{}}],["northeurop",{"_index":1161,"title":{},"content":{"225":{}},"tags":{}}],["notabl",{"_index":330,"title":{},"content":{"135":{}},"tags":{}}],["note",{"_index":597,"title":{},"content":{"156":{}},"tags":{}}],["now",{"_index":1113,"title":{},"content":{"210":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1034,"title":{},"content":{"195":{},"198":{},"209":{},"214":{}},"tags":{}}],["object",{"_index":470,"title":{},"content":{"150":{},"232":{}},"tags":{}}],["observ",{"_index":842,"title":{},"content":{"174":{}},"tags":{}}],["obtain",{"_index":213,"title":{},"content":{"129":{},"133":{},"146":{}},"tags":{}}],["occur",{"_index":136,"title":{},"content":{"124":{}},"tags":{}}],["oci",{"_index":478,"title":{},"content":{"150":{},"151":{},"172":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"120":{},"152":{},"153":{},"162":{},"165":{}},"tags":{}}],["offlin",{"_index":303,"title":{},"content":{"132":{}},"tags":{}}],["older",{"_index":1134,"title":{},"content":{"217":{},"218":{}},"tags":{}}],["omit",{"_index":850,"title":{},"content":{"174":{},"192":{},"232":{}},"tags":{}}],["on",{"_index":278,"title":{},"content":{"131":{},"150":{},"162":{},"186":{},"225":{}},"tags":{}}],["onc",{"_index":966,"title":{},"content":{"188":{},"206":{}},"tags":{}}],["opa",{"_index":501,"title":{},"content":{"151":{},"167":{}},"tags":{}}],["open",{"_index":140,"title":{},"content":{"124":{},"151":{},"167":{}},"tags":{}}],["openssl",{"_index":1069,"title":{},"content":{"198":{},"214":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"119":{},"132":{},"138":{},"140":{},"153":{},"154":{},"155":{},"157":{},"159":{},"160":{},"162":{},"164":{},"224":{}},"tags":{}}],["optim",{"_index":509,"title":{},"content":{"153":{}},"tags":{}}],["option",{"_index":486,"title":{"215":{}},"content":{"151":{}},"tags":{}}],["orchestr",{"_index":532,"title":{},"content":{"153":{},"167":{}},"tags":{}}],["order",{"_index":849,"title":{},"content":{"174":{},"193":{},"232":{}},"tags":{}}],["origin",{"_index":497,"title":{},"content":{"151":{},"183":{},"191":{}},"tags":{}}],["os",{"_index":130,"title":{},"content":{"124":{},"156":{},"226":{}},"tags":{}}],["os.readfile(\"/tl",{"_index":1016,"title":{},"content":{"192":{}},"tags":{}}],["otherwis",{"_index":839,"title":{},"content":{"173":{}},"tags":{}}],["out",{"_index":450,"title":{"218":{}},"content":{"147":{},"158":{},"159":{},"161":{},"182":{},"185":{},"218":{},"227":{}},"tags":{}}],["outlin",{"_index":547,"title":{},"content":{"154":{},"190":{},"229":{}},"tags":{}}],["output",{"_index":1151,"title":{},"content":{"224":{}},"tags":{}}],["outsid",{"_index":816,"title":{},"content":{"171":{},"185":{}},"tags":{}}],["over",{"_index":492,"title":{},"content":{"151":{},"159":{},"185":{},"186":{},"210":{},"212":{}},"tags":{}}],["overview",{"_index":546,"title":{"154":{}},"content":{"163":{}},"tags":{}}],["own",{"_index":611,"title":{},"content":{"157":{}},"tags":{}}],["owner",{"_index":203,"title":{"133":{}},"content":{"129":{},"133":{},"146":{},"147":{},"155":{},"157":{},"161":{},"162":{},"197":{},"202":{}},"tags":{}}],["owner'",{"_index":794,"title":{},"content":{"166":{},"170":{}},"tags":{}}],["ownership",{"_index":554,"title":{},"content":{"154":{}},"tags":{}}],["owners—to",{"_index":377,"title":{},"content":{"140":{}},"tags":{}}],["p",{"_index":1046,"title":{},"content":{"198":{}},"tags":{}}],["packet",{"_index":907,"title":{},"content":{"185":{}},"tags":{}}],["page",{"_index":327,"title":{},"content":{"135":{},"163":{}},"tags":{}}],["paramet",{"_index":818,"title":{},"content":{"171":{},"172":{}},"tags":{}}],["pars",{"_index":713,"title":{},"content":{"161":{}},"tags":{}}],["part",{"_index":265,"title":{},"content":{"131":{},"135":{},"139":{},"147":{},"156":{},"166":{},"170":{},"171":{},"176":{},"180":{},"183":{},"186":{},"205":{},"210":{},"217":{}},"tags":{}}],["parti",{"_index":105,"title":{"133":{},"142":{}},"content":{"120":{},"129":{},"133":{},"142":{},"144":{},"146":{},"153":{},"157":{},"159":{},"162":{},"165":{},"185":{}},"tags":{}}],["particip",{"_index":809,"title":{},"content":{"170":{}},"tags":{}}],["particular",{"_index":1225,"title":{},"content":{"232":{}},"tags":{}}],["particularli",{"_index":557,"title":{},"content":{"154":{},"174":{}},"tags":{}}],["parties—such",{"_index":376,"title":{},"content":{"140":{}},"tags":{}}],["partit",{"_index":698,"title":{},"content":{"161":{},"181":{}},"tags":{}}],["pass",{"_index":262,"title":{},"content":{"131":{}},"tags":{}}],["passiv",{"_index":708,"title":{},"content":{"161":{}},"tags":{}}],["patch",{"_index":1044,"title":{},"content":{"198":{},"217":{}},"tags":{}}],["path",{"_index":1203,"title":{},"content":{"228":{}},"tags":{}}],["patient",{"_index":758,"title":{},"content":{"162":{}},"tags":{}}],["peer",{"_index":1009,"title":{},"content":{"192":{}},"tags":{}}],["pend",{"_index":1213,"title":{},"content":{"230":{}},"tags":{}}],["per",{"_index":895,"title":{},"content":{"183":{}},"tags":{}}],["perform",{"_index":672,"title":{},"content":{"160":{},"161":{},"177":{},"182":{},"188":{},"206":{}},"tags":{}}],["period",{"_index":653,"title":{},"content":{"159":{}},"tags":{}}],["perman",{"_index":650,"title":{},"content":{"159":{}},"tags":{}}],["permiss",{"_index":612,"title":{},"content":{"157":{},"171":{},"172":{},"223":{}},"tags":{}}],["permit",{"_index":798,"title":{},"content":{"167":{},"175":{}},"tags":{}}],["persist",{"_index":726,"title":{},"content":{"161":{},"231":{},"232":{}},"tags":{}}],["person",{"_index":551,"title":{},"content":{"154":{}},"tags":{}}],["persona",{"_index":606,"title":{"157":{}},"content":{"162":{}},"tags":{}}],["perspect",{"_index":511,"title":{"211":{}},"content":{"153":{},"201":{}},"tags":{}}],["phase",{"_index":576,"title":{},"content":{"155":{},"194":{}},"tags":{}}],["physic",{"_index":570,"title":{},"content":{"155":{},"156":{},"159":{},"160":{},"161":{}},"tags":{}}],["piec",{"_index":316,"title":{},"content":{"135":{}},"tags":{}}],["pii",{"_index":552,"title":{},"content":{"154":{}},"tags":{}}],["pki",{"_index":417,"title":{},"content":{"145":{},"153":{},"183":{}},"tags":{}}],["placehold",{"_index":986,"title":{},"content":{"191":{}},"tags":{}}],["plain",{"_index":997,"title":{},"content":{"192":{}},"tags":{}}],["plan",{"_index":1212,"title":{},"content":{"230":{}},"tags":{}}],["plane",{"_index":588,"title":{},"content":{"156":{},"160":{},"161":{}},"tags":{}}],["platform",{"_index":319,"title":{},"content":{"135":{},"153":{},"155":{},"159":{},"202":{},"230":{},"233":{}},"tags":{}}],["platform'",{"_index":745,"title":{},"content":{"162":{}},"tags":{}}],["play",{"_index":370,"title":{},"content":{"140":{}},"tags":{}}],["pleas",{"_index":1031,"title":{},"content":{"193":{},"203":{}},"tags":{}}],["plugin",{"_index":803,"title":{},"content":{"169":{},"178":{},"182":{}},"tags":{}}],["pod",{"_index":12,"title":{"131":{},"181":{}},"content":{"118":{},"131":{},"132":{},"136":{},"139":{},"147":{},"149":{},"150":{},"151":{},"153":{},"155":{},"156":{},"165":{},"166":{},"170":{},"172":{},"173":{},"174":{},"175":{},"176":{},"179":{},"180":{},"181":{},"182":{},"183":{},"186":{},"191":{},"195":{},"208":{},"232":{}},"tags":{}}],["pod'",{"_index":280,"title":{},"content":{"131":{},"144":{}},"tags":{}}],["podspec",{"_index":821,"title":{},"content":{"171":{},"172":{}},"tags":{}}],["podvm",{"_index":804,"title":{},"content":{"169":{}},"tags":{}}],["pod’",{"_index":365,"title":{},"content":{"139":{}},"tags":{}}],["point",{"_index":340,"title":{},"content":{"135":{},"160":{}},"tags":{}}],["polici",{"_index":150,"title":{"136":{},"167":{},"170":{},"193":{},"208":{},"232":{}},"content":{"124":{},"129":{},"131":{},"132":{},"135":{},"136":{},"138":{},"139":{},"151":{},"155":{},"156":{},"161":{},"164":{},"166":{},"167":{},"170":{},"171":{},"172":{},"173":{},"174":{},"175":{},"180":{},"191":{},"193":{},"197":{},"208":{},"212":{},"213":{},"216":{},"232":{}},"tags":{}}],["policy'",{"_index":276,"title":{},"content":{"131":{},"172":{},"175":{}},"tags":{}}],["pool",{"_index":505,"title":{},"content":{"152":{},"226":{},"227":{}},"tags":{}}],["popul",{"_index":820,"title":{},"content":{"171":{},"192":{}},"tags":{}}],["port",{"_index":915,"title":{},"content":{"185":{},"186":{},"192":{},"195":{},"231":{},"233":{}},"tags":{}}],["port>#::###fals",{"_index":952,"title":{},"content":{"304":{}},"tags":{}}],["name>##tru",{"_index":959,"title":{},"content":{"304":{}},"tags":{}}],["namespac",{"_index":1205,"title":{},"content":{"309":{}},"tags":{}}],["nativ",{"_index":586,"title":{},"content":{"272":{}},"tags":{}}],["necessari",{"_index":824,"title":{},"content":{"67":{},"70":{},"97":{},"283":{}},"tags":{}}],["need",{"_index":448,"title":{},"content":{"65":{},"67":{},"72":{},"83":{},"88":{},"90":{},"264":{},"280":{},"281":{},"284":{},"290":{},"295":{},"296":{},"308":{},"309":{},"311":{}},"tags":{}}],["nest",{"_index":547,"title":{},"content":{"270":{},"271":{}},"tags":{}}],["net_admin",{"_index":977,"title":{},"content":{"304":{}},"tags":{}}],["network",{"_index":552,"title":{},"content":{"270":{},"276":{},"278":{},"279":{},"280":{},"302":{}},"tags":{}}],["new",{"_index":430,"title":{},"content":{"94":{},"95":{},"262":{},"264":{},"266":{},"278":{},"280":{},"284":{},"301":{},"310":{},"312":{}},"tags":{}}],["newmeshcert",{"_index":496,"title":{},"content":{"266":{}},"tags":{}}],["next",{"_index":107,"title":{"237":{}},"content":{"72":{},"90":{},"94":{}},"tags":{}}],["node",{"_index":543,"title":{"296":{},"301":{}},"content":{"65":{},"83":{},"270":{},"271":{},"276":{},"288":{},"294":{},"296":{},"298":{},"301":{},"311":{},"312":{}},"tags":{}}],["node.k8s.io/v1",{"_index":904,"title":{},"content":{"295":{}},"tags":{}}],["nodepool",{"_index":1238,"title":{},"content":{"311":{}},"tags":{}}],["nodepool1",{"_index":1242,"title":{},"content":{"311":{}},"tags":{}}],["nodepool2",{"_index":1239,"title":{},"content":{"311":{}},"tags":{}}],["non",{"_index":750,"title":{},"content":{"280":{},"304":{},"311":{}},"tags":{}}],["none",{"_index":1249,"title":{},"content":{"311":{}},"tags":{}}],["northeurop",{"_index":1219,"title":{},"content":{"310":{}},"tags":{}}],["notabl",{"_index":333,"title":{},"content":{"252":{}},"tags":{}}],["note",{"_index":648,"title":{},"content":{"275":{},"304":{}},"tags":{}}],["now",{"_index":1154,"title":{},"content":{"87":{},"311":{}},"tags":{}}],["number",{"_index":484,"title":{},"content":{"266":{}},"tags":{}}],["numer",{"_index":464,"title":{},"content":{"265":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1078,"title":{},"content":{"72":{},"75":{},"86":{},"91":{}},"tags":{}}],["object",{"_index":528,"title":{},"content":{"99":{},"269":{},"302":{},"303":{}},"tags":{}}],["observ",{"_index":169,"title":{"244":{},"265":{}},"content":{"241":{},"293":{}},"tags":{}}],["obtain",{"_index":216,"title":{},"content":{"246":{},"250":{},"263":{}},"tags":{}}],["occur",{"_index":136,"title":{},"content":{"240":{}},"tags":{}}],["oci",{"_index":534,"title":{},"content":{"269":{},"270":{},"291":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"236":{},"271":{},"272":{},"281":{},"284":{}},"tags":{}}],["offlin",{"_index":306,"title":{},"content":{"249":{}},"tags":{}}],["older",{"_index":1175,"title":{},"content":{"94":{},"95":{}},"tags":{}}],["omit",{"_index":891,"title":{},"content":{"69":{},"99":{},"293":{}},"tags":{}}],["on",{"_index":281,"title":{},"content":{"248":{},"266":{},"269":{},"281":{},"305":{},"310":{}},"tags":{}}],["onc",{"_index":1004,"title":{},"content":{"65":{},"83":{}},"tags":{}}],["opa",{"_index":557,"title":{},"content":{"270":{},"286":{}},"tags":{}}],["open",{"_index":140,"title":{},"content":{"240":{},"270":{},"286":{}},"tags":{}}],["openssl",{"_index":1112,"title":{},"content":{"75":{},"91":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"235":{},"249":{},"255":{},"257":{},"267":{},"272":{},"273":{},"274":{},"276":{},"278":{},"279":{},"281":{},"283":{},"309":{}},"tags":{}}],["optim",{"_index":565,"title":{},"content":{"272":{}},"tags":{}}],["option",{"_index":542,"title":{"92":{}},"content":{"270":{},"311":{}},"tags":{}}],["orchestr",{"_index":587,"title":{},"content":{"272":{},"286":{}},"tags":{}}],["order",{"_index":890,"title":{},"content":{"70":{},"99":{},"293":{}},"tags":{}}],["origin",{"_index":553,"title":{},"content":{"68":{},"270":{},"302":{}},"tags":{}}],["os",{"_index":130,"title":{},"content":{"240":{},"275":{},"311":{}},"tags":{}}],["os.readfile(\"/tl",{"_index":1053,"title":{},"content":{"69":{}},"tags":{}}],["otherwis",{"_index":881,"title":{},"content":{"292":{},"304":{}},"tags":{}}],["out",{"_index":453,"title":{"95":{}},"content":{"95":{},"264":{},"277":{},"278":{},"280":{},"301":{},"304":{},"312":{}},"tags":{}}],["outlin",{"_index":599,"title":{},"content":{"67":{},"273":{}},"tags":{}}],["output",{"_index":1209,"title":{},"content":{"309":{}},"tags":{}}],["outsid",{"_index":859,"title":{},"content":{"290":{},"304":{}},"tags":{}}],["over",{"_index":548,"title":{},"content":{"87":{},"89":{},"270":{},"278":{},"304":{},"305":{}},"tags":{}}],["overview",{"_index":598,"title":{"273":{}},"content":{"282":{}},"tags":{}}],["own",{"_index":662,"title":{},"content":{"276":{}},"tags":{}}],["owner",{"_index":206,"title":{"250":{}},"content":{"74":{},"79":{},"246":{},"250":{},"263":{},"264":{},"274":{},"276":{},"280":{},"281":{}},"tags":{}}],["owner'",{"_index":839,"title":{},"content":{"285":{},"289":{}},"tags":{}}],["ownership",{"_index":605,"title":{},"content":{"273":{}},"tags":{}}],["owners—to",{"_index":380,"title":{},"content":{"257":{}},"tags":{}}],["p",{"_index":1089,"title":{},"content":{"75":{}},"tags":{}}],["packet",{"_index":949,"title":{},"content":{"304":{}},"tags":{}}],["page",{"_index":330,"title":{},"content":{"252":{},"282":{}},"tags":{}}],["pair",{"_index":469,"title":{},"content":{"265":{}},"tags":{}}],["paramet",{"_index":860,"title":{},"content":{"290":{},"291":{}},"tags":{}}],["pars",{"_index":762,"title":{},"content":{"280":{}},"tags":{}}],["part",{"_index":268,"title":{},"content":{"82":{},"87":{},"94":{},"248":{},"252":{},"256":{},"264":{},"275":{},"285":{},"289":{},"290":{},"295":{},"299":{},"302":{},"305":{}},"tags":{}}],["parti",{"_index":105,"title":{"250":{},"259":{}},"content":{"236":{},"246":{},"250":{},"259":{},"261":{},"263":{},"272":{},"276":{},"278":{},"281":{},"284":{},"304":{}},"tags":{}}],["particip",{"_index":853,"title":{},"content":{"289":{}},"tags":{}}],["particular",{"_index":1197,"title":{},"content":{"99":{}},"tags":{}}],["particularli",{"_index":608,"title":{},"content":{"273":{},"293":{}},"tags":{}}],["parties—such",{"_index":379,"title":{},"content":{"257":{}},"tags":{}}],["partit",{"_index":747,"title":{},"content":{"280":{},"300":{}},"tags":{}}],["pass",{"_index":265,"title":{},"content":{"248":{}},"tags":{}}],["passiv",{"_index":757,"title":{},"content":{"280":{}},"tags":{}}],["patch",{"_index":1087,"title":{},"content":{"75":{},"94":{}},"tags":{}}],["path",{"_index":1262,"title":{},"content":{"313":{}},"tags":{}}],["patient",{"_index":806,"title":{},"content":{"281":{}},"tags":{}}],["peer",{"_index":1046,"title":{},"content":{"69":{}},"tags":{}}],["pend",{"_index":1184,"title":{},"content":{"97":{}},"tags":{}}],["per",{"_index":933,"title":{},"content":{"70":{},"302":{}},"tags":{}}],["perform",{"_index":508,"title":{},"content":{"65":{},"83":{},"267":{},"279":{},"280":{},"296":{},"301":{}},"tags":{}}],["period",{"_index":704,"title":{},"content":{"278":{}},"tags":{}}],["perman",{"_index":701,"title":{},"content":{"278":{}},"tags":{}}],["permiss",{"_index":663,"title":{},"content":{"276":{},"290":{},"291":{},"308":{}},"tags":{}}],["permit",{"_index":843,"title":{},"content":{"286":{},"294":{}},"tags":{}}],["persist",{"_index":775,"title":{},"content":{"98":{},"99":{},"280":{}},"tags":{}}],["person",{"_index":602,"title":{},"content":{"273":{}},"tags":{}}],["persona",{"_index":657,"title":{"276":{}},"content":{"281":{}},"tags":{}}],["perspect",{"_index":567,"title":{"88":{}},"content":{"78":{},"272":{}},"tags":{}}],["phase",{"_index":627,"title":{},"content":{"71":{},"274":{}},"tags":{}}],["physic",{"_index":621,"title":{},"content":{"274":{},"275":{},"278":{},"279":{},"280":{}},"tags":{}}],["piec",{"_index":319,"title":{},"content":{"252":{}},"tags":{}}],["pii",{"_index":603,"title":{},"content":{"273":{}},"tags":{}}],["pki",{"_index":420,"title":{},"content":{"262":{},"272":{},"302":{}},"tags":{}}],["placehold",{"_index":1023,"title":{},"content":{"68":{}},"tags":{}}],["plain",{"_index":1033,"title":{},"content":{"69":{}},"tags":{}}],["plan",{"_index":1182,"title":{"96":{}},"content":{"96":{},"97":{}},"tags":{}}],["plane",{"_index":639,"title":{},"content":{"275":{},"279":{},"280":{}},"tags":{}}],["platform",{"_index":322,"title":{},"content":{"79":{},"97":{},"100":{},"252":{},"272":{},"274":{},"278":{}},"tags":{}}],["platform'",{"_index":794,"title":{},"content":{"281":{}},"tags":{}}],["play",{"_index":373,"title":{},"content":{"257":{}},"tags":{}}],["pleas",{"_index":1068,"title":{},"content":{"70":{},"80":{}},"tags":{}}],["plugin",{"_index":847,"title":{},"content":{"288":{},"297":{},"301":{}},"tags":{}}],["pod",{"_index":12,"title":{"248":{},"300":{}},"content":{"68":{},"72":{},"85":{},"99":{},"234":{},"248":{},"249":{},"253":{},"256":{},"264":{},"266":{},"268":{},"269":{},"270":{},"272":{},"274":{},"275":{},"284":{},"285":{},"289":{},"291":{},"292":{},"293":{},"294":{},"295":{},"298":{},"299":{},"300":{},"301":{},"305":{}},"tags":{}}],["pod'",{"_index":283,"title":{},"content":{"248":{},"261":{}},"tags":{}}],["podspec",{"_index":863,"title":{},"content":{"290":{},"291":{}},"tags":{}}],["podvm",{"_index":848,"title":{},"content":{"288":{}},"tags":{}}],["pod’",{"_index":368,"title":{},"content":{"256":{}},"tags":{}}],["point",{"_index":343,"title":{},"content":{"252":{},"279":{}},"tags":{}}],["polici",{"_index":150,"title":{"70":{},"85":{},"99":{},"253":{},"286":{},"289":{}},"content":{"68":{},"70":{},"74":{},"85":{},"89":{},"90":{},"93":{},"99":{},"240":{},"246":{},"248":{},"249":{},"252":{},"253":{},"255":{},"256":{},"270":{},"274":{},"275":{},"280":{},"283":{},"285":{},"286":{},"289":{},"290":{},"291":{},"292":{},"293":{},"294":{},"299":{}},"tags":{}}],["policy'",{"_index":279,"title":{},"content":{"248":{},"291":{},"294":{}},"tags":{}}],["pool",{"_index":561,"title":{},"content":{"271":{},"311":{},"312":{}},"tags":{}}],["popul",{"_index":862,"title":{},"content":{"69":{},"290":{}},"tags":{}}],["port",{"_index":472,"title":{},"content":{"69":{},"72":{},"98":{},"100":{},"266":{},"267":{},"303":{},"304":{},"305":{}},"tags":{}}],["port>#::###fals",{"_index":971,"title":{},"content":{"381":{}},"tags":{}}],["name>##tru",{"_index":978,"title":{},"content":{"381":{}},"tags":{}}],["namespac",{"_index":1238,"title":{},"content":{"422":{},"431":{},"434":{}},"tags":{}}],["nativ",{"_index":612,"title":{},"content":{"349":{}},"tags":{}}],["necessari",{"_index":846,"title":{},"content":{"360":{},"386":{},"389":{},"415":{}},"tags":{}}],["need",{"_index":444,"title":{},"content":{"338":{},"343":{},"344":{},"357":{},"358":{},"361":{},"367":{},"372":{},"373":{},"384":{},"386":{},"391":{},"401":{},"406":{},"407":{},"408":{},"419":{},"421":{},"422":{},"424":{}},"tags":{}}],["nest",{"_index":574,"title":{},"content":{"347":{},"348":{}},"tags":{}}],["net_admin",{"_index":996,"title":{},"content":{"381":{}},"tags":{}}],["network",{"_index":579,"title":{},"content":{"347":{},"353":{},"355":{},"356":{},"357":{},"379":{}},"tags":{}}],["new",{"_index":426,"title":{},"content":{"336":{},"338":{},"340":{},"355":{},"357":{},"361":{},"378":{},"395":{},"412":{},"413":{},"423":{},"425":{}},"tags":{}}],["newli",{"_index":1148,"title":{},"content":{"395":{}},"tags":{}}],["newmeshcert",{"_index":496,"title":{},"content":{"340":{}},"tags":{}}],["next",{"_index":107,"title":{"317":{}},"content":{"391":{},"408":{},"412":{},"434":{}},"tags":{}}],["node",{"_index":570,"title":{"373":{},"378":{}},"content":{"347":{},"348":{},"353":{},"365":{},"371":{},"373":{},"375":{},"378":{},"384":{},"401":{},"419":{},"424":{},"425":{}},"tags":{}}],["node.k8s.io/v1",{"_index":923,"title":{},"content":{"372":{}},"tags":{}}],["nodepool",{"_index":1270,"title":{},"content":{"424":{}},"tags":{}}],["nodepool1",{"_index":1273,"title":{},"content":{"424":{}},"tags":{}}],["nodepool2",{"_index":1271,"title":{},"content":{"424":{}},"tags":{}}],["non",{"_index":774,"title":{},"content":{"357":{},"381":{},"424":{}},"tags":{}}],["none",{"_index":1280,"title":{},"content":{"424":{}},"tags":{}}],["northeurop",{"_index":1252,"title":{},"content":{"423":{}},"tags":{}}],["notabl",{"_index":329,"title":{},"content":{"326":{}},"tags":{}}],["note",{"_index":675,"title":{},"content":{"352":{},"381":{}},"tags":{}}],["now",{"_index":1145,"title":{},"content":{"395":{},"405":{},"424":{}},"tags":{}}],["number",{"_index":485,"title":{},"content":{"340":{}},"tags":{}}],["numer",{"_index":463,"title":{},"content":{"339":{}},"tags":{}}],["o=jsonpath='{.spec.runtimeclassnam",{"_index":1352,"title":{},"content":{"434":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1095,"title":{},"content":{"391":{},"394":{},"404":{},"409":{}},"tags":{}}],["object",{"_index":555,"title":{},"content":{"346":{},"379":{},"380":{},"417":{},"431":{}},"tags":{}}],["observ",{"_index":455,"title":{"339":{}},"content":{"370":{}},"tags":{}}],["obtain",{"_index":208,"title":{},"content":{"320":{},"324":{},"337":{},"434":{}},"tags":{}}],["occur",{"_index":135,"title":{},"content":{"318":{}},"tags":{}}],["oci",{"_index":561,"title":{},"content":{"346":{},"347":{},"368":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"316":{},"348":{},"349":{},"358":{},"361":{}},"tags":{}}],["offlin",{"_index":300,"title":{},"content":{"323":{}},"tags":{}}],["older",{"_index":1201,"title":{},"content":{"412":{},"413":{}},"tags":{}}],["omit",{"_index":910,"title":{},"content":{"370":{},"388":{},"417":{}},"tags":{}}],["on",{"_index":273,"title":{},"content":{"322":{},"346":{},"358":{},"382":{},"419":{},"423":{},"430":{},"433":{},"434":{}},"tags":{}}],["onc",{"_index":1023,"title":{},"content":{"384":{},"401":{}},"tags":{}}],["opa",{"_index":584,"title":{},"content":{"347":{},"363":{}},"tags":{}}],["open",{"_index":139,"title":{},"content":{"318":{},"347":{},"363":{}},"tags":{}}],["openssl",{"_index":1128,"title":{},"content":{"394":{},"409":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"315":{},"323":{},"329":{},"331":{},"341":{},"349":{},"350":{},"351":{},"353":{},"355":{},"356":{},"358":{},"360":{},"395":{},"422":{}},"tags":{}}],["optim",{"_index":591,"title":{},"content":{"349":{}},"tags":{}}],["option",{"_index":569,"title":{"410":{}},"content":{"347":{},"424":{}},"tags":{}}],["orchestr",{"_index":613,"title":{},"content":{"349":{},"363":{}},"tags":{}}],["order",{"_index":533,"title":{},"content":{"343":{},"370":{},"389":{},"417":{}},"tags":{}}],["origin",{"_index":580,"title":{},"content":{"347":{},"379":{},"387":{}},"tags":{}}],["os",{"_index":129,"title":{},"content":{"318":{},"352":{},"424":{}},"tags":{}}],["os.readfile(\"/tl",{"_index":1069,"title":{},"content":{"388":{}},"tags":{}}],["otherwis",{"_index":902,"title":{},"content":{"369":{},"381":{}},"tags":{}}],["out",{"_index":449,"title":{"413":{}},"content":{"338":{},"354":{},"355":{},"357":{},"378":{},"381":{},"407":{},"413":{},"425":{}},"tags":{}}],["outlin",{"_index":626,"title":{},"content":{"350":{},"386":{}},"tags":{}}],["output",{"_index":1170,"title":{},"content":{"400":{},"422":{},"430":{},"431":{},"434":{}},"tags":{}}],["outsid",{"_index":881,"title":{},"content":{"367":{},"381":{}},"tags":{}}],["over",{"_index":575,"title":{},"content":{"347":{},"355":{},"381":{},"382":{},"405":{},"407":{}},"tags":{}}],["overview",{"_index":625,"title":{"350":{}},"content":{"359":{}},"tags":{}}],["own",{"_index":688,"title":{},"content":{"353":{}},"tags":{}}],["owner",{"_index":197,"title":{"324":{}},"content":{"320":{},"324":{},"337":{},"338":{},"342":{},"344":{},"351":{},"353":{},"357":{},"358":{},"393":{},"397":{}},"tags":{}}],["owner'",{"_index":861,"title":{},"content":{"362":{},"366":{}},"tags":{}}],["ownership",{"_index":632,"title":{},"content":{"350":{}},"tags":{}}],["owners—to",{"_index":376,"title":{},"content":{"331":{}},"tags":{}}],["p",{"_index":1106,"title":{},"content":{"394":{}},"tags":{}}],["packet",{"_index":968,"title":{},"content":{"381":{}},"tags":{}}],["page",{"_index":326,"title":{},"content":{"326":{},"359":{}},"tags":{}}],["pair",{"_index":468,"title":{},"content":{"339":{}},"tags":{}}],["paramet",{"_index":882,"title":{},"content":{"367":{},"368":{}},"tags":{}}],["pars",{"_index":786,"title":{},"content":{"357":{}},"tags":{}}],["part",{"_index":260,"title":{},"content":{"322":{},"326":{},"330":{},"338":{},"352":{},"362":{},"366":{},"367":{},"372":{},"376":{},"379":{},"382":{},"400":{},"405":{},"412":{},"430":{}},"tags":{}}],["parti",{"_index":105,"title":{"324":{},"333":{}},"content":{"316":{},"320":{},"324":{},"333":{},"335":{},"337":{},"349":{},"353":{},"355":{},"358":{},"361":{},"381":{}},"tags":{}}],["particip",{"_index":875,"title":{},"content":{"366":{}},"tags":{}}],["particular",{"_index":1227,"title":{},"content":{"417":{}},"tags":{}}],["particularli",{"_index":635,"title":{},"content":{"350":{},"370":{}},"tags":{}}],["parties—such",{"_index":375,"title":{},"content":{"331":{}},"tags":{}}],["partit",{"_index":771,"title":{},"content":{"357":{},"377":{}},"tags":{}}],["pass",{"_index":257,"title":{},"content":{"322":{},"343":{},"393":{},"395":{}},"tags":{}}],["passiv",{"_index":781,"title":{},"content":{"357":{}},"tags":{}}],["patch",{"_index":1104,"title":{},"content":{"394":{},"412":{}},"tags":{}}],["path",{"_index":1293,"title":{},"content":{"426":{}},"tags":{}}],["patient",{"_index":828,"title":{},"content":{"358":{}},"tags":{}}],["peer",{"_index":1062,"title":{},"content":{"388":{}},"tags":{}}],["pend",{"_index":1210,"title":{},"content":{"415":{}},"tags":{}}],["per",{"_index":952,"title":{},"content":{"379":{},"389":{}},"tags":{}}],["perform",{"_index":508,"title":{},"content":{"341":{},"356":{},"357":{},"373":{},"378":{},"384":{},"401":{}},"tags":{}}],["period",{"_index":729,"title":{},"content":{"355":{}},"tags":{}}],["perman",{"_index":726,"title":{},"content":{"355":{}},"tags":{}}],["permiss",{"_index":689,"title":{},"content":{"353":{},"367":{},"368":{},"421":{}},"tags":{}}],["permit",{"_index":865,"title":{},"content":{"363":{},"371":{}},"tags":{}}],["persist",{"_index":527,"title":{"343":{}},"content":{"343":{},"344":{},"357":{},"416":{},"417":{}},"tags":{}}],["person",{"_index":629,"title":{},"content":{"350":{}},"tags":{}}],["persona",{"_index":684,"title":{"353":{}},"content":{"358":{}},"tags":{}}],["perspect",{"_index":593,"title":{"406":{}},"content":{"349":{},"396":{}},"tags":{}}],["phase",{"_index":654,"title":{},"content":{"351":{},"390":{},"395":{}},"tags":{}}],["physic",{"_index":648,"title":{},"content":{"351":{},"352":{},"355":{},"356":{},"357":{}},"tags":{}}],["piec",{"_index":315,"title":{},"content":{"326":{}},"tags":{}}],["pii",{"_index":630,"title":{},"content":{"350":{}},"tags":{}}],["pin",{"_index":1333,"title":{"433":{}},"content":{"433":{}},"tags":{}}],["pki",{"_index":416,"title":{},"content":{"336":{},"349":{},"379":{}},"tags":{}}],["placehold",{"_index":1041,"title":{},"content":{"387":{}},"tags":{}}],["plain",{"_index":535,"title":{},"content":{"343":{},"388":{}},"tags":{}}],["plan",{"_index":1208,"title":{"414":{}},"content":{"414":{},"415":{},"416":{},"419":{}},"tags":{}}],["plane",{"_index":666,"title":{},"content":{"352":{},"356":{},"357":{}},"tags":{}}],["platform",{"_index":318,"title":{},"content":{"326":{},"349":{},"351":{},"355":{},"397":{},"415":{},"418":{}},"tags":{}}],["platform'",{"_index":816,"title":{},"content":{"358":{}},"tags":{}}],["play",{"_index":369,"title":{},"content":{"331":{}},"tags":{}}],["pleas",{"_index":1085,"title":{},"content":{"389":{},"398":{}},"tags":{}}],["plugin",{"_index":870,"title":{},"content":{"365":{},"374":{},"378":{}},"tags":{}}],["pod",{"_index":12,"title":{"322":{},"377":{},"431":{}},"content":{"314":{},"322":{},"323":{},"327":{},"330":{},"338":{},"340":{},"345":{},"346":{},"347":{},"349":{},"351":{},"352":{},"361":{},"362":{},"366":{},"368":{},"369":{},"370":{},"371":{},"372":{},"375":{},"376":{},"377":{},"378":{},"382":{},"387":{},"391":{},"395":{},"403":{},"417":{},"419":{},"430":{},"431":{},"433":{},"434":{}},"tags":{}}],["pod'",{"_index":275,"title":{},"content":{"322":{},"335":{}},"tags":{}}],["pod/#::###fals",{"_index":971,"title":{},"content":{"502":{}},"tags":{}}],["name>##tru",{"_index":978,"title":{},"content":{"502":{}},"tags":{}}],["namespac",{"_index":1237,"title":{},"content":{"544":{},"556":{},"559":{}},"tags":{}}],["nativ",{"_index":612,"title":{},"content":{"470":{}},"tags":{}}],["necessari",{"_index":846,"title":{},"content":{"472":{},"507":{},"510":{},"536":{}},"tags":{}}],["need",{"_index":444,"title":{},"content":{"462":{},"464":{},"465":{},"473":{},"479":{},"491":{},"492":{},"493":{},"494":{},"505":{},"507":{},"512":{},"522":{},"527":{},"528":{},"529":{},"540":{},"543":{},"544":{},"546":{}},"tags":{}}],["nest",{"_index":574,"title":{},"content":{"468":{},"469":{}},"tags":{}}],["net_admin",{"_index":996,"title":{},"content":{"502":{}},"tags":{}}],["network",{"_index":579,"title":{},"content":{"468":{},"487":{},"489":{},"490":{},"491":{},"500":{}},"tags":{}}],["new",{"_index":426,"title":{},"content":{"457":{},"460":{},"462":{},"473":{},"489":{},"491":{},"499":{},"516":{},"533":{},"534":{},"545":{},"547":{}},"tags":{}}],["newli",{"_index":1148,"title":{},"content":{"516":{}},"tags":{}}],["newmeshcert",{"_index":496,"title":{},"content":{"457":{}},"tags":{}}],["next",{"_index":107,"title":{"438":{}},"content":{"512":{},"529":{},"533":{},"559":{}},"tags":{}}],["node",{"_index":570,"title":{"494":{},"499":{}},"content":{"468":{},"469":{},"477":{},"483":{},"487":{},"494":{},"496":{},"499":{},"505":{},"522":{},"540":{},"546":{},"547":{}},"tags":{}}],["node.k8s.io/v1",{"_index":923,"title":{},"content":{"493":{}},"tags":{}}],["nodepool",{"_index":1269,"title":{},"content":{"546":{}},"tags":{}}],["nodepool1",{"_index":1272,"title":{},"content":{"546":{}},"tags":{}}],["nodepool2",{"_index":1270,"title":{},"content":{"546":{}},"tags":{}}],["non",{"_index":774,"title":{},"content":{"491":{},"502":{},"546":{}},"tags":{}}],["none",{"_index":1279,"title":{},"content":{"546":{}},"tags":{}}],["northeurop",{"_index":1251,"title":{},"content":{"545":{}},"tags":{}}],["notabl",{"_index":329,"title":{},"content":{"447":{}},"tags":{}}],["note",{"_index":675,"title":{},"content":{"486":{},"502":{}},"tags":{}}],["now",{"_index":1145,"title":{},"content":{"516":{},"526":{},"546":{}},"tags":{}}],["number",{"_index":485,"title":{},"content":{"457":{}},"tags":{}}],["numer",{"_index":463,"title":{},"content":{"456":{}},"tags":{}}],["o=jsonpath='{.spec.runtimeclassnam",{"_index":1345,"title":{},"content":{"559":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1095,"title":{},"content":{"512":{},"515":{},"525":{},"530":{}},"tags":{}}],["object",{"_index":555,"title":{},"content":{"467":{},"500":{},"501":{},"538":{},"556":{}},"tags":{}}],["observ",{"_index":455,"title":{"456":{}},"content":{"482":{}},"tags":{}}],["obtain",{"_index":208,"title":{},"content":{"441":{},"445":{},"461":{},"559":{}},"tags":{}}],["occur",{"_index":135,"title":{},"content":{"439":{}},"tags":{}}],["oci",{"_index":561,"title":{},"content":{"467":{},"468":{},"480":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"437":{},"469":{},"470":{},"473":{},"492":{}},"tags":{}}],["offlin",{"_index":300,"title":{},"content":{"444":{}},"tags":{}}],["older",{"_index":1200,"title":{},"content":{"533":{},"534":{}},"tags":{}}],["omit",{"_index":910,"title":{},"content":{"482":{},"509":{},"538":{}},"tags":{}}],["on",{"_index":273,"title":{},"content":{"443":{},"467":{},"492":{},"503":{},"540":{},"545":{},"555":{},"558":{},"559":{}},"tags":{}}],["onc",{"_index":1023,"title":{},"content":{"505":{},"522":{}},"tags":{}}],["opa",{"_index":584,"title":{},"content":{"468":{},"475":{}},"tags":{}}],["open",{"_index":139,"title":{},"content":{"439":{},"468":{},"475":{}},"tags":{}}],["openssl",{"_index":1128,"title":{},"content":{"515":{},"530":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"436":{},"444":{},"450":{},"452":{},"458":{},"470":{},"472":{},"484":{},"485":{},"487":{},"489":{},"490":{},"492":{},"516":{},"544":{}},"tags":{}}],["optim",{"_index":591,"title":{},"content":{"470":{}},"tags":{}}],["option",{"_index":569,"title":{"531":{}},"content":{"468":{},"546":{}},"tags":{}}],["orchestr",{"_index":613,"title":{},"content":{"470":{},"475":{}},"tags":{}}],["order",{"_index":533,"title":{},"content":{"464":{},"482":{},"510":{},"538":{}},"tags":{}}],["origin",{"_index":580,"title":{},"content":{"468":{},"500":{},"508":{}},"tags":{}}],["os",{"_index":129,"title":{},"content":{"439":{},"486":{},"546":{}},"tags":{}}],["os.readfile(\"/tl",{"_index":1069,"title":{},"content":{"509":{}},"tags":{}}],["otherwis",{"_index":902,"title":{},"content":{"481":{},"502":{}},"tags":{}}],["out",{"_index":449,"title":{"534":{}},"content":{"462":{},"488":{},"489":{},"491":{},"499":{},"502":{},"528":{},"534":{},"547":{}},"tags":{}}],["outlin",{"_index":626,"title":{},"content":{"484":{},"507":{}},"tags":{}}],["output",{"_index":1170,"title":{},"content":{"521":{},"544":{},"555":{},"556":{},"559":{}},"tags":{}}],["outsid",{"_index":881,"title":{},"content":{"479":{},"502":{}},"tags":{}}],["over",{"_index":575,"title":{},"content":{"468":{},"489":{},"502":{},"503":{},"526":{},"528":{}},"tags":{}}],["overview",{"_index":625,"title":{"484":{}},"content":{"471":{}},"tags":{}}],["own",{"_index":688,"title":{},"content":{"487":{}},"tags":{}}],["owner",{"_index":197,"title":{"445":{}},"content":{"441":{},"445":{},"461":{},"462":{},"463":{},"465":{},"485":{},"487":{},"491":{},"492":{},"514":{},"518":{}},"tags":{}}],["owner'",{"_index":861,"title":{},"content":{"474":{},"478":{}},"tags":{}}],["ownership",{"_index":632,"title":{},"content":{"484":{}},"tags":{}}],["owners—to",{"_index":376,"title":{},"content":{"452":{}},"tags":{}}],["p",{"_index":1106,"title":{},"content":{"515":{}},"tags":{}}],["packet",{"_index":968,"title":{},"content":{"502":{}},"tags":{}}],["page",{"_index":326,"title":{},"content":{"447":{},"471":{}},"tags":{}}],["pair",{"_index":468,"title":{},"content":{"456":{}},"tags":{}}],["paramet",{"_index":882,"title":{},"content":{"479":{},"480":{}},"tags":{}}],["pars",{"_index":786,"title":{},"content":{"491":{}},"tags":{}}],["part",{"_index":260,"title":{},"content":{"443":{},"447":{},"451":{},"462":{},"474":{},"478":{},"479":{},"486":{},"493":{},"497":{},"500":{},"503":{},"521":{},"526":{},"533":{},"555":{}},"tags":{}}],["parti",{"_index":105,"title":{"445":{},"454":{}},"content":{"437":{},"441":{},"445":{},"454":{},"459":{},"461":{},"470":{},"473":{},"487":{},"489":{},"492":{},"502":{}},"tags":{}}],["particip",{"_index":875,"title":{},"content":{"478":{}},"tags":{}}],["particular",{"_index":1226,"title":{},"content":{"538":{}},"tags":{}}],["particularli",{"_index":635,"title":{},"content":{"482":{},"484":{}},"tags":{}}],["parties—such",{"_index":375,"title":{},"content":{"452":{}},"tags":{}}],["partit",{"_index":771,"title":{},"content":{"491":{},"498":{}},"tags":{}}],["pass",{"_index":257,"title":{},"content":{"443":{},"464":{},"514":{},"516":{}},"tags":{}}],["passiv",{"_index":781,"title":{},"content":{"491":{}},"tags":{}}],["patch",{"_index":1104,"title":{},"content":{"515":{},"533":{}},"tags":{}}],["path",{"_index":1292,"title":{},"content":{"541":{}},"tags":{}}],["patient",{"_index":828,"title":{},"content":{"492":{}},"tags":{}}],["peer",{"_index":1062,"title":{},"content":{"509":{}},"tags":{}}],["pend",{"_index":1209,"title":{},"content":{"536":{}},"tags":{}}],["per",{"_index":952,"title":{},"content":{"500":{},"510":{}},"tags":{}}],["perform",{"_index":508,"title":{},"content":{"458":{},"490":{},"491":{},"494":{},"499":{},"505":{},"522":{}},"tags":{}}],["period",{"_index":729,"title":{},"content":{"489":{}},"tags":{}}],["perman",{"_index":726,"title":{},"content":{"489":{}},"tags":{}}],["permiss",{"_index":689,"title":{},"content":{"479":{},"480":{},"487":{},"543":{}},"tags":{}}],["permit",{"_index":865,"title":{},"content":{"475":{},"483":{}},"tags":{}}],["persist",{"_index":527,"title":{"464":{}},"content":{"464":{},"465":{},"491":{},"537":{},"538":{}},"tags":{}}],["person",{"_index":629,"title":{},"content":{"484":{}},"tags":{}}],["persona",{"_index":684,"title":{"487":{}},"content":{"492":{}},"tags":{}}],["perspect",{"_index":593,"title":{"527":{}},"content":{"470":{},"517":{}},"tags":{}}],["phase",{"_index":654,"title":{},"content":{"485":{},"511":{},"516":{}},"tags":{}}],["physic",{"_index":648,"title":{},"content":{"485":{},"486":{},"489":{},"490":{},"491":{}},"tags":{}}],["piec",{"_index":315,"title":{},"content":{"447":{}},"tags":{}}],["pii",{"_index":630,"title":{},"content":{"484":{}},"tags":{}}],["pin",{"_index":1332,"title":{"558":{}},"content":{"558":{}},"tags":{}}],["pki",{"_index":416,"title":{},"content":{"460":{},"470":{},"500":{}},"tags":{}}],["placehold",{"_index":1041,"title":{},"content":{"508":{}},"tags":{}}],["plain",{"_index":535,"title":{},"content":{"464":{},"509":{}},"tags":{}}],["plan",{"_index":1207,"title":{"535":{}},"content":{"535":{},"536":{},"537":{},"540":{}},"tags":{}}],["plane",{"_index":666,"title":{},"content":{"486":{},"490":{},"491":{}},"tags":{}}],["platform",{"_index":318,"title":{},"content":{"447":{},"470":{},"485":{},"489":{},"518":{},"524":{},"536":{},"539":{}},"tags":{}}],["platform'",{"_index":816,"title":{},"content":{"492":{}},"tags":{}}],["play",{"_index":369,"title":{},"content":{"452":{}},"tags":{}}],["pleas",{"_index":1085,"title":{},"content":{"510":{},"519":{}},"tags":{}}],["plugin",{"_index":870,"title":{},"content":{"477":{},"495":{},"499":{}},"tags":{}}],["pod",{"_index":12,"title":{"443":{},"498":{},"556":{}},"content":{"435":{},"443":{},"444":{},"448":{},"451":{},"457":{},"462":{},"466":{},"467":{},"468":{},"470":{},"473":{},"474":{},"478":{},"480":{},"481":{},"482":{},"483":{},"485":{},"486":{},"493":{},"496":{},"497":{},"498":{},"499":{},"503":{},"508":{},"512":{},"516":{},"524":{},"538":{},"540":{},"555":{},"556":{},"558":{},"559":{}},"tags":{}}],["pod'",{"_index":275,"title":{},"content":{"443":{},"459":{}},"tags":{}}],["pod/#::/secrets/workload",{"_index":543,"title":{},"content":{"587":{}},"tags":{}}],["move",{"_index":91,"title":{},"content":{"550":{},"792":{}},"tags":{}}],["mtl",{"_index":414,"title":{},"content":{"577":{},"592":{},"738":{},"764":{}},"tags":{}}],["multi",{"_index":104,"title":{},"content":{"550":{},"710":{}},"tags":{}}],["multipl",{"_index":976,"title":{},"content":{"740":{},"741":{}},"tags":{}}],["mutual",{"_index":430,"title":{},"content":{"579":{},"592":{},"712":{},"738":{}},"tags":{}}],["my_resource_dir",{"_index":1036,"title":{},"content":{"746":{}},"tags":{}}],["my_servic",{"_index":1108,"title":{},"content":{"753":{}},"tags":{}}],["n",{"_index":1323,"title":{},"content":{"790":{},"793":{}},"tags":{}}],["name",{"_index":465,"title":{},"content":{"581":{},"582":{},"731":{},"740":{},"741":{},"746":{},"748":{},"753":{},"766":{},"769":{},"781":{},"782":{},"783":{},"784":{},"789":{},"790":{},"793":{}},"tags":{}}],["name>###fals",{"_index":975,"title":{},"content":{"740":{}},"tags":{}}],["name>##tru",{"_index":982,"title":{},"content":{"740":{}},"tags":{}}],["namespac",{"_index":1241,"title":{},"content":{"781":{},"790":{},"793":{}},"tags":{}}],["nativ",{"_index":618,"title":{},"content":{"592":{}},"tags":{}}],["necessari",{"_index":851,"title":{},"content":{"719":{},"745":{},"748":{},"774":{}},"tags":{}}],["need",{"_index":444,"title":{},"content":{"580":{},"585":{},"586":{},"716":{},"717":{},"720":{},"726":{},"731":{},"732":{},"743":{},"745":{},"750":{},"760":{},"765":{},"766":{},"767":{},"778":{},"780":{},"781":{},"783":{}},"tags":{}}],["nest",{"_index":580,"title":{},"content":{"590":{},"591":{}},"tags":{}}],["net_admin",{"_index":1000,"title":{},"content":{"740":{}},"tags":{}}],["network",{"_index":585,"title":{},"content":{"590":{},"712":{},"714":{},"715":{},"716":{},"738":{}},"tags":{}}],["new",{"_index":426,"title":{},"content":{"578":{},"580":{},"582":{},"714":{},"716":{},"720":{},"737":{},"754":{},"771":{},"772":{},"782":{},"784":{}},"tags":{}}],["newli",{"_index":1151,"title":{},"content":{"754":{}},"tags":{}}],["newmeshcert",{"_index":496,"title":{},"content":{"582":{}},"tags":{}}],["next",{"_index":107,"title":{"551":{}},"content":{"750":{},"767":{},"771":{},"793":{}},"tags":{}}],["node",{"_index":576,"title":{"732":{},"737":{}},"content":{"590":{},"591":{},"712":{},"724":{},"730":{},"732":{},"734":{},"737":{},"743":{},"760":{},"778":{},"783":{},"784":{}},"tags":{}}],["node.k8s.io/v1",{"_index":927,"title":{},"content":{"731":{}},"tags":{}}],["nodepool",{"_index":1273,"title":{},"content":{"783":{}},"tags":{}}],["nodepool1",{"_index":1276,"title":{},"content":{"783":{}},"tags":{}}],["nodepool2",{"_index":1274,"title":{},"content":{"783":{}},"tags":{}}],["non",{"_index":780,"title":{},"content":{"716":{},"740":{},"783":{}},"tags":{}}],["none",{"_index":1283,"title":{},"content":{"783":{}},"tags":{}}],["northeurop",{"_index":1255,"title":{},"content":{"782":{}},"tags":{}}],["notabl",{"_index":329,"title":{},"content":{"568":{}},"tags":{}}],["note",{"_index":681,"title":{},"content":{"711":{},"740":{}},"tags":{}}],["now",{"_index":1148,"title":{},"content":{"754":{},"764":{},"783":{}},"tags":{}}],["number",{"_index":485,"title":{},"content":{"582":{}},"tags":{}}],["numer",{"_index":463,"title":{},"content":{"581":{}},"tags":{}}],["o=jsonpath='{.spec.runtimeclassnam",{"_index":1348,"title":{},"content":{"793":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1098,"title":{},"content":{"750":{},"753":{},"763":{},"768":{}},"tags":{}}],["object",{"_index":561,"title":{},"content":{"589":{},"738":{},"739":{},"776":{},"790":{}},"tags":{}}],["observ",{"_index":455,"title":{"581":{}},"content":{"729":{}},"tags":{}}],["obtain",{"_index":208,"title":{},"content":{"562":{},"566":{},"579":{},"793":{}},"tags":{}}],["occur",{"_index":135,"title":{},"content":{"560":{}},"tags":{}}],["oci",{"_index":567,"title":{},"content":{"589":{},"590":{},"727":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"550":{},"591":{},"592":{},"717":{},"720":{}},"tags":{}}],["offlin",{"_index":300,"title":{},"content":{"565":{}},"tags":{}}],["older",{"_index":1204,"title":{},"content":{"771":{},"772":{}},"tags":{}}],["omit",{"_index":914,"title":{},"content":{"729":{},"747":{},"776":{}},"tags":{}}],["on",{"_index":273,"title":{},"content":{"564":{},"589":{},"717":{},"741":{},"778":{},"782":{},"789":{},"792":{},"793":{}},"tags":{}}],["onc",{"_index":1025,"title":{},"content":{"743":{},"760":{}},"tags":{}}],["opa",{"_index":590,"title":{},"content":{"590":{},"722":{}},"tags":{}}],["open",{"_index":139,"title":{},"content":{"560":{},"590":{},"722":{}},"tags":{}}],["openssl",{"_index":1131,"title":{},"content":{"753":{},"768":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"549":{},"565":{},"571":{},"573":{},"583":{},"592":{},"709":{},"710":{},"712":{},"714":{},"715":{},"717":{},"719":{},"754":{},"781":{}},"tags":{}}],["optim",{"_index":597,"title":{},"content":{"592":{}},"tags":{}}],["option",{"_index":575,"title":{"769":{}},"content":{"590":{},"783":{}},"tags":{}}],["orchestr",{"_index":619,"title":{},"content":{"592":{},"722":{}},"tags":{}}],["order",{"_index":533,"title":{},"content":{"585":{},"729":{},"748":{},"776":{}},"tags":{}}],["origin",{"_index":586,"title":{},"content":{"590":{},"738":{},"746":{}},"tags":{}}],["os",{"_index":129,"title":{},"content":{"560":{},"711":{},"783":{}},"tags":{}}],["os.readfile(\"/contrast/tl",{"_index":1071,"title":{},"content":{"747":{}},"tags":{}}],["otherwis",{"_index":906,"title":{},"content":{"728":{},"740":{}},"tags":{}}],["out",{"_index":449,"title":{"772":{}},"content":{"580":{},"713":{},"714":{},"716":{},"737":{},"740":{},"766":{},"772":{},"784":{}},"tags":{}}],["outlin",{"_index":632,"title":{},"content":{"709":{},"745":{}},"tags":{}}],["output",{"_index":1173,"title":{},"content":{"759":{},"781":{},"789":{},"790":{},"793":{}},"tags":{}}],["outsid",{"_index":885,"title":{},"content":{"726":{},"740":{}},"tags":{}}],["over",{"_index":581,"title":{},"content":{"590":{},"714":{},"740":{},"741":{},"764":{},"766":{}},"tags":{}}],["overview",{"_index":631,"title":{"709":{}},"content":{"718":{}},"tags":{}}],["own",{"_index":694,"title":{},"content":{"712":{}},"tags":{}}],["owner",{"_index":197,"title":{"566":{}},"content":{"562":{},"566":{},"579":{},"580":{},"584":{},"586":{},"587":{},"710":{},"712":{},"716":{},"717":{},"752":{},"756":{}},"tags":{}}],["owner'",{"_index":865,"title":{},"content":{"721":{},"725":{}},"tags":{}}],["ownership",{"_index":638,"title":{},"content":{"709":{}},"tags":{}}],["owners—to",{"_index":376,"title":{},"content":{"573":{}},"tags":{}}],["p",{"_index":1109,"title":{},"content":{"753":{}},"tags":{}}],["packet",{"_index":972,"title":{},"content":{"740":{}},"tags":{}}],["page",{"_index":326,"title":{},"content":{"568":{},"718":{}},"tags":{}}],["pair",{"_index":468,"title":{},"content":{"581":{}},"tags":{}}],["paramet",{"_index":886,"title":{},"content":{"726":{},"727":{}},"tags":{}}],["pars",{"_index":792,"title":{},"content":{"716":{}},"tags":{}}],["part",{"_index":260,"title":{},"content":{"564":{},"568":{},"572":{},"580":{},"711":{},"721":{},"725":{},"726":{},"731":{},"735":{},"738":{},"741":{},"759":{},"764":{},"771":{},"789":{}},"tags":{}}],["parti",{"_index":105,"title":{"566":{},"575":{}},"content":{"550":{},"562":{},"566":{},"575":{},"577":{},"579":{},"592":{},"712":{},"714":{},"717":{},"720":{},"740":{}},"tags":{}}],["particip",{"_index":879,"title":{},"content":{"725":{}},"tags":{}}],["particular",{"_index":1230,"title":{},"content":{"776":{}},"tags":{}}],["particularli",{"_index":641,"title":{},"content":{"709":{},"729":{}},"tags":{}}],["parties—such",{"_index":375,"title":{},"content":{"573":{}},"tags":{}}],["partit",{"_index":777,"title":{},"content":{"716":{},"736":{}},"tags":{}}],["pass",{"_index":257,"title":{},"content":{"564":{},"585":{},"752":{},"754":{}},"tags":{}}],["passiv",{"_index":787,"title":{},"content":{"716":{}},"tags":{}}],["patch",{"_index":1107,"title":{},"content":{"753":{},"771":{}},"tags":{}}],["path",{"_index":542,"title":{},"content":{"587":{},"785":{}},"tags":{}}],["patient",{"_index":833,"title":{},"content":{"717":{}},"tags":{}}],["peer",{"_index":1064,"title":{},"content":{"747":{}},"tags":{}}],["pend",{"_index":1213,"title":{},"content":{"774":{}},"tags":{}}],["per",{"_index":956,"title":{},"content":{"738":{},"748":{}},"tags":{}}],["perform",{"_index":508,"title":{},"content":{"583":{},"715":{},"716":{},"732":{},"737":{},"743":{},"760":{}},"tags":{}}],["period",{"_index":735,"title":{},"content":{"714":{}},"tags":{}}],["perman",{"_index":732,"title":{},"content":{"714":{}},"tags":{}}],["permiss",{"_index":695,"title":{},"content":{"712":{},"726":{},"727":{},"780":{}},"tags":{}}],["permit",{"_index":869,"title":{},"content":{"722":{},"730":{}},"tags":{}}],["persist",{"_index":527,"title":{"585":{}},"content":{"585":{},"586":{},"587":{},"716":{},"775":{},"776":{}},"tags":{}}],["person",{"_index":635,"title":{},"content":{"709":{}},"tags":{}}],["persona",{"_index":690,"title":{"712":{}},"content":{"717":{}},"tags":{}}],["perspect",{"_index":599,"title":{"765":{}},"content":{"592":{},"755":{}},"tags":{}}],["phase",{"_index":660,"title":{},"content":{"710":{},"749":{},"754":{}},"tags":{}}],["physic",{"_index":654,"title":{},"content":{"710":{},"711":{},"714":{},"715":{},"716":{}},"tags":{}}],["piec",{"_index":315,"title":{},"content":{"568":{}},"tags":{}}],["pii",{"_index":636,"title":{},"content":{"709":{}},"tags":{}}],["pin",{"_index":1335,"title":{"792":{}},"content":{"792":{}},"tags":{}}],["pki",{"_index":416,"title":{},"content":{"578":{},"592":{},"738":{}},"tags":{}}],["placehold",{"_index":1043,"title":{},"content":{"746":{}},"tags":{}}],["plain",{"_index":535,"title":{},"content":{"585":{},"747":{}},"tags":{}}],["plan",{"_index":1211,"title":{"773":{}},"content":{"773":{},"774":{},"775":{},"778":{}},"tags":{}}],["plane",{"_index":672,"title":{},"content":{"711":{},"715":{},"716":{}},"tags":{}}],["platform",{"_index":318,"title":{},"content":{"568":{},"592":{},"710":{},"714":{},"756":{},"762":{},"774":{},"777":{}},"tags":{}}],["platform'",{"_index":821,"title":{},"content":{"717":{}},"tags":{}}],["play",{"_index":369,"title":{},"content":{"573":{}},"tags":{}}],["pleas",{"_index":1088,"title":{},"content":{"748":{},"757":{}},"tags":{}}],["plugin",{"_index":874,"title":{},"content":{"724":{},"733":{},"737":{}},"tags":{}}],["pod",{"_index":12,"title":{"564":{},"736":{},"790":{}},"content":{"548":{},"564":{},"565":{},"569":{},"572":{},"580":{},"582":{},"588":{},"589":{},"590":{},"592":{},"710":{},"711":{},"720":{},"721":{},"725":{},"727":{},"728":{},"729":{},"730":{},"731":{},"734":{},"735":{},"736":{},"737":{},"741":{},"746":{},"750":{},"754":{},"762":{},"776":{},"778":{},"789":{},"790":{},"792":{},"793":{}},"tags":{}}],["pod'",{"_index":275,"title":{},"content":{"564":{},"577":{}},"tags":{}}],["pod/#::/secrets/workload",{"_index":547,"title":{},"content":{"825":{}},"tags":{}}],["move",{"_index":91,"title":{},"content":{"796":{},"926":{}},"tags":{}}],["mrconfigid",{"_index":270,"title":{},"content":{"802":{},"857":{}},"tags":{}}],["mrseam",{"_index":1159,"title":{},"content":{"879":{},"892":{}},"tags":{}}],["mtl",{"_index":418,"title":{},"content":{"815":{},"837":{},"868":{},"894":{}},"tags":{}}],["multi",{"_index":104,"title":{},"content":{"796":{},"839":{}},"tags":{}}],["multipl",{"_index":1040,"title":{},"content":{"870":{},"871":{}},"tags":{}}],["mutabl",{"_index":599,"title":{},"content":{"831":{}},"tags":{}}],["mutual",{"_index":434,"title":{},"content":{"817":{},"837":{},"841":{},"868":{}},"tags":{}}],["my_resource_dir",{"_index":1103,"title":{},"content":{"877":{}},"tags":{}}],["my_servic",{"_index":1181,"title":{},"content":{"884":{}},"tags":{}}],["n",{"_index":1420,"title":{},"content":{"924":{},"927":{}},"tags":{}}],["name",{"_index":469,"title":{},"content":{"819":{},"820":{},"861":{},"870":{},"871":{},"877":{},"879":{},"884":{},"896":{},"899":{},"915":{},"916":{},"917":{},"918":{},"923":{},"924":{},"927":{}},"tags":{}}],["name>###fals",{"_index":1039,"title":{},"content":{"870":{}},"tags":{}}],["name>##tru",{"_index":1045,"title":{},"content":{"870":{}},"tags":{}}],["namespac",{"_index":1345,"title":{},"content":{"915":{},"924":{},"927":{}},"tags":{}}],["nativ",{"_index":633,"title":{},"content":{"832":{},"837":{}},"tags":{}}],["necessari",{"_index":920,"title":{},"content":{"848":{},"875":{},"879":{},"904":{}},"tags":{}}],["need",{"_index":448,"title":{},"content":{"818":{},"823":{},"824":{},"826":{},"831":{},"845":{},"846":{},"849":{},"855":{},"860":{},"861":{},"862":{},"873":{},"875":{},"881":{},"890":{},"895":{},"896":{},"897":{},"908":{},"915":{}},"tags":{}}],["nest",{"_index":675,"title":{},"content":{"835":{},"836":{}},"tags":{}}],["net_admin",{"_index":1063,"title":{},"content":{"870":{}},"tags":{}}],["network",{"_index":570,"title":{},"content":{"828":{},"835":{},"841":{},"843":{},"844":{},"845":{},"868":{}},"tags":{}}],["new",{"_index":430,"title":{},"content":{"816":{},"818":{},"820":{},"843":{},"845":{},"849":{},"867":{},"885":{},"901":{},"902":{},"916":{},"918":{}},"tags":{}}],["newer",{"_index":1304,"title":{},"content":{"910":{},"914":{}},"tags":{}}],["newli",{"_index":1221,"title":{},"content":{"885":{}},"tags":{}}],["newmeshcert",{"_index":500,"title":{},"content":{"820":{}},"tags":{}}],["next",{"_index":107,"title":{"797":{}},"content":{"881":{},"897":{},"901":{},"927":{}},"tags":{}}],["node",{"_index":672,"title":{"862":{},"867":{}},"content":{"835":{},"836":{},"841":{},"853":{},"859":{},"862":{},"864":{},"867":{},"873":{},"890":{},"908":{},"917":{},"918":{}},"tags":{}}],["node.k8s.io/v1",{"_index":993,"title":{},"content":{"861":{}},"tags":{}}],["nodepool1",{"_index":1379,"title":{},"content":{"917":{}},"tags":{}}],["non",{"_index":853,"title":{},"content":{"845":{},"870":{},"910":{}},"tags":{}}],["none",{"_index":1383,"title":{},"content":{"917":{}},"tags":{}}],["northeurop",{"_index":1359,"title":{},"content":{"916":{}},"tags":{}}],["notabl",{"_index":333,"title":{},"content":{"806":{}},"tags":{}}],["note",{"_index":767,"title":{},"content":{"840":{},"870":{},"879":{},"892":{},"911":{},"914":{}},"tags":{}}],["now",{"_index":631,"title":{},"content":{"832":{},"885":{},"894":{},"917":{}},"tags":{}}],["number",{"_index":489,"title":{},"content":{"820":{},"910":{}},"tags":{}}],["numer",{"_index":467,"title":{},"content":{"819":{}},"tags":{}}],["nydu",{"_index":1012,"title":{},"content":{"865":{}},"tags":{}}],["o=jsonpath='{.spec.runtimeclassnam",{"_index":1442,"title":{},"content":{"927":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1171,"title":{},"content":{"881":{},"884":{},"893":{},"898":{}},"tags":{}}],["object",{"_index":658,"title":{},"content":{"834":{},"868":{},"869":{},"906":{},"924":{}},"tags":{}}],["observ",{"_index":459,"title":{"819":{}},"content":{"858":{},"879":{},"892":{}},"tags":{}}],["obtain",{"_index":208,"title":{},"content":{"800":{},"804":{},"817":{},"927":{}},"tags":{}}],["occur",{"_index":135,"title":{},"content":{"798":{}},"tags":{}}],["oci",{"_index":664,"title":{},"content":{"834":{},"835":{},"856":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"796":{},"836":{},"837":{},"846":{},"849":{}},"tags":{}}],["offlin",{"_index":304,"title":{},"content":{"803":{}},"tags":{}}],["older",{"_index":1272,"title":{},"content":{"901":{},"902":{}},"tags":{}}],["omit",{"_index":978,"title":{},"content":{"858":{},"878":{},"906":{}},"tags":{}}],["on",{"_index":276,"title":{},"content":{"802":{},"834":{},"846":{},"871":{},"908":{},"916":{},"923":{},"926":{},"927":{}},"tags":{}}],["onc",{"_index":1088,"title":{},"content":{"873":{},"890":{}},"tags":{}}],["opa",{"_index":684,"title":{},"content":{"835":{},"851":{}},"tags":{}}],["open",{"_index":139,"title":{},"content":{"798":{},"835":{},"851":{}},"tags":{}}],["openssl",{"_index":1203,"title":{},"content":{"884":{},"898":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"795":{},"803":{},"809":{},"811":{},"821":{},"837":{},"838":{},"839":{},"841":{},"843":{},"844":{},"846":{},"848":{},"885":{},"915":{}},"tags":{}}],["optim",{"_index":691,"title":{},"content":{"837":{}},"tags":{}}],["option",{"_index":671,"title":{"899":{}},"content":{"835":{}},"tags":{}}],["orchestr",{"_index":711,"title":{},"content":{"837":{},"851":{}},"tags":{}}],["order",{"_index":537,"title":{},"content":{"823":{},"858":{},"879":{},"906":{}},"tags":{}}],["origin",{"_index":680,"title":{},"content":{"835":{},"868":{},"877":{}},"tags":{}}],["os",{"_index":129,"title":{},"content":{"798":{},"840":{},"917":{}},"tags":{}}],["os.readfile(\"/contrast/tl",{"_index":1136,"title":{},"content":{"878":{}},"tags":{}}],["otherwis",{"_index":970,"title":{},"content":{"857":{},"870":{}},"tags":{}}],["out",{"_index":453,"title":{"902":{}},"content":{"818":{},"832":{},"842":{},"843":{},"845":{},"867":{},"870":{},"896":{},"902":{},"918":{}},"tags":{}}],["outdat",{"_index":1340,"title":{},"content":{"914":{}},"tags":{}}],["outlin",{"_index":557,"title":{},"content":{"826":{},"838":{},"875":{}},"tags":{}}],["output",{"_index":1241,"title":{},"content":{"889":{},"915":{},"923":{},"924":{},"927":{}},"tags":{}}],["outsid",{"_index":554,"title":{},"content":{"826":{},"828":{},"855":{},"870":{}},"tags":{}}],["over",{"_index":676,"title":{},"content":{"835":{},"843":{},"870":{},"871":{},"894":{},"896":{}},"tags":{}}],["overview",{"_index":721,"title":{"838":{}},"content":{"847":{}},"tags":{}}],["overwritten",{"_index":987,"title":{},"content":{"860":{},"882":{},"883":{},"885":{},"893":{},"896":{},"901":{}},"tags":{}}],["own",{"_index":778,"title":{},"content":{"841":{}},"tags":{}}],["owner",{"_index":197,"title":{"804":{}},"content":{"800":{},"804":{},"817":{},"818":{},"822":{},"824":{},"825":{},"839":{},"841":{},"845":{},"846":{},"883":{}},"tags":{}}],["owner'",{"_index":933,"title":{},"content":{"850":{},"854":{}},"tags":{}}],["ownership",{"_index":727,"title":{},"content":{"838":{}},"tags":{}}],["owners—to",{"_index":380,"title":{},"content":{"811":{}},"tags":{}}],["p",{"_index":1182,"title":{},"content":{"884":{}},"tags":{}}],["packag",{"_index":1339,"title":{},"content":{"914":{}},"tags":{}}],["packet",{"_index":1037,"title":{},"content":{"870":{}},"tags":{}}],["page",{"_index":330,"title":{},"content":{"806":{},"826":{},"847":{}},"tags":{}}],["pair",{"_index":472,"title":{},"content":{"819":{}},"tags":{}}],["paramet",{"_index":953,"title":{},"content":{"855":{},"856":{}},"tags":{}}],["pars",{"_index":864,"title":{},"content":{"845":{}},"tags":{}}],["part",{"_index":260,"title":{},"content":{"802":{},"806":{},"810":{},"818":{},"840":{},"850":{},"854":{},"855":{},"861":{},"865":{},"868":{},"871":{},"889":{},"894":{},"901":{},"923":{}},"tags":{}}],["parti",{"_index":105,"title":{"804":{},"813":{}},"content":{"796":{},"800":{},"804":{},"813":{},"815":{},"817":{},"837":{},"841":{},"843":{},"846":{},"849":{},"870":{}},"tags":{}}],["particip",{"_index":947,"title":{},"content":{"854":{}},"tags":{}}],["particular",{"_index":1296,"title":{},"content":{"906":{}},"tags":{}}],["particularli",{"_index":610,"title":{},"content":{"831":{},"838":{},"858":{}},"tags":{}}],["parties—such",{"_index":379,"title":{},"content":{"811":{}},"tags":{}}],["partit",{"_index":851,"title":{},"content":{"845":{},"866":{}},"tags":{}}],["pass",{"_index":257,"title":{},"content":{"802":{},"823":{},"883":{},"885":{}},"tags":{}}],["passiv",{"_index":860,"title":{},"content":{"845":{}},"tags":{}}],["patch",{"_index":1180,"title":{},"content":{"884":{},"901":{},"910":{}},"tags":{}}],["path",{"_index":546,"title":{},"content":{"825":{},"919":{}},"tags":{}}],["patient",{"_index":902,"title":{},"content":{"846":{}},"tags":{}}],["peer",{"_index":564,"title":{},"content":{"828":{},"878":{}},"tags":{}}],["pend",{"_index":1281,"title":{},"content":{"904":{}},"tags":{}}],["per",{"_index":597,"title":{},"content":{"831":{},"868":{},"879":{}},"tags":{}}],["perform",{"_index":512,"title":{},"content":{"821":{},"844":{},"845":{},"862":{},"867":{},"873":{},"890":{}},"tags":{}}],["period",{"_index":814,"title":{},"content":{"843":{}},"tags":{}}],["perman",{"_index":811,"title":{},"content":{"843":{}},"tags":{}}],["permiss",{"_index":779,"title":{},"content":{"841":{},"855":{},"856":{}},"tags":{}}],["permit",{"_index":937,"title":{},"content":{"851":{},"859":{}},"tags":{}}],["persist",{"_index":531,"title":{"823":{}},"content":{"823":{},"824":{},"825":{},"829":{},"831":{},"845":{},"905":{},"906":{}},"tags":{}}],["person",{"_index":724,"title":{},"content":{"838":{}},"tags":{}}],["persona",{"_index":775,"title":{"841":{}},"content":{"846":{}},"tags":{}}],["perspect",{"_index":590,"title":{},"content":{"831":{},"837":{},"886":{}},"tags":{}}],["phase",{"_index":748,"title":{},"content":{"839":{},"880":{},"885":{}},"tags":{}}],["physic",{"_index":742,"title":{},"content":{"839":{},"840":{},"843":{},"844":{},"845":{}},"tags":{}}],["piec",{"_index":319,"title":{},"content":{"806":{}},"tags":{}}],["pii",{"_index":725,"title":{},"content":{"838":{}},"tags":{}}],["pin",{"_index":605,"title":{"926":{}},"content":{"831":{},"926":{}},"tags":{}}],["pipe",{"_index":640,"title":{},"content":{"832":{}},"tags":{}}],["pki",{"_index":420,"title":{},"content":{"816":{},"828":{},"837":{},"868":{}},"tags":{}}],["place",{"_index":1314,"title":{},"content":{"910":{}},"tags":{}}],["placehold",{"_index":1110,"title":{},"content":{"877":{}},"tags":{}}],["plain",{"_index":539,"title":{},"content":{"823":{},"878":{}},"tags":{}}],["plan",{"_index":1279,"title":{"903":{}},"content":{"903":{},"904":{},"905":{},"908":{}},"tags":{}}],["plane",{"_index":760,"title":{},"content":{"840":{},"844":{},"845":{}},"tags":{}}],["platform",{"_index":322,"title":{"860":{}},"content":{"806":{},"837":{},"839":{},"843":{},"860":{},"879":{},"892":{},"904":{},"907":{}},"tags":{}}],["platform'",{"_index":890,"title":{},"content":{"846":{}},"tags":{}}],["play",{"_index":373,"title":{},"content":{"811":{}},"tags":{}}],["pleas",{"_index":1162,"title":{},"content":{"879":{}},"tags":{}}],["plugin",{"_index":942,"title":{},"content":{"853":{},"863":{},"867":{}},"tags":{}}],["pod",{"_index":12,"title":{"802":{},"866":{},"924":{}},"content":{"794":{},"802":{},"803":{},"807":{},"810":{},"818":{},"820":{},"831":{},"833":{},"834":{},"835":{},"837":{},"839":{},"840":{},"849":{},"850":{},"854":{},"856":{},"857":{},"858":{},"859":{},"861":{},"864":{},"865":{},"866":{},"867":{},"871":{},"877":{},"881":{},"885":{},"892":{},"906":{},"908":{},"923":{},"924":{},"926":{},"927":{}},"tags":{}}],["pod'",{"_index":279,"title":{},"content":{"802":{},"815":{}},"tags":{}}],["pod/#::###fals",{"_index":1062,"title":{},"content":{"1034":{}},"tags":{}}],["name>##tru",{"_index":1068,"title":{},"content":{"1034":{}},"tags":{}}],["namespac",{"_index":1385,"title":{},"content":{"1094":{},"1103":{},"1106":{}},"tags":{}}],["nativ",{"_index":638,"title":{},"content":{"996":{},"1001":{}},"tags":{}}],["necessari",{"_index":541,"title":{},"content":{"989":{},"1012":{},"1039":{},"1043":{},"1075":{},"1082":{}},"tags":{}}],["need",{"_index":385,"title":{},"content":{"981":{},"986":{},"987":{},"989":{},"990":{},"995":{},"1009":{},"1010":{},"1013":{},"1019":{},"1024":{},"1025":{},"1026":{},"1037":{},"1039":{},"1045":{},"1054":{},"1059":{},"1060":{},"1061":{},"1071":{},"1076":{},"1077":{},"1078":{},"1080":{},"1086":{},"1087":{},"1094":{}},"tags":{}}],["nest",{"_index":684,"title":{},"content":{"999":{},"1000":{}},"tags":{}}],["net_admin",{"_index":1084,"title":{},"content":{"1034":{}},"tags":{}}],["network",{"_index":578,"title":{},"content":{"992":{},"999":{},"1005":{},"1007":{},"1008":{},"1009":{},"1032":{}},"tags":{}}],["new",{"_index":365,"title":{},"content":{"979":{},"981":{},"983":{},"1007":{},"1009":{},"1013":{},"1031":{},"1049":{},"1065":{},"1066":{},"1080":{},"1095":{},"1097":{}},"tags":{}}],["newer",{"_index":1344,"title":{},"content":{"1089":{},"1093":{}},"tags":{}}],["newli",{"_index":1241,"title":{},"content":{"1049":{},"1080":{}},"tags":{}}],["newmeshcert",{"_index":437,"title":{},"content":{"983":{}},"tags":{}}],["next",{"_index":1190,"title":{"1110":{}},"content":{"1045":{},"1061":{},"1065":{},"1078":{},"1106":{}},"tags":{}}],["node",{"_index":681,"title":{"1026":{},"1031":{}},"content":{"999":{},"1000":{},"1005":{},"1017":{},"1023":{},"1026":{},"1028":{},"1031":{},"1037":{},"1054":{},"1071":{},"1086":{},"1096":{},"1097":{}},"tags":{}}],["node.k8s.io/v1",{"_index":1020,"title":{},"content":{"1025":{}},"tags":{}}],["nodepool1",{"_index":1419,"title":{},"content":{"1096":{}},"tags":{}}],["non",{"_index":881,"title":{},"content":{"1009":{},"1034":{},"1089":{}},"tags":{}}],["none",{"_index":1423,"title":{},"content":{"1096":{}},"tags":{}}],["northeurop",{"_index":1399,"title":{},"content":{"1095":{}},"tags":{}}],["notabl",{"_index":251,"title":{},"content":{"969":{}},"tags":{}}],["note",{"_index":552,"title":{},"content":{"989":{},"1004":{},"1034":{},"1043":{},"1056":{},"1073":{},"1087":{},"1090":{},"1093":{}},"tags":{}}],["now",{"_index":636,"title":{},"content":{"996":{},"1049":{},"1058":{},"1075":{},"1096":{}},"tags":{}}],["number",{"_index":426,"title":{},"content":{"983":{},"1089":{}},"tags":{}}],["numer",{"_index":404,"title":{},"content":{"982":{}},"tags":{}}],["nydu",{"_index":1035,"title":{},"content":{"1029":{}},"tags":{}}],["o=jsonpath='{.spec.runtimeclassnam",{"_index":1483,"title":{},"content":{"1106":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1192,"title":{},"content":{"1045":{},"1048":{},"1057":{},"1062":{},"1074":{}},"tags":{}}],["object",{"_index":666,"title":{},"content":{"998":{},"1032":{},"1033":{},"1103":{}},"tags":{}}],["observ",{"_index":396,"title":{"982":{}},"content":{"1022":{},"1043":{},"1056":{},"1073":{}},"tags":{}}],["obtain",{"_index":107,"title":{},"content":{"963":{},"967":{},"980":{},"1106":{}},"tags":{}}],["occur",{"_index":22,"title":{},"content":{"961":{}},"tags":{}}],["oci",{"_index":673,"title":{},"content":{"998":{},"999":{},"1020":{}},"tags":{}}],["offer",{"_index":700,"title":{},"content":{"1000":{},"1001":{},"1010":{},"1013":{},"1109":{}},"tags":{}}],["offlin",{"_index":221,"title":{},"content":{"966":{}},"tags":{}}],["older",{"_index":1292,"title":{},"content":{"1065":{},"1066":{}},"tags":{}}],["omit",{"_index":1006,"title":{},"content":{"1022":{},"1042":{},"1084":{}},"tags":{}}],["on",{"_index":190,"title":{},"content":{"965":{},"998":{},"1010":{},"1035":{},"1086":{},"1095":{},"1102":{},"1105":{},"1106":{}},"tags":{}}],["onc",{"_index":1108,"title":{},"content":{"1037":{},"1054":{},"1071":{},"1080":{}},"tags":{}}],["opa",{"_index":694,"title":{},"content":{"999":{},"1015":{}},"tags":{}}],["open",{"_index":28,"title":{},"content":{"961":{},"989":{},"999":{},"1015":{},"1067":{},"1075":{},"1080":{}},"tags":{}}],["openssl",{"_index":1223,"title":{},"content":{"1048":{},"1062":{}},"tags":{}}],["oper",{"_index":202,"title":{},"content":{"966":{},"972":{},"974":{},"984":{},"1001":{},"1002":{},"1003":{},"1005":{},"1007":{},"1008":{},"1010":{},"1012":{},"1049":{},"1094":{},"1108":{}},"tags":{}}],["optim",{"_index":705,"title":{},"content":{"1001":{}},"tags":{}}],["option",{"_index":680,"title":{"1063":{}},"content":{"999":{}},"tags":{}}],["orchestr",{"_index":730,"title":{},"content":{"1001":{},"1015":{}},"tags":{}}],["order",{"_index":478,"title":{},"content":{"986":{},"1022":{},"1043":{},"1067":{},"1084":{}},"tags":{}}],["organ",{"_index":1301,"title":{},"content":{"1067":{}},"tags":{}}],["origin",{"_index":523,"title":{},"content":{"989":{},"999":{},"1032":{},"1041":{}},"tags":{}}],["os",{"_index":15,"title":{},"content":{"961":{},"1004":{},"1096":{}},"tags":{}}],["os.readfile(\"/contrast/tl",{"_index":1157,"title":{},"content":{"1042":{}},"tags":{}}],["otherwis",{"_index":998,"title":{},"content":{"1021":{},"1034":{}},"tags":{}}],["out",{"_index":390,"title":{"1066":{}},"content":{"981":{},"996":{},"1006":{},"1007":{},"1009":{},"1031":{},"1034":{},"1060":{},"1066":{},"1077":{},"1097":{}},"tags":{}}],["outdat",{"_index":1380,"title":{},"content":{"1093":{}},"tags":{}}],["outlin",{"_index":500,"title":{},"content":{"989":{},"990":{},"1002":{},"1039":{}},"tags":{}}],["output",{"_index":1261,"title":{},"content":{"1053":{},"1070":{},"1094":{},"1102":{},"1103":{},"1106":{}},"tags":{}}],["outsid",{"_index":562,"title":{},"content":{"990":{},"992":{},"1019":{},"1034":{}},"tags":{}}],["over",{"_index":685,"title":{},"content":{"999":{},"1007":{},"1034":{},"1035":{},"1058":{},"1060":{},"1077":{}},"tags":{}}],["overrid",{"_index":1340,"title":{"1087":{}},"content":{"1087":{}},"tags":{}}],["overview",{"_index":741,"title":{"1002":{}},"content":{"1011":{}},"tags":{}}],["overwritten",{"_index":1016,"title":{},"content":{"1024":{},"1046":{},"1047":{},"1049":{},"1057":{},"1060":{},"1065":{},"1074":{},"1077":{}},"tags":{}}],["own",{"_index":807,"title":{},"content":{"1005":{}},"tags":{}}],["owner",{"_index":95,"title":{"967":{}},"content":{"963":{},"967":{},"980":{},"981":{},"985":{},"987":{},"988":{},"1003":{},"1005":{},"1009":{},"1010":{},"1047":{},"1067":{}},"tags":{}}],["owner'",{"_index":961,"title":{},"content":{"1014":{},"1018":{}},"tags":{}}],["ownership",{"_index":747,"title":{},"content":{"1002":{}},"tags":{}}],["owners—to",{"_index":306,"title":{},"content":{"974":{}},"tags":{}}],["p",{"_index":1203,"title":{},"content":{"1048":{}},"tags":{}}],["packag",{"_index":1379,"title":{},"content":{"1093":{}},"tags":{}}],["packet",{"_index":1060,"title":{},"content":{"1034":{}},"tags":{}}],["page",{"_index":248,"title":{},"content":{"969":{},"990":{},"1011":{}},"tags":{}}],["pair",{"_index":409,"title":{},"content":{"982":{}},"tags":{}}],["paramet",{"_index":981,"title":{},"content":{"1019":{},"1020":{}},"tags":{}}],["pars",{"_index":892,"title":{},"content":{"1009":{}},"tags":{}}],["part",{"_index":172,"title":{},"content":{"965":{},"969":{},"973":{},"981":{},"1004":{},"1014":{},"1018":{},"1019":{},"1025":{},"1029":{},"1032":{},"1035":{},"1053":{},"1058":{},"1065":{},"1070":{},"1102":{}},"tags":{}}],["parti",{"_index":73,"title":{"967":{},"976":{}},"content":{"963":{},"967":{},"976":{},"978":{},"980":{},"1001":{},"1005":{},"1007":{},"1010":{},"1013":{},"1034":{},"1109":{}},"tags":{}}],["particip",{"_index":975,"title":{},"content":{"1018":{}},"tags":{}}],["particular",{"_index":1333,"title":{},"content":{"1084":{}},"tags":{}}],["particularli",{"_index":616,"title":{},"content":{"995":{},"1002":{},"1022":{}},"tags":{}}],["parties—such",{"_index":305,"title":{},"content":{"974":{}},"tags":{}}],["partit",{"_index":879,"title":{},"content":{"1009":{},"1030":{},"1075":{},"1080":{}},"tags":{}}],["pass",{"_index":169,"title":{},"content":{"965":{},"986":{},"1047":{},"1049":{}},"tags":{}}],["passiv",{"_index":888,"title":{},"content":{"1009":{}},"tags":{}}],["patch",{"_index":1201,"title":{},"content":{"1048":{},"1065":{},"1089":{}},"tags":{}}],["path",{"_index":489,"title":{},"content":{"988":{},"1098":{}},"tags":{}}],["path/to/original/app",{"_index":534,"title":{},"content":{"989":{}},"tags":{}}],["patient",{"_index":931,"title":{},"content":{"1010":{}},"tags":{}}],["peer",{"_index":572,"title":{},"content":{"992":{},"1042":{}},"tags":{}}],["pend",{"_index":1320,"title":{},"content":{"1082":{}},"tags":{}}],["per",{"_index":603,"title":{},"content":{"995":{},"1032":{},"1043":{}},"tags":{}}],["perform",{"_index":451,"title":{},"content":{"984":{},"1008":{},"1009":{},"1026":{},"1031":{},"1037":{},"1054":{},"1071":{}},"tags":{}}],["period",{"_index":842,"title":{},"content":{"1007":{}},"tags":{}}],["perman",{"_index":839,"title":{},"content":{"1007":{}},"tags":{}}],["permiss",{"_index":808,"title":{},"content":{"1005":{},"1019":{},"1020":{}},"tags":{}}],["permit",{"_index":965,"title":{},"content":{"1015":{},"1023":{}},"tags":{}}],["persist",{"_index":472,"title":{"986":{},"989":{}},"content":{"986":{},"987":{},"988":{},"989":{},"993":{},"995":{},"1009":{},"1067":{},"1075":{},"1083":{}},"tags":{}}],["persistentvolumeclaim",{"_index":546,"title":{},"content":{"989":{}},"tags":{}}],["person",{"_index":744,"title":{},"content":{"1002":{}},"tags":{}}],["persona",{"_index":803,"title":{"1005":{}},"content":{"1010":{}},"tags":{}}],["perspect",{"_index":596,"title":{},"content":{"995":{},"1001":{},"1050":{}},"tags":{}}],["phase",{"_index":772,"title":{},"content":{"1003":{},"1044":{},"1049":{}},"tags":{}}],["physic",{"_index":764,"title":{},"content":{"1003":{},"1004":{},"1007":{},"1008":{},"1009":{}},"tags":{}}],["piec",{"_index":237,"title":{},"content":{"969":{}},"tags":{}}],["pii",{"_index":745,"title":{},"content":{"1002":{}},"tags":{}}],["pin",{"_index":611,"title":{"1105":{}},"content":{"995":{},"1105":{}},"tags":{}}],["pipe",{"_index":645,"title":{},"content":{"996":{}},"tags":{}}],["pki",{"_index":355,"title":{},"content":{"979":{},"992":{},"1001":{},"1032":{}},"tags":{}}],["place",{"_index":1354,"title":{},"content":{"1089":{}},"tags":{}}],["placehold",{"_index":1131,"title":{},"content":{"1041":{}},"tags":{}}],["plain",{"_index":480,"title":{},"content":{"986":{},"1042":{}},"tags":{}}],["plan",{"_index":1318,"title":{"1081":{}},"content":{"1081":{},"1082":{},"1083":{},"1086":{}},"tags":{}}],["plane",{"_index":790,"title":{},"content":{"1004":{},"1008":{},"1009":{}},"tags":{}}],["platform",{"_index":240,"title":{"1024":{}},"content":{"969":{},"1001":{},"1003":{},"1007":{},"1024":{},"1043":{},"1056":{},"1073":{},"1082":{},"1085":{}},"tags":{}}],["platform'",{"_index":918,"title":{},"content":{"1010":{}},"tags":{}}],["play",{"_index":297,"title":{},"content":{"974":{}},"tags":{}}],["pleas",{"_index":1183,"title":{},"content":{"1043":{},"1067":{}},"tags":{}}],["plugin",{"_index":970,"title":{},"content":{"1017":{},"1027":{},"1031":{}},"tags":{}}],["pod",{"_index":115,"title":{"965":{},"1030":{},"1103":{}},"content":{"965":{},"966":{},"970":{},"973":{},"981":{},"983":{},"995":{},"997":{},"998":{},"999":{},"1001":{},"1003":{},"1004":{},"1013":{},"1014":{},"1018":{},"1020":{},"1021":{},"1022":{},"1023":{},"1025":{},"1028":{},"1029":{},"1030":{},"1031":{},"1035":{},"1041":{},"1045":{},"1049":{},"1056":{},"1073":{},"1075":{},"1080":{},"1084":{},"1086":{},"1102":{},"1103":{},"1105":{},"1106":{},"1107":{}},"tags":{}}],["pod'",{"_index":193,"title":{},"content":{"965":{},"978":{}},"tags":{}}],["pod/#::###fals",{"_index":1083,"title":{},"content":{"638":{}},"tags":{}}],["name>##tru",{"_index":1089,"title":{},"content":{"638":{}},"tags":{}}],["namespac",{"_index":1403,"title":{},"content":{"705":{},"957":{},"960":{}},"tags":{}}],["nativ",{"_index":694,"title":{},"content":{"607":{},"612":{}},"tags":{}}],["necessari",{"_index":599,"title":{},"content":{"597":{},"623":{},"643":{},"647":{},"686":{},"693":{}},"tags":{}}],["need",{"_index":448,"title":{},"content":{"594":{},"595":{},"597":{},"601":{},"606":{},"620":{},"621":{},"624":{},"629":{},"630":{},"641":{},"643":{},"649":{},"655":{},"660":{},"665":{},"670":{},"671":{},"672":{},"682":{},"687":{},"688":{},"689":{},"691":{},"697":{},"698":{},"705":{},"952":{}},"tags":{}}],["nest",{"_index":736,"title":{},"content":{"610":{},"611":{}},"tags":{}}],["net_admin",{"_index":1104,"title":{},"content":{"638":{}},"tags":{}}],["network",{"_index":635,"title":{},"content":{"603":{},"610":{},"616":{},"618":{},"619":{},"620":{},"636":{}},"tags":{}}],["new",{"_index":430,"title":{},"content":{"599":{},"618":{},"620":{},"624":{},"635":{},"653":{},"676":{},"677":{},"691":{},"706":{},"708":{},"950":{},"952":{}},"tags":{}}],["newer",{"_index":1362,"title":{},"content":{"700":{},"704":{}},"tags":{}}],["newli",{"_index":1259,"title":{},"content":{"653":{},"691":{}},"tags":{}}],["newmeshcert",{"_index":500,"title":{},"content":{"599":{}},"tags":{}}],["next",{"_index":107,"title":{"931":{}},"content":{"649":{},"672":{},"676":{},"689":{},"960":{}},"tags":{}}],["node",{"_index":733,"title":{"630":{},"635":{}},"content":{"610":{},"611":{},"616":{},"628":{},"630":{},"632":{},"635":{},"641":{},"659":{},"665":{},"682":{},"697":{},"707":{},"708":{}},"tags":{}}],["node.k8s.io/v1",{"_index":1041,"title":{},"content":{"629":{}},"tags":{}}],["nodepool1",{"_index":1437,"title":{},"content":{"707":{}},"tags":{}}],["non",{"_index":907,"title":{},"content":{"620":{},"638":{},"700":{}},"tags":{}}],["none",{"_index":1441,"title":{},"content":{"707":{}},"tags":{}}],["northeurop",{"_index":1417,"title":{},"content":{"706":{}},"tags":{}}],["notabl",{"_index":333,"title":{},"content":{"940":{}},"tags":{}}],["note",{"_index":610,"title":{},"content":{"597":{},"615":{},"638":{},"647":{},"667":{},"684":{},"698":{},"701":{},"704":{}},"tags":{}}],["now",{"_index":692,"title":{},"content":{"607":{},"653":{},"669":{},"686":{},"707":{}},"tags":{}}],["number",{"_index":489,"title":{},"content":{"599":{},"700":{}},"tags":{}}],["numer",{"_index":467,"title":{},"content":{"598":{}},"tags":{}}],["nydu",{"_index":1056,"title":{},"content":{"633":{}},"tags":{}}],["o=jsonpath='{.spec.runtimeclassnam",{"_index":1499,"title":{},"content":{"960":{}},"tags":{}}],["o=jsonpath='{.status.loadbalancer.ingress[0].ip",{"_index":1210,"title":{},"content":{"649":{},"652":{},"668":{},"673":{},"685":{}},"tags":{}}],["object",{"_index":719,"title":{},"content":{"609":{},"636":{},"637":{},"957":{}},"tags":{}}],["observ",{"_index":459,"title":{"598":{}},"content":{"647":{},"658":{},"667":{},"684":{}},"tags":{}}],["obtain",{"_index":208,"title":{},"content":{"934":{},"938":{},"951":{},"960":{}},"tags":{}}],["occur",{"_index":135,"title":{},"content":{"932":{}},"tags":{}}],["oci",{"_index":725,"title":{},"content":{"609":{},"610":{},"656":{}},"tags":{}}],["offer",{"_index":100,"title":{},"content":{"611":{},"612":{},"621":{},"624":{},"930":{}},"tags":{}}],["offlin",{"_index":304,"title":{},"content":{"937":{}},"tags":{}}],["older",{"_index":1310,"title":{},"content":{"676":{},"677":{}},"tags":{}}],["omit",{"_index":1028,"title":{},"content":{"646":{},"658":{},"695":{}},"tags":{}}],["on",{"_index":276,"title":{},"content":{"609":{},"621":{},"639":{},"697":{},"706":{},"936":{},"956":{},"959":{},"960":{}},"tags":{}}],["onc",{"_index":1128,"title":{},"content":{"641":{},"665":{},"682":{},"691":{}},"tags":{}}],["opa",{"_index":744,"title":{},"content":{"610":{},"626":{}},"tags":{}}],["open",{"_index":139,"title":{},"content":{"597":{},"610":{},"626":{},"678":{},"686":{},"691":{},"932":{}},"tags":{}}],["openssl",{"_index":1241,"title":{},"content":{"652":{},"673":{}},"tags":{}}],["oper",{"_index":78,"title":{},"content":{"600":{},"612":{},"613":{},"614":{},"616":{},"618":{},"619":{},"621":{},"623":{},"653":{},"705":{},"929":{},"937":{},"943":{},"945":{}},"tags":{}}],["optim",{"_index":750,"title":{},"content":{"612":{}},"tags":{}}],["option",{"_index":732,"title":{"674":{}},"content":{"610":{}},"tags":{}}],["orchestr",{"_index":770,"title":{},"content":{"612":{},"626":{}},"tags":{}}],["order",{"_index":537,"title":{},"content":{"594":{},"647":{},"658":{},"678":{},"695":{}},"tags":{}}],["organ",{"_index":1319,"title":{},"content":{"678":{}},"tags":{}}],["origin",{"_index":582,"title":{},"content":{"597":{},"610":{},"636":{},"645":{}},"tags":{}}],["os",{"_index":129,"title":{},"content":{"615":{},"707":{},"932":{}},"tags":{}}],["os.readfile(\"/contrast/tl",{"_index":1176,"title":{},"content":{"646":{}},"tags":{}}],["otherwis",{"_index":1020,"title":{},"content":{"638":{},"657":{}},"tags":{}}],["out",{"_index":453,"title":{"677":{}},"content":{"607":{},"617":{},"618":{},"620":{},"635":{},"638":{},"671":{},"677":{},"688":{},"708":{},"952":{}},"tags":{}}],["outdat",{"_index":1398,"title":{},"content":{"704":{}},"tags":{}}],["outlin",{"_index":559,"title":{},"content":{"597":{},"601":{},"613":{},"643":{}},"tags":{}}],["output",{"_index":1279,"title":{},"content":{"664":{},"681":{},"705":{},"956":{},"957":{},"960":{}},"tags":{}}],["outsid",{"_index":620,"title":{},"content":{"601":{},"603":{},"638":{},"655":{}},"tags":{}}],["over",{"_index":737,"title":{},"content":{"610":{},"618":{},"638":{},"639":{},"669":{},"671":{},"688":{}},"tags":{}}],["overrid",{"_index":1358,"title":{"698":{}},"content":{"698":{}},"tags":{}}],["overview",{"_index":780,"title":{"613":{}},"content":{"622":{}},"tags":{}}],["overwritten",{"_index":1037,"title":{},"content":{"650":{},"651":{},"653":{},"660":{},"668":{},"671":{},"676":{},"685":{},"688":{}},"tags":{}}],["own",{"_index":835,"title":{},"content":{"616":{}},"tags":{}}],["owner",{"_index":197,"title":{"938":{}},"content":{"593":{},"595":{},"596":{},"614":{},"616":{},"620":{},"621":{},"651":{},"678":{},"934":{},"938":{},"951":{},"952":{}},"tags":{}}],["owner'",{"_index":983,"title":{},"content":{"625":{},"654":{}},"tags":{}}],["ownership",{"_index":786,"title":{},"content":{"613":{}},"tags":{}}],["owners—to",{"_index":380,"title":{},"content":{"945":{}},"tags":{}}],["p",{"_index":1221,"title":{},"content":{"652":{}},"tags":{}}],["packag",{"_index":1397,"title":{},"content":{"704":{}},"tags":{}}],["packet",{"_index":1081,"title":{},"content":{"638":{}},"tags":{}}],["page",{"_index":330,"title":{},"content":{"601":{},"622":{},"940":{}},"tags":{}}],["pair",{"_index":472,"title":{},"content":{"598":{}},"tags":{}}],["paramet",{"_index":1003,"title":{},"content":{"655":{},"656":{}},"tags":{}}],["pars",{"_index":918,"title":{},"content":{"620":{}},"tags":{}}],["part",{"_index":260,"title":{},"content":{"615":{},"625":{},"629":{},"633":{},"636":{},"639":{},"654":{},"655":{},"664":{},"669":{},"676":{},"681":{},"936":{},"940":{},"944":{},"952":{},"956":{}},"tags":{}}],["parti",{"_index":105,"title":{"938":{},"947":{}},"content":{"612":{},"616":{},"618":{},"621":{},"624":{},"638":{},"930":{},"934":{},"938":{},"947":{},"949":{},"951":{}},"tags":{}}],["particip",{"_index":997,"title":{},"content":{"654":{}},"tags":{}}],["particular",{"_index":1351,"title":{},"content":{"695":{}},"tags":{}}],["particularli",{"_index":673,"title":{},"content":{"606":{},"613":{},"658":{}},"tags":{}}],["parties—such",{"_index":379,"title":{},"content":{"945":{}},"tags":{}}],["partit",{"_index":905,"title":{},"content":{"620":{},"634":{},"686":{},"691":{}},"tags":{}}],["pass",{"_index":257,"title":{},"content":{"594":{},"651":{},"653":{},"936":{}},"tags":{}}],["passiv",{"_index":914,"title":{},"content":{"620":{}},"tags":{}}],["patch",{"_index":1219,"title":{},"content":{"652":{},"676":{},"700":{}},"tags":{}}],["path",{"_index":548,"title":{},"content":{"306":{},"596":{}},"tags":{}}],["path/to/original/app",{"_index":593,"title":{},"content":{"597":{}},"tags":{}}],["patient",{"_index":954,"title":{},"content":{"621":{}},"tags":{}}],["peer",{"_index":629,"title":{},"content":{"603":{},"646":{}},"tags":{}}],["pend",{"_index":1338,"title":{},"content":{"693":{}},"tags":{}}],["per",{"_index":660,"title":{},"content":{"606":{},"636":{},"647":{}},"tags":{}}],["perform",{"_index":512,"title":{},"content":{"600":{},"619":{},"620":{},"630":{},"635":{},"641":{},"665":{},"682":{}},"tags":{}}],["period",{"_index":869,"title":{},"content":{"618":{}},"tags":{}}],["perman",{"_index":866,"title":{},"content":{"618":{}},"tags":{}}],["permiss",{"_index":836,"title":{},"content":{"616":{},"655":{},"656":{}},"tags":{}}],["permit",{"_index":987,"title":{},"content":{"626":{},"659":{}},"tags":{}}],["persist",{"_index":531,"title":{"594":{},"597":{}},"content":{"594":{},"595":{},"596":{},"597":{},"604":{},"606":{},"620":{},"678":{},"686":{},"694":{}},"tags":{}}],["persistentvolumeclaim",{"_index":604,"title":{},"content":{"597":{}},"tags":{}}],["person",{"_index":783,"title":{},"content":{"613":{}},"tags":{}}],["persona",{"_index":832,"title":{"616":{}},"content":{"621":{}},"tags":{}}],["perspect",{"_index":653,"title":{},"content":{"606":{},"612":{},"661":{}},"tags":{}}],["phase",{"_index":807,"title":{},"content":{"614":{},"648":{},"653":{}},"tags":{}}],["physic",{"_index":801,"title":{},"content":{"614":{},"615":{},"618":{},"619":{},"620":{}},"tags":{}}],["piec",{"_index":319,"title":{},"content":{"940":{}},"tags":{}}],["pii",{"_index":784,"title":{},"content":{"613":{}},"tags":{}}],["pin",{"_index":668,"title":{"959":{}},"content":{"606":{},"959":{}},"tags":{}}],["pipe",{"_index":701,"title":{},"content":{"607":{}},"tags":{}}],["pki",{"_index":420,"title":{},"content":{"603":{},"612":{},"636":{},"950":{}},"tags":{}}],["place",{"_index":1372,"title":{},"content":{"700":{}},"tags":{}}],["placehold",{"_index":1150,"title":{},"content":{"645":{}},"tags":{}}],["plain",{"_index":539,"title":{},"content":{"594":{},"646":{}},"tags":{}}],["plan",{"_index":1336,"title":{"692":{}},"content":{"692":{},"693":{},"694":{},"697":{}},"tags":{}}],["plane",{"_index":819,"title":{},"content":{"615":{},"619":{},"620":{}},"tags":{}}],["platform",{"_index":322,"title":{"660":{}},"content":{"612":{},"614":{},"618":{},"647":{},"660":{},"667":{},"684":{},"693":{},"696":{},"940":{}},"tags":{}}],["platform'",{"_index":943,"title":{},"content":{"621":{}},"tags":{}}],["play",{"_index":373,"title":{},"content":{"945":{}},"tags":{}}],["pleas",{"_index":1202,"title":{},"content":{"647":{},"678":{}},"tags":{}}],["plugin",{"_index":992,"title":{},"content":{"628":{},"631":{},"635":{}},"tags":{}}],["pod",{"_index":12,"title":{"634":{},"936":{},"957":{}},"content":{"599":{},"606":{},"608":{},"609":{},"610":{},"612":{},"614":{},"615":{},"624":{},"625":{},"629":{},"632":{},"633":{},"634":{},"635":{},"639":{},"645":{},"649":{},"653":{},"654":{},"656":{},"657":{},"658":{},"659":{},"667":{},"684":{},"686":{},"691":{},"695":{},"697":{},"928":{},"936":{},"937":{},"941":{},"944":{},"952":{},"956":{},"957":{},"959":{},"960":{}},"tags":{}}],["pod'",{"_index":279,"title":{},"content":{"936":{},"949":{}},"tags":{}}],["pod/#https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architectureweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/attestation/coordinatorweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/attestation/hardwareweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/attestation/manifestweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/attestation/pod-vmweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/attestation/runtime-policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/certificates-and-identities/pkiweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/components/cliweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/components/coordinatorweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/components/init-containerweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/protocols-and-keysweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/architecture/network-encryption/sidecarweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/category/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/category/certificates-and-identitiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/category/componentsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/category/network-encryptionweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/examplesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/getting-startedweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/getting-started/first-stepsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.5/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/aboutweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/architectureweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/componentsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/examplesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/getting-startedweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.6/known-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/aboutweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/architectureweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/componentsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/examplesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/getting-startedweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.7/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/architecture/secretsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/components/overviewweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.8/troubleshootingweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/architecture/secretsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/components/overviewweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/0.9/troubleshootingweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/architecture/secretsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/components/overviewweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.0/troubleshootingweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1weekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/architecture/secretsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/architecture/security-considerationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/components/overviewweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/getting-started/bare-metalweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/1.1/troubleshootingweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/nextweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/architecture/secretsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/architecture/security-considerationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/components/overviewweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/examples/mysqlweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/getting-started/bare-metalweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/next/troubleshootingweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/about/telemetryweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/architecture/attestationweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/architecture/certificatesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/architecture/observabilityweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/architecture/secretsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/architecture/security-considerationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/basics/confidential-containersweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/basics/featuresweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/basics/security-benefitsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/components/overviewweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/components/policiesweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/components/runtimeweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/components/service-meshweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/deploymentweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/examples/emojivotoweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/examples/mysqlweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/features-limitationsweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/getting-started/bare-metalweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/getting-started/cluster-setupweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/getting-started/installweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/troubleshootingweekly0.5https://docs.edgeless.systems/contrast/pr-preview/pr-1071/weekly0.5 \ No newline at end of file diff --git a/pr-preview/pr-1071/troubleshooting.html b/pr-preview/pr-1071/troubleshooting.html deleted file mode 100644 index f0ca896bd1..0000000000 --- a/pr-preview/pr-1071/troubleshooting.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - -Troubleshooting | Contrast - - - - -
Version: 1.2

Troubleshooting

-

This section contains information on how to debug your Contrast deployment.

-

Logging

-

Collecting logs can be a good first step to identify problems in your -deployment. Both the CLI and the Contrast Coordinator as well as the Initializer -can be configured to emit additional logs.

-

CLI

-

The CLI logs can be configured with the --log-level command-line flag, which -can be set to either debug, info, warn or error. The default is info. -Setting this to debug can get more fine-grained information as to where the -problem lies.

-

Coordinator and Initializer

-

The logs from the Coordinator and the Initializer can be configured via the -environment variables CONTRAST_LOG_LEVEL, CONTRAST_LOG_FORMAT and -CONTRAST_LOG_SUBSYSTEMS.

-
    -
  • CONTRAST_LOG_LEVEL can be set to one of either debug, info, warn, or -error, similar to the CLI (defaults to info).
  • -
  • CONTRAST_LOG_FORMAT can be set to text or json, determining the output -format (defaults to text).
  • -
  • CONTRAST_LOG_SUBSYSTEMS is a comma-separated list of subsystems that should -be enabled for logging, which are disabled by default. Subsystems include: -kds-getter, issuer and validator. -To enable all subsystems, use * as the value for this environment variable. -Warnings and error messages from subsystems get printed regardless of whether -the subsystem is listed in the CONTRAST_LOG_SUBSYSTEMS environment variable.
  • -
-

To configure debug logging with all subsystems for your Coordinator, add the -following variables to your container definition.

-
spec: # v1.PodSpec
containers:
image: "ghcr.io/edgelesssys/contrast/coordinator:v1.2.0@sha256:458e408cd8f390b258b84a1236464febf63bda08f0be91a585c5a14500564cc8"
name: coordinator
env:
- name: CONTRAST_LOG_LEVEL
value: debug
- name: CONTRAST_LOG_SUBSYSTEMS
value: "*"
# ...
-
info

While the Contrast Coordinator has a policy that allows certain configurations, -the Initializer and service mesh don't. When changing environment variables of other -parts than the Coordinator, ensure to rerun contrast generate to update the policy.

-

To access the logs generated by the Coordinator, you can use kubectl with the -following command:

-
kubectl logs <coordinator-pod-name>
-

Pod fails to start

-

If the Coordinator or a workload pod fails to even start, it can be helpful to -look at the events of the pod during the startup process using the describe -command.

-
kubectl -n <namespace> events --for pod/<coordinator-pod-name>
-

Example output:

-
LAST SEEN  TYPE     REASON  OBJECT             MESSAGE
32m Warning Failed Pod/coordinator-0 kubelet Error: failed to create containerd task: failed to create shim task: "CreateContainerRequest is blocked by policy: ...
-

A common error, as in this example, is that the container creation was blocked by the -policy. Potential reasons are a modification of the deployment YAML without updating -the policies afterward, or a version mismatch between Contrast components.

-

Regenerating the policies

-

To ensure there isn't a mismatch between Kubernetes resource YAML and the annotated -policies, rerun

-
contrast generate
-

on your deployment. If any of the policy annotations change, re-deploy with the updated policies.

-

Pin container images

-

When generating the policies, Contrast will download the images specified in your deployment -YAML and include their cryptographic identity. If the image tag is moved to another -container image after the policy has been generated, the image downloaded at deploy time -will differ from the one at generation time, and the policy enforcement won't allow the -container to be started in the pod VM.

-

To ensure the correct image is always used, pin the container image to a fixed sha256:

-
image: ubuntu:22.04@sha256:19478ce7fc2ffbce89df29fea5725a8d12e57de52eb9ea570890dc5852aac1ac
-

This way, the same image will still be pulled when the container tag (22.04) is moved -to another image.

-

Validate Contrast components match

-

A version mismatch between Contrast components can cause policy validation or attestation -to fail. Each Contrast runtime is identifiable based on its (shortened) measurement value -used to name the runtime class version.

-

First, analyze which runtime class is currently installed in your cluster by running

-
kubectl get runtimeclasses
-

This should give you output similar to the following one.

-
NAME                                           HANDLER                                        AGE
contrast-cc-aks-clh-snp-7173acb5 contrast-cc-aks-clh-snp-7173acb5 23h
kata-cc-isolation kata-cc 45d
-

The output shows that there are four Contrast runtime classes installed (as well as the runtime class provided -by the AKS CoCo preview, which isn't used by Contrast).

-

Next, check if the pod that won't start has the correct runtime class configured, and the -Coordinator uses the exact same runtime:

-
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<pod-name>
kubectl -n <namespace> get -o=jsonpath='{.spec.runtimeClassName}' pod/<coordinator-pod-name>
-

The output should list the runtime class the pod is using:

-
contrast-cc-aks-clh-snp-7173acb5
-

Version information about the currently used CLI can be obtained via the version flag:

-
contrast --version
-
contrast version v0.X.0

runtime handler: contrast-cc-aks-clh-snp-7173acb5
launch digest: beee79ca916b9e5dc59602788cbfb097721cde34943e1583a3918f21011a71c47f371f68e883f5e474a6d4053d931a35
genpolicy version: 3.2.0.azl1.genpolicy0
image versions: ghcr.io/edgelesssys/contrast/coordinator@sha256:...
ghcr.io/edgelesssys/contrast/initializer@sha256:...
- - \ No newline at end of file