diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..a587123f --- /dev/null +++ b/404.html @@ -0,0 +1,1880 @@ + + + +
+ + + + + + + + + + + + + + +Backend services are small, self-contained, and (ideally) stateless applications that can be deployed and scaled independently. They are designed to be used in conjunction with other services and are often packaged together to form a larger application.
+The following is an example for the combination of services creating the backend of a Telestion application:
+graph TB
+ accTitle: Diagram showcasing the structure of an exemplary Telestion backend. Text description in collapsible section below.
+ db[Database]
+ md[Mission Device]
+ subgraph Backend
+ io[IO Service]
+ tmps[Telemetry Parser Service]
+ tcs[Telecommand Service]
+ dbs[Database Writer Service]
+ dbqs[Database Query Service]
+ end
+ subgraph Frontend
+ wc[Web Client]
+ end
+ md <---> io
+ io --> tmps
+ tmps --> dbs
+ dbs --> db
+ wc --> dbqs
+ dbqs --> db
+ wc --> tcs
+ tcs --> io
+The most common way to write a backend service is to use TypeScript.
+Get started writing a backend service in TypeScript
+However, for some use cases, it may be necessary to write a backend service in other languages.
+Even some of the core services provided out of the box are written in Rust. To learn how to write a service in Rust, see Using Rust.
+You can even write a backend service in any language you want. The only requirement is that it can communicate with the NATS message bus. To learn how to write a service in other languages, see Using other languages.
+ + + + + + + + + + + + + + + + +You can use any language you want to write your backend. The only requirement is that it can communicate with the NATS message bus.
+The only technical requirement for a backend service is that it can communicate with the NATS message bus. This means that it must be able to send and receive messages on the message bus.
+However, there are some additional standards that you should follow to make your service easier to use (and compliant with the Telestion ecosystem):
+Your service should be deployable as both a Docker container and as an executable. This makes it easier to deploy and scale your service.
+Your service should be configurable via environment variables.
+Every Telestion service receives at least the following environment variables:
+NATS_URL
: The URL of the NATS serverNATS_USER
: The username of the NATS userNATS_PASSWORD
: The password of the NATS userSERVICE_NAME
: The name of the service. This is used to create a unique queue group for your service. See Queues for more information.DATA_DIR
: The path to the data directory. This is where your service should store any data it needs to persist. This is shared between multiple services. To ensure that your service doesn’t overwrite data from other services, you should create a subdirectory for your service.If your service doesn’t receive any of these environment variables, it should exit with a non-zero exit code.
+Warning
+There can be multiple instances of a service with the same name running at the same time. They are guaranteed to have the same configuration, apart from the SERVICE_ID
. If you need a truly unique identifier, you can combine the SERVICE_NAME
and the process ID.
Your service should log any “feedback” to stdout
and stderr
.
For logging data to files, you should use the Standard Operations Library.
+NATS allows you to create queue groups. This means that you can have multiple instances of the same service running, and they’ll share the messages they receive.
+If you want to use this feature, you should use the SERVICE_NAME
environment variable to create a unique queue group for your service.
Your message must be able to handle, without crashing, the following types of messages:
+Your service mustn’t assume anything about the format or content of the message body. It must be able to handle any message body of the two types.
+Your service should provide a health check feature on the message bus subject __telestion__/health
. This allows other services to check if your service is still running.
While running, any Telestion service should respond (within 0.5 seconds) to requests on the __telestion__/health
subject with a message containing the following JSON-encoded information:
{
+ "errors": 0, // or number of "recent" errors
+ "service": "my-service", // the SERVICE_ID
+ "name": "My Service" // the SERVICE_NAME
+}
+
Info
+The standard operations library is a library that provides a set of common operations that are used by many Telestion services. While it can be overwritten, every Telestion application comes with an implementation of these operations out-of-the-box that you can use.
+The standard operations library provides a simple way to log data to files.
+To use it, publish a message to the __telestion__/log/[category]
subject with the body you want to log. [category]
is the category of the log message. It can be any string.
The standard operations library then logs the message to the file logs/[category].log
in your data directory.
use nats::asynk::Connection;
+use std::error::Error;
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn Error>> {
+ let nc = Connection::new("nats://localhost:4222").await?;
+ let sub = nc.subscribe("bar")?.with_handler(move |msg| {
+ println!("Received {}", &msg);
+ Ok(())
+ });
+
+ Ok(())
+}
+
Tip
+Not every service needs to be configurable. If you are writing a simple service, you can skip this section.
+However, you can often save yourself a lot of time by making your service configurable. This way, you can use the same service in multiple environments without having to change the code.
+Warning
+This section is specific to TypeScript services. Only the environment variables are standardized and must be implemented for all Telestion services.
+While services in other languages can use the same configuration sources, they aren’t required to do so.
+Services can be configured using the following sources:
+All these sources get combined into a single configuration object. If a configuration value is defined in multiple sources, the following order is used:
+Environment variables are the most common way to configure a service. They are easy to use and supported by most platforms.
+Environment variables are always strings. If you need to use a different type, you will have to parse the value yourself.
+Command line arguments are useful for configuring a service during development. They are also useful for overriding configuration values when running a service in production.
+Configuration files are useful for configuring a service in production. They are also useful for overriding configuration values when running a service in production.
+Configuration files are optional. If no configuration file is provided, the service will still start.
+A configuration file is a JSON file with an object as its root element. The keys of this object are the configuration values. The values of this object are the configuration values.
+The configuration file is loaded from the path passed as CONFIG_FILE
as either environment variable or command line argument.
You can optionally also pass a CONFIG_KEY
to load a specific key from the configuration file. This is useful if you want to use the same configuration file for multiple services.
CONFIG_FILE
parameter of the preliminary configuration) and merged into the preliminary configuration.Some configuration values are required for all services. These values are:
+NATS_URL
: The URL of the NATS server to connect to.NATS_USER
: The username to use when connecting to NATS.NATS_PASSWORD
: The password to use when connecting to NATS.SERVICE_NAME
: The name of the service. This is used to identify the service in the logs and in the NATS server. This is required for all services.DATA_DIR
: The directory where the service can store data. This is required for all services.Tip
+To make it easier to run your service during development, sensible defaults are used when you pass the --dev
flag to the service:
Configuration Value | +Default Value | +
---|---|
NATS_URL |
+localhost:4222 |
+
NATS_USER |
+(none) | +
NATS_PASSWORD |
+(none) | +
SERVICE_NAME |
+dev-[process gid] |
+
DATA_DIR |
+./data |
+
This way, you don’t have to set all the required configuration values when running the service locally.
+Without the --dev
flag, the service fails if any of the required configuration values are missing.
Now that you know about the different configuration sources, let’s see how you can access the configuration in your service. Since the complicated bits are handled by the startService
function, this is actually pretty straight forward.
Create a file called config.json
next to your service.ts
file with the following content:
{
+ "SERVICE_NAME": "Config Tester",
+ "tasks": {
+ "task1": "Task 1",
+ "task2": "Task 2"
+ }
+}
+
Now, let’s adjust the service.ts
file to use the configuration:
import { startService } from "https://deno.land/x/telestion/mod.ts";
+import { z } from "https://deno.land/x/zod@v3.21.4/mod.ts";// (1)!
+
+const { config: rawConfig/* (2)! */} = await startService({
+ nats: false,
+});
+
+const config = z.object({
+ NAME: z.string(),
+ tasks: z.record(z.string(), z.string()),
+}).parse(rawConfig);// (3)!
+
+console.log(config.NAME, config.tasks);// (4)!
+
z
function from the Zod to validate the configuration. Never assume the configuration is valid. Always validate it before using it.rawConfig
.Now, let’s see what happens if we run the service:
+ +As expected, the service doesn’t start:
+$ deno run --allow-all service.ts --dev
+Running in development mode.
+Using default values for missing environment variables.
+error: Uncaught ZodError: [
+ {
+ "code": "invalid_type",
+ "expected": "string",
+ "received": "undefined",
+ "path": [
+ "NAME"
+ ],
+ "message": "Required"
+ },
+ {
+ "code": "invalid_type",
+ "expected": "object",
+ "received": "undefined",
+ "path": [
+ "tasks"
+ ],
+ "message": "Required"
+ }
+]
+
Let’s fix this by passing the required configuration values:
+deno run --allow-all service.ts --dev \
+ --CONFIG_FILE ./config.json \ # (1)!
+ --NAME "Hello" # (2)!
+
--CONFIG_FILE
flag.NAME
configuration value using the --NAME
flag.Now, everything works as expected.
+ + + + + + + + + + + + + + + + +Note
+The author generated this text in part with GPT-3, OpenAI’s large-scale language-generation model. Upon generating draft language, the author reviewed, edited, and revised the language to their own liking and takes ultimate responsibility for the content of this publication.
+This tutorial will explain step-by-step how to write a log service that will listen for messages on the log.>
subject and write them to a file.
First, we need to import the startService
function from our library (lib.ts
) and the encode
function from the standard Deno library.
Next, we create a new TextEncoder instance. This will be used to turn messages into a format that can be written to a file.
+ +We then call the startService
function to set up our service. This will return an object containing information about the message bus that we can use to subscribe to messages.
We then subscribe to the message bus, using a wildcard subscription for any messages published on the log.>
subject. This will allow us to receive all messages published on any topics starting with log.
.
We use a for-await-of loop to receive messages from the message bus. For each message, we extract the subject (split the string on .
, then take the second element) and the message data, which we encode using the encode
function from the standard library.
We log the message to the console and write it to a file (appending it to the end).
+ +And that’s it! Our service is now complete and ready to be used.
+import { startService } from "https://deno.land/x/telestion/mod.ts";
+import { encode } from "https://deno.land/std@0.186.0/encoding/hex.ts";
+
+const encoder = new TextEncoder();
+
+const { messageBus } = await startService();
+
+const logMessages = messageBus.subscribe("log.>");
+
+for await (const msg of logMessages) {
+ try {
+ const currentTime = new Date().toISOString();
+ const logMessage = encode(msg.data).toString();
+ const subject = msg.subject.split(".")[1];
+
+ console.log(`${currentTime} [${subject}] ${logMessage}`);
+ await Deno.writeFile(
+ "log.txt",
+ encoder.encode(`${currentTime} [${subject}] ${logMessage}\n`),
+ { append: true },
+ );
+ } catch (error) {
+ console.error(error);
+ }
+}
+
TypeScript is the recommended language for writing backend services. It is a superset of JavaScript that adds static typing and other features that make it easier to write and maintain code.
+To write a backend service in TypeScript, you should be familiar with JavaScript and (ideally) TypeScript. Overall, basic JavaScript knowledge will be sufficient to get started, but async
/await
and Promises are used extensively for services, so you should be familiar with these topics.
Deno is a JavaScript/TypeScript runtime that is built on top of V8, Rust, and Tokio. It is a secure runtime for JavaScript and TypeScript.
+Compared to Node.js, Deno has the following advantages:
+To install Deno, please follow the instructions on the Deno website .
+Create a new directory for your service:
+ +Create a new file called service.ts
:
Open service.ts
in your favorite editor and add the following code:
import { startService } from 'https://deno.land/x/telestion/mod.ts';// (1)!
+
+await startService/*(2)!*/({
+ nats: false,// (3)!
+});
+
+console.log('Hello World!');// (4)!
+
startService
function from the library. Note that the library is in the same directory as the service.ts
file, so we can use a relative path.+ Later, when we publish the library to a registry, we will be able to use a URL instead.
To run the service, run the following command:
+ +Success
+You should see the following output:
+ +Running in development mode
+When you run the service with the --dev
flag, the service will use default values for missing environment variables. You’ll learn more about this in the configuration section.
Now that you have a basic service running, you should have a look at how to make your service configurable.
+ + + + + + + + + + + + + + + + + +The message bus is a simple, lightweight, and fast way to send messages between different parts (services) of your application. It is a simple publish/subscribe system that allows you to send messages to a specific subject and have any listeners on that subject receive the message.
+Running NATS for development
+Now that we want to interact with the message bus, we need to have NATS running. If you’re using the --dev
mode for testing your service, it’s sufficient to run the nats-server
executable in a separate terminal window. This will start a local NATS server on port 4222
which is the default port for NATS.
If you have a prdouction-like setup, you’ll need to pass the NATS_USER
and NATS_PASSWORD
corresponding to your NATS configuration as configuration parameters to your service for authentication.
Connecting to the event bus is automatically handled by the startService
function. It will connect to the message bus using the NATS_URL
environment variable. If you’re running the service in --dev
mode, this will be nats://localhost:4222
by default.
All you need to do compared to the previous examples is to omit the { nats: false }
parameter from the startService
function call:
import {
+ startService
+} from "https://deno.land/x/telestion/mod.ts";
+
+const {nc/* (1)! */} = await startService(/* (2)! */);
+
nc
for later use.{ nats: false }
parameter from the startService
function call since we want to connect to the message bus.Note
+startService
actually returns an object containing the NATS connection (nc
) and a few other things. In our example, we use destructuring to only get the nc
variable. This is equivalent to the following code:
Publishing messages is as simple as calling the publish
function on the NATS connection:
However, Telestion Hub uses a specific message format for all messages sent over the message bus. A message can be either JSON or a binary message. The binary message is used for sending large amounts of data, e.g., images or video streams. The JSON message is used for all other messages.
+To send a JSON message, you need to create a JSON object and pass it to the publish
function:
import {
+ JSONCodec,
+ startService
+} from "https://deno.land/x/telestion/mod.ts";
+// or: import { JSONCodec } from "https://deno.land/x/nats/src/mod.ts";
+
+const {nc} = await startService();
+
+const jsonCodec = JSONCodec();//(2)!
+
+await nc.publish("subject", jsonCodec.encode/*(3)!*/({
+ foo: "some arbitrary JSON-compatible data",
+ bar: 42
+}));
+
JSONCodec
(for convenience, this gets re-exported by the lib.ts
, but you can also import it directly from the NATS library).JSONCodec
instance.JSONCodec
instance.To send a binary message, you need to create a Uint8Array
containing the bytes and pass it to the publish
function:
import {
+ startService
+} from "https://deno.land/x/telestion/mod.ts";
+
+const {nc} = await startService();
+
+await nc.publish("subject", new Uint8Array([0x01, 0x02, 0x03]));
+
Uint8Arrays
+You can learn more about how you can use Uint8Array
on MDN.
There are multiple ways to subscribe to messages on a subject. The most common way is to use the subscribe
function in combination with a for await
loop:
import {
+ startService
+} from "https://deno.land/x/telestion/mod.ts";
+
+const {nc} = await startService();
+
+const subjectSubscription/*(1)!*/ = await nc.subscribe("subject"/*(2)!*/);
+
+for await (const message of subjectSubscription) {//(3)!
+ console.log(message.data);//(4)!
+}
+
subjectSubscription
for later use.subject
subject.Unfortunately, this won’t decode our JSON messages automatically. We need to do this ourselves:
+import {
+ JSONCodec,
+ startService
+} from "https://deno.land/x/telestion/mod.ts";
+
+const {nc} = await startService();
+
+const jsonCodec = JSONCodec();
+
+const subjectSubscription = await nc.subscribe("subject");
+for await (const message of subjectSubscription) {
+ const jsonMessage = jsonCodec.decode(message.data);//(1)!
+ console.log(jsonMessage.foo);//(2)!
+}
+
JSONCodec
instance.foo
property of the decoded JSON message to the console.Danger
+Can you spot the problem with this code? What happens if the message data doesn’t contain a foo
property? Or if it’s not a JSON message at all? This would lead to our service crashing!
Never assume a message’s structure!
+You should always validate the message data before using it. We’ll cover this in the next section.
+A Telestion service must validate all messages it receives. This is to ensure that the service doesn’t crash when it receives invalid messages.
+The first “layer” of validation is the message type. A message can either be a JSON message or a binary message. The jsonCodec.decode
function will throw an error if the message data is not a valid JSON message. Therefore, we can use a try
/catch
block to catch the error and handle it accordingly:
// ...
+
+for await (const message of subjectSubscription) {
+ try/*(3)!*/{
+ const jsonMessage = jsonCodec.decode(message.data);
+ console.log(jsonMessage.foo);
+ } catch (_e) {
+ console.error/*(2)!*/("Received invalid message:", message);
+ }
+}
+
jsonCodec.decode
.try
/catch
block.Binary Messages
+Since any messages get sent as binary messages (in fact, the JSONCodec
does nothing else than convert the JSON message to a Uint8Array
and back), there’s no way to validate that a message is supposed to be a binary message. This makes the next section even more important.
The second “layer” of validation is the message structure. This is where you validate that the message data contains all the properties you expect it to contain. For example, if you expect a message to contain a foo
property, you must verify its existence before using it.
For structured JSON data, we recommend that you use the zod
library for validation. This is also used in our lib.ts
file to validate the configuration. You can find more information about zod
in the library’s GitHub repository.
Let’s create a zod
schema for our JSON message in a new file called foo-message.ts
:
import {
+ z
+} from "https://deno.land/x/zod@v3.16.1/mod.ts";
+
+export const fooMessageSchema = z.object/*(1)!*/(({
+ foo: z.string()/*(2)!*/,
+ bar: z.number().min(-10)/*(3)!*/
+});
+
+export type FooMessage = z.infer<typeof fooMessageSchema>;//(4)!
+
FooMessage
must be an object.FooMessage
must have a foo
property that is a string.FooMessage
must have a bar
property that is a number and is greater than or equal to -10
.FooMessage
type. While we won’t use it in this example, it’s good practice to create a type for each schema you create. This allows you to use the type anywhere in your code:
+ Now we can use this schema to validate the message data:
+import {
+ fooMessageSchema
+} from "./foo-message.ts";
+
+// ...
+
+for await (const message of subjectSubscription) {
+ try {
+ const jsonMessage = fooMessageSchema.parse/*(1)!*/(
+ jsonCodec.decode(message.data)
+ );
+
+ console.log(jsonMessage/*(2)!*/.foo);
+ } catch (_e) {
+ console.error("Received invalid message:", message);
+ }
+}
+
fooMessageSchema
schema. This will throw an error if the message data doesn’t match the schema.jsonMessage
is a valid FooMessage
object. Therefore, we can access the foo
property without any problems.Success
+If your editor has great TypeScript support and has shown you warnings/errors before, they are now gone! This is because TypeScript now knows that the jsonMessage
variable is a valid FooMessage
object. In other words, your code is now safe from invalid messages!
Binary Messages
+For binary messages, you can’t use zod
to validate the message structure. Instead, you should use the Uint8Array
methods to validate the message structure. For example, you can check the length of the message data using the length
property of the Uint8Array
:
However, the exact validation required completely depends on your use case. Just make sure that your code doesn’t crash when it receives an invalid message.
+So far, we’ve used the for await
loop. This is a convenient way to subscribe to a single topic. However, if you want to do more than just react to messages from a specific subject, we get into trouble. Since the for await
loop is blocking, we can’t do anything else while we’re waiting for messages.
We can solve this by wrapping the for await
loop in an async
function and calling it in a separate thread. This allows us to do other things while we’re waiting for messages:
// ...
+
+const subjectMessages = nc.subscribe("foo");
+(async () => {//(1)!
+ for await (const message of subjectMessages) {
+ // Handle messages from the "foo" subject
+ }
+})();
+
+// ... (2)
+
for await
loop in an async
function and call it immediately. This will start the subscription in parallel to the rest of the code. Note that we’re storing the return value of nc.subscribe
in a variable outside the async
function. This is important so that we can close the subscription or check its status later.
Closing the Subscription
+You can close the subscription by calling the unsubscribe
method on the subscription object:
You must call unsubscribe
on the subscription object. Calling nc.unsubscribe
will unsubscribe from all subscriptions!
This now allows us to subscribe to multiple topics:
+// ...
+
+const fooMessages = nc.subscribe("foo");//(1)!
+(async () => {
+ for await (const message of fooMessages) {
+ // Handle messages from the "foo" subject
+ }
+})();
+
+const barMessages = nc.subscribe("bar");//(2)!
+(async () => {
+ for await (const message of barMessages) {
+ // Handle messages from the "bar" subject
+ if (shouldUnsubscribeFoo(message))
+ fooMessages.unsubscribe/*(3)!*/();
+
+ if (shouldUnsubscribeBar(message))
+ barMessages.unsubscribe/*(4)!*/();
+ }
+})();
+
+await Promise.all/*(5)!*/([
+ fooMessages.closed,
+ barMessages.closed
+]);
+
+console.log("All subscriptions closed!");//(6)!
+
foo
subject.bar
subject (in parallel to the foo
subscription).foo
subject if the shouldUnsubscribeFoo
function returns true
.bar
subject if the shouldUnsubscribeBar
function returns true
.unsubscribe
method is called on the subscription object. The closed
property is a Promise
that resolves when the subscription is closed.
Promise.all
is a convenient way to wait for multiple promises to resolve. It returns a Promise
that resolves when all promises passed to it have resolved.
Info
+Queue groups are a way to distribute messages between multiple subscribers. If you have multiple subscribers to a subject, you can use queue groups to distribute messages between them. This is useful if you want to distribute messages between multiple instances of a service (for example, if you want to scale your service horizontally because processing a message takes too long).
+All you have to do to use queue groups is to pass a queue
option to the subscribe
method. You can use any string as the queue name, but by its definition, the SERVICE_NAME
configuration parameter works perfect for this. For convenience, this gets exposed as serviceName
on the object returned by startService
:
// ...
+
+const {
+ nc,
+ serviceName/*(1)!*/
+} = await startService();
+
+const fooMessages = nc.subscribe(
+ "foo",
+ {queue: serviceName/*(2)!*/}
+);
+(async () => {
+ for await (const message of fooMessages) {
+ // Handle messages from the "foo" subject
+ }
+})();
+
+// ...
+
serviceName
from the object returned by startService
.serviceName
as the queue
option to the subscribe
method.If you now run multiple instances of your service, you’ll see that messages are distributed between them. This is because the queue
option tells the message bus to distribute messages between all subscribers with the same queue name.
Service names in development mode
+When you run your service in development mode, the serviceName
will be generated. This means that you’ll get a different service name every time you start your service. To avoid this, you can either set the SERVICE_NAME
environment variable or pass a service name via the CLI:
Wildcards are a way to subscribe to multiple subjects at once. This is useful if you want to subscribe to multiple subjects that have a common prefix. For example, you could have a service that handles all requests to the /api
endpoint. You could then subscribe to all requests to the /api
endpoint by subscribing to the api.>
subject.
There are two types of wildcards: *
and >
. The *
wildcard matches a single token. The >
wildcard matches one or more tokens. For example, the api.*
subject matches api.foo
and api.bar
, but not api.foo.bar
. The api.>
subject matches api.foo
, api.bar
, and api.foo.bar
.
You can use wildcards in the subscribe
method and then use the subject
property of the message to check which subject the message was sent to:
// ...
+
+/**
+ * A simple key-value store.
+ */
+const store: Record<string, unknown> = {};
+
+const kvMessages = nc.subscribe/*(1)!*/("kv.>");
+(async () => {
+ for await (const message of kvMessages) {
+ try {
+ const [_kv, action, ...keyParts] =
+ message.subject.split/*(2)!*/(".");
+
+ const key = keyParts.join(".");
+
+ if (action === "get") {
+ // retrieve the value from the store
+ message.respond(
+ jsonCodec.encode(store[key])
+ );
+ } else if (action === "set") {
+ // set the value in the store
+ store[key] = jsonCodec.decode(message.data);
+ message.respond(jsonCodec.encode({ok: true});
+ }
+ } catch (error) {
+ message.respond(
+ jsonCodec.encode({error: error.message})
+ );
+ }
+ }
+})();
+
kv.>
subject. This matches all subjects that start with kv.
.kv
, the second token is the action, and the rest of the tokens are the key. We store these into variables using array destructuring.In this example, we subscribe to the foo.*
subject. We then use the subject
property of the message to check which action was requested. If the action is get
, we get the value from the store
object and respond with it. If the action is set
, we set the value in the store
object.
For example, if we send a message to the foo.get.bar
subject, we’ll get the value of the bar
key in the store
object. If we send a message to the foo.set.bar
subject with the value 42
, we’ll set the value of the bar
key in the store
object to 42
.
Success
+Woohoo! You’ve just re-implemented a key-value store using the message bus, which (with a few convenience features on top) is an essential part of Telestion’s standard services!
+So far, we’ve looked at publishing messages and subscribing to messages. However, there’s one more thing we can do with the message bus: request/reply.
+Request/reply is a pattern where one service sends a request to another service and waits for a response. This is useful if you want to get data from another service. For example, you could have a service that stores data in a database. Other services can then request data from this service.
+Let’s start by looking at how we can send a request. We can use the request
method on the NatsConnection
object to send a request. This makes it incredibly easy to send a request:
// ...
+
+const response = await nc.request/*(1)!*/(
+ "fooRequest"/*(2)!*/,
+ jsonCodec.encode({foo: "bar"})/*(3)!*/
+);
+console.log(response.data);
+
request
method on the NatsConnection
object. This method returns a Promise
that resolves when the response is received. The response has the same form as the messages we’ve already seen in our for await
loops.jsonCodec
codec. This is the same as we’ve done before.Tip: Specifying a timeout
+As it is, our code will wait forever for a response. This is probably not what we want. We can specify a timeout by passing a second argument to the request
method:
const response = await nc.request(
+ "fooRequest",
+ jsonCodec.encode({foo: "bar"}),
+ {timeout: 1000}
+);
+
This will cause the request
method to reject the Promise
if no response is received within 1000 milliseconds. Make sure to handle the rejection by handling it appropriately.
Now that we know how to send a request, let’s look at how we can handle a request. We can use the subscribe
method on the NatsConnection
object to subscribe to a subject. This allows us to handle requests:
// ...
+
+const requestMessages = nc.subscribe/*(1)!*/("fooRequest");
+
+(async () => {
+ for await (const message of requestMessages) {//(2)!
+ message.respond/*(3)!*/(jsonCodec.encode({bar: "baz"}));
+ }
+})();
+
fooRequest
subject as usual.fooRequest
subject as usual.respond
method on the message object. This method takes a single argument: the response message data. This is the same as we’ve done before.Tip
+The message
received from the fooRequest
subject is the same as the message
received from the foo
subject. This means that we can use the same steps to handle the message as we’ve done before if we need the data to handle the request.
While we’ve covered the basics of interacting with the message bus in this article, there are a few more things you can do with the message bus. You can find more information about the message bus in the NATS documentation. While the connection to the message bus is handled by the startService
function, topics like receiving and sending messages are covered more extensively (including useful concepts like request/reply, queue groups, etc.) in the NATS documentation.
This document describes the pre-requisites for deploying Telestion on your local machine.
+Docker is a containerization platform that allows you to package your application and all its dependencies together in the form of containers to ensure that your application works seamlessly in any environment be it development or test or production.
+Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
+Info
+Kubernetes is not required for deploying Telestion. It’s mostly relevant for big production deployments.
+Kubernetes is an open source container-orchestration system for automating computer application deployment, scaling, and management.
+Info
+For Telestion, a web server is required to serve the frontend application to the user.
+A web server is server software, or hardware dedicated to running said software, that can satisfy web client requests. A web server can, in general, contain one or more websites. A web server processes incoming network requests over HTTP and several other related protocols.
+Info
+Telestion uses NATS as a message broker. It’s required for the communication between the Telestion services (both backend and frontend).
+NATS is a simple, secure and high-performance open source messaging system for cloud native applications, IoT messaging, and microservice architectures.
+ + + + + + + + + + + + + + + + +Deployment is the process of making a software system available for use. In the context of Telestion, deployment refers to the process of making the Telestion application available for use.
+Warning
+The deployment process is heavily dependent on the specific use case. The following documentation is intended to give a general overview of the deployment process that’s available by default in new Telestion Projects.
+Depending on your project, you may need to adapt the deployment process to your specific needs.
+Telestion can be deployed in multiple ways:
+ +Info
+The local deployment is the easiest way to get started with Telestion. You should probably start with the local deployment and then move on to the other deployment methods as needed.
+Telestion uses NATS as a message broker. NATS is a lightweight, high-performance cloud native messaging system. It is used for the communication between the Telestion backend and the Telestion frontend.
+No matter which deployment method you choose, you need to configure NATS. The configuration of NATS is described in the NATS Configuration document.
+ + + + + + + + + + + + + + + + +Telestion can be deployed locally on your machine. This can have several reasons, for example:
+Note
+It’s a common tactic to have most Telestion services running in a cloud environment and only the services that need direct access to the machine running locally.
+This is easy to achieve thanks to NATS and means that you can have the best of both worlds.
+NATS isn’t complicated to deploy. This guide will show you how to deploy NATS locally.
+Download the NATS server from the NATS download page.
+Run the NATS server with the following command:
+ +NATS can be configured using a configuration file. To run NATS with a configuration file, use the following command:
+ +Info
+This guide will focus on getting you started. We’ll look deeper into NATS permissions in the NATS configuration guide.
+In your NATS configuration file, add the following section:
+authorization {
+ default_permissions = {
+ publish = []
+ subscribe = ["__telestion__.>"]
+ }
+ SERVICE = {
+ publish = ["altitude", "log.>"]
+ subscribe = ["altitude", "__telestion__.health"]
+ allow_responses = true
+ }
+ users = [
+ {user: service, password: service, permissions: $SERVICE}
+ ]
+}
+
This will create a user called service
with the password service
. This user will be able to publish to the altitude
subject and subscribe to the __telestion__.health
subject.
(coming soon)
+pup
¶The process manager pup
is a tool that can be used to run multiple services at once without having to manually start each service. It also makes it easy to manage the running services.
pup
¶Install pup
using the following command:
pup
¶In your project’s root directory, create a file called pup.jsonc
with the following contents:
{
+ "services": [
+ {
+ "name": "service1",
+ "command": "deno run --allow-net --allow-env service1.ts",
+ "env": {
+ "SERVICE_NAME": "service1",
+ "NATS_URL": "nats://localhost:4222",
+ "NATS_USER": "service",
+ "NATS_PASSWORD": "service"
+ }
+ },
+ {
+ "name": "service2",
+ "command": "deno run --allow-net --allow-env service2.ts",
+ "env": {
+ "SERVICE_NAME": "service1",
+ "NATS_URL": "nats://localhost:4222",
+ "NATS_USER": "service",
+ "NATS_PASSWORD": "service"
+ }
+ }
+ ]
+}
+
pup
¶Run pup
using the following command:
This will start the pup runner. To start the services, run the following command:
+ +Tip
+If you want to have a service starting immediately after the runner starts, you can add "autostart": true
to that service’s configuration.
To stop the services, run the following command:
+ +Tip
+You can also stop a single service by specifying its name instead of all
.
You can get the status of the services using the following command:
+ +Tip: Running NATS through pup
You can even run NATS through pup
. Just add the following service to your pup.jsonc
file:
You can find more information about pup
on their documentation page.
The NATS server configuration is done via environment variables. The following table lists all available environment variables and their default values.
+Environment Variable | +Default Value | +Description | +
---|---|---|
NATS_HOST |
+localhost |
+The host of the NATS server. | +
NATS_PORT |
+4222 |
+The port of the NATS server. | +
@wuespace/telestion / auth / LoginError
+auth.LoginError
+Error
↳ LoginError
• new LoginError(messages
): LoginError
Name | +Type | +
---|---|
messages |
+ErrorMessages |
+
Error.constructor
+• message: string
Error.message
+• messages: ErrorMessages
• name: string
Error.name
+• Optional
stack: string
Error.stack
+▪ Static
Optional
prepareStackTrace: (err
: Error
, stackTraces
: CallSite
[]) => any
▸ (err
, stackTraces
): any
Optional override for formatting stack traces
+Name | +Type | +
---|---|
err |
+Error |
+
stackTraces |
+CallSite [] |
+
any
See
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
+Error.prepareStackTrace
+▪ Static
stackTraceLimit: number
Error.stackTraceLimit
+▸ captureStackTrace(targetObject
, constructorOpt?
): void
Create .stack property on a target object
+Name | +Type | +
---|---|
targetObject |
+object |
+
constructorOpt? |
+Function |
+
void
Error.captureStackTrace
+ + + + + + + + + + + + + +@wuespace/telestion
+The Telestion Frontend Library.
+Import this library to use the Telestion Frontend:
+ +The most important function is initTelestion. +It initializes the Telestion Frontend and renders the application.
+ +See
Re-exports TelestionOptions
+Re-exports UserData
+Re-exports Widget
+Re-exports initTelestion
+Re-exports registerWidgets
+Re-exports useNats
+Re-exports useWidgetConfig
+ + + + + + + + + + + + + +@wuespace/telestion / application / TelestionOptions
+application.TelestionOptions
+Represents the options for Telestion.
+• Optional
defaultBackendUrl: string
The backend URL that should be inserted by default on first page load.
+• Optional
defaultUserData: Object
Represents the default user data.
+Name | +Type | +Description | +
---|---|---|
dashboards |
+Record <string , { title: string; layout: string[][]; }> |
+The user’s dashboards. | +
version |
+string |
+The version of the client that created this user data. | +
widgetInstances |
+Record <string , { type: string; configuration: Record<string, unknown>; }> |
+The user’s widget instances. | +
• version: string
Represents the current version of the software.
+• Optional
widgets: Widget
<Record
<string
, unknown
>>[]
Represents an array of widgets.
+ + + + + + + + + + + + + +@wuespace/telestion / auth / ErrorMessages
+auth.ErrorMessages
+• Optional
natsUrlMessage: string
• Optional
passwordMessage: string
• Optional
usernameMessage: string
@wuespace/telestion / widget / Widget
+widget.Widget
+A widget that can be used in widget instances on dashboards.
+See
Name | +Type | +Description | +
---|---|---|
T |
+extends Record <string , unknown > = Record <string , unknown > |
+the type of the widget configuration | +
• configElement: ReactNode
A configuration element that is used to configure the widget.
+• element: ReactNode
A function that takes the configuration of the widget and returns a React element that represents the widget.
+• id: string
Represents an identifier of the widget type.
+• label: string
Represents a human-readable label of the widget type.
+▸ createConfig(input
): T
A function that takes an object that contains the previous widget configuration (which may or may not be from a +previous version of the client (or could also, when creating new widget instances, be empty) and returns a valid +configuration for the widget.
+For widgets with expected breaking changes, it is therefore useful to have some version identifier be a part +of the configuration options to enable more complex migration logic in this function.
+Name | +Type | +Description | +
---|---|---|
input |
+Partial <T > & Record <string , unknown > |
+previous configuration or empty | +
T
@wuespace/telestion / application
+▸ initTelestion(options
): Promise
<void
>
Initialize the Telestion application.
+Name | +Type | +Description | +
---|---|---|
options |
+TelestionOptions |
+The options for initializing the application. | +
Promise
<void
>
A Promise that resolves once the initialization is completed.
+▸ useWidgetConfig<T
>(): T
Retrieves the widget configuration from the widgetConfigContext.
+Name | +Description | +
---|---|
T |
+The type of the widget configuration. | +
T
The widget configuration retrieved from the widgetConfigContext.
+Throws
Error Throws an error if useWidgetConfig is not used within a WidgetConfigProvider.
+ + + + + + + + + + + + + +@wuespace/telestion / auth
+▸ getNatsConnection(): null
| NatsConnection
null
| NatsConnection
▸ getUser(): null
| User
Returns the user object if the user is currently logged in, else returns null
if no user is currently logged in.
null
| User
▸ isLoggedIn(): boolean
Checks if a user is logged in.
+boolean
true
if the user is logged in, false
otherwise.
▸ login(natsUrl
, username
, password
): Promise
<null
| User
>
Logs in a user with the given credentials.
+Name | +Type | +Description | +
---|---|---|
natsUrl |
+string |
+The url to connect to the NATS server. | +
username |
+string |
+The username for authentication. | +
password |
+string |
+The password for authentication. | +
A promise that resolves once the user is logged in. +The resolved value is the logged-in user object.
+Throws
Error If the provided credentials are incorrect.
+▸ logout(): Promise
<void
>
Logs out the user if currently logged in.
+Promise
<void
>
A promise that resolves once the user is logged out.
+▸ setNatsConnection(nc
): void
Name | +Type | +
---|---|
nc |
+null | NatsConnection |
+
void
▸ setUser(user
): void
Sets a new user object or null
if the user is no longer logged in.
Name | +Type | +Description | +
---|---|---|
user |
+null | User |
+the user object or null |
+
void
▸ useNats(): NatsConnection
NatsConnection
▸ useNatsSubscription(subject
, callback
, options?
): void
Name | +Type | +
---|---|
subject |
+string |
+
callback |
+(message : Msg ) => void | Promise <void > |
+
options? |
+SubscriptionOptions |
+
void
@wuespace/telestion / userData
+Ƭ Dashboard: Object
Represents a dashboard.
+See
Name | +Type | +Description | +
---|---|---|
layout |
+string [][] |
+The layout of the dashboard. | +
title |
+string |
+The title of the dashboard. | +
Ƭ UserData: Object
Represents the user data.
+See
Name | +Type | +Description | +
---|---|---|
dashboards |
+Record <string , { title: string; layout: string[][]; }> |
+The user’s dashboards. | +
version |
+string |
+The version of the client that created this user data. | +
widgetInstances |
+Record <string , { type: string; configuration: Record<string, unknown>; }> |
+The user’s widget instances. | +
Ƭ WidgetInstance: Object
Represents a widget instance.
+See
Name | +Type | +Description | +
---|---|---|
configuration |
+Record <string , unknown > |
+The configuration of the widget. | +
type |
+string |
+The type ID of the widget. This is used to determine which widget type to use to render the widget. See Widget.id |
+
• Const
dashboardSchema: ZodObject
<Dashboard
>
Represents the schema for a dashboard.
+• Const
idSchema: ZodString
A regular expression that matches valid identifiers.
+Used for dashboard and widget instance IDs.
+See
• Const
layoutSchema: ZodArray
<ZodArray
<ZodUnion
<[ZodString
, ZodLiteral
<"."
>]>, "many"
>, "many"
>
A schema that matches valid layout configurations.
+• Const
semverRegExp: RegExp
A regular expression that matches semantic version numbers.
+Taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
+• Const
userDataSchema: ZodObject
<UserData
>
The schema for the user data.
+See
• Const
widgetInstanceSchema: ZodObject
<WidgetInstance
>
Represents the schema for a widget instance.
+See
▸ getBlankUserData(version
): UserData
Returns a new blank user data object.
+Name | +Type | +Description | +
---|---|---|
version |
+string |
+the current application version | +
▸ getEmptyDashboard(): readonly [id: string, dashboard: Dashboard]
+Returns a new and empty dashboard with a unique id.
+readonly [id: string, dashboard: Dashboard]
+▸ getUserData(): undefined
| { dashboards
: Record
<string
, { title: string; layout: string[][]; }> ; version
: string
; widgetInstances
: Record
<string
, { type: string; configuration: Record<string, unknown>; }> }
Retrieves user data from local storage.
+undefined
| { dashboards
: Record
<string
, { title: string; layout: string[][]; }> ; version
: string
; widgetInstances
: Record
<string
, { type: string; configuration: Record<string, unknown>; }> }
The user data if found in local storage, otherwise undefined.
+▸ removeUserData(): void
Removes the user data from local storage.
+void
▸ setUserData(newUserData
): void
Sets the user data in the local storage based on the given input.
+Name | +Type | +Description | +
---|---|---|
newUserData |
+Object |
+The new user data to be set. | +
newUserData.dashboards |
+Record <string , { title: string; layout: string[][]; }> |
+The user’s dashboards. | +
newUserData.version |
+string |
+The version of the client that created this user data. | +
newUserData.widgetInstances |
+Record <string , { type: string; configuration: Record<string, unknown>; }> |
+The user’s widget instances. | +
void
@wuespace/telestion / utils
+▸ generateDashboardId(): string
Generates a unique identifier for a dashboard.
+string
The generated dashboard identifier.
+▸ isUserDataUpToDate(userData
, currentVersion
): boolean
Checks if the user data is up-to-date with the current version of the application.
+Name | +Type | +Description | +
---|---|---|
userData |
+undefined | { dashboards : Record <string , { title: string; layout: string[][]; }> ; version : string ; widgetInstances : Record <string , { type: string; configuration: Record<string, unknown>; }> } |
+the user data to compare with the application version | +
currentVersion |
+string |
+the current version of the application | +
boolean
▸ loadFileContents(file
, encoding?
): Promise
<string
>
Loads the contents of a specified file.
+Name | +Type | +Default value | +Description | +
---|---|---|---|
file |
+File |
+undefined |
+The file object to load contents from. | +
encoding |
+string |
+'utf-8' |
+The encoding to use while reading the file. Default is UTF-8. | +
Promise
<string
>
▸ wait(timeout
): Promise
<void
>
Waits for the specified amount of time before resolving the returned promise.
+Name | +Type | +Description | +
---|---|---|
timeout |
+number |
+The duration in milliseconds to wait before resolving. | +
Promise
<void
>
A promise that resolves after the specified time has elapsed.
+ + + + + + + + + + + + + +@wuespace/telestion / widget
+• Const
widgetConfigContext: Context
<unknown
>
▸ WidgetRenderer(WidgetRendererProps
): Element
Renders a widget based on the provided widgetInstanceId.
+Name | +Type | +Description | +
---|---|---|
WidgetRendererProps |
+WidgetRendererProps |
+The props for the WidgetRenderer. | +
Element
The rendered widget.
+Throws
Error If the widget instance is not found.
+▸ getWidgetById(id
): undefined
| Widget
<Record
<string
, unknown
>>
Retrieves a widget by its unique type ID.
+Name | +Type | +Description | +
---|---|---|
id |
+string |
+The unique type ID of the widget. | +
undefined
| Widget
<Record
<string
, unknown
>>
The widget associated with the ID, or null if the widget is not found.
+▸ getWidgets(): Widget
<Record
<string
, unknown
>>[]
Returns an array of all the widgets that are currently registered.
+Widget
<Record
<string
, unknown
>>[]
An array containing all the widgets.
+▸ registerWidgets(...widgets
): void
Registers widgets in the widget store.
+If a widget with the same ID already exists in the widget store, a warning is logged and the widget is ignored.
+Name | +Type | +Description | +
---|---|---|
...widgets |
+Widget <Record <string , unknown >>[] |
+The widgets to be registered. | +
void
This document describes the various concepts you need to know when building components for the Telestion frontend.
+The Telestion frontend is the part of Telestion that is visible to the user. It is built with React and TypeScript. It is responsible for displaying data from the backend and for sending commands to the backend.
+HTML, CSS, and JavaScript are the three core technologies of the web. HTML is used to describe the structure of web pages. CSS is used to describe the presentation of web pages. JavaScript is used to describe the behavior of web pages.
+The Telestion frontend is built with React. React is a JavaScript library for building user interfaces. It is component-based and declarative. This means that you can build your UI from small, reusable components and that you can describe how your UI should look like without having to worry about how it is rendered.
+Components are the building blocks of React applications. They are small, reusable pieces of code that can be composed to build more complex components. Components can be either functional or class-based. Functional components are just functions that return a React element.
+JSX is a syntax extension to JavaScript that allows you to write HTML-like code in your JavaScript files. It is not required to use JSX when writing React applications, but it is recommended. JSX makes your code more readable and easier to write. It also allows you to use the full power of JavaScript inside your HTML-like code.
+Props are the way to pass data from a parent component to a child component. They are immutable and can only be changed by the parent component. Props are passed to a component as attributes in JSX.
+State is the way to store data inside a component. It is mutable and can be changed by the component itself.
+You can initialize and use state using the useState()
hook like this:
const [counter, setCounter] = useCounter(0); // initialize with 0
+setCounter(counter + 1); // increase counter by 1
+
Hooks are a new feature that was introduced in React 16.8. They allow you to use state and other React features without writing a class. Hooks are functions that can be called inside functional components. They allow you to use state and other React features without writing a class.
+The Telestion frontend is written in TypeScript. TypeScript is a superset of JavaScript that adds static typing to the language. It is a strict superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code. TypeScript is a statically typed language, which means that the type of a variable is known at compile time. This allows the compiler to catch many errors at compile time instead of at runtime.
+ + + + + + + + + + + + + + + + +Processing data is only half the fun. To make the data accessible to the user, you need a frontend.
+Telestion uses a frontend based on React, TypeScript, and Bootstrap. +Thankfully, Telestion (together with vite) provides a lot of tools to make frontend development as easy as possible.
+All you need to get started is an installation of Node.js and pnpm.
+To create a new frontend, create a new directory for it:
+ +Now, add the following files to your directory:
+package.json
¶{
+ "name": "telestion-frontend",
+ "version": "1.0.0",
+ "type": "module",
+ "dependencies": {
+ "@wuespace/telestion": "^1.0.0-alpha.2",// (1)!
+ "react": "^18.2.0",
+ "zod": "^3.22.4"// (2)!
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react-swc": "^4.2.1",
+ "vite": "^5.0.8"
+ }
+}
+
@wuespace/telestion
package as a dependency. This package contains all the tools you need to get started with frontend development.zod
package as a dependency. This package is used to validate any data that is sent to the frontend.vite.config.ts
¶import { defineConfig } from "vite";
+import react from '@vitejs/plugin-react-swc';
+
+export default defineConfig({
+ plugins: [react()/*(1)!*/],
+});
+
react
plugin to vite. This plugin allows you to use React in your frontend.index.html
¶<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Telestion Frontend</title>
+ </head>
+ <body data-bs-theme="dark"><!-- (1)! -->
+ <div id="root"></div><!-- (2)! -->
+ <script type="module" src="/index.ts"></script><!-- (3)! -->
+ </body>
+</html>
+
data-bs-theme
attribute to the body
tag. This attribute is used to set the default theme of the frontend. You can choose between light
and dark
.div
tag with the id root
. This is where your frontend will be rendered.script
tag that loads the index.ts
file. This file is the entry point of your frontend.index.ts
¶import { initTelestion, registerWidgets } from "@wuespace/telestion"; // (1)!
+
+import "@wuespace/telestion/telestion.css"; // (2)!
+
+// initialize Telestion
+await initTelestion/* (3)!*/({
+ version: "1.0.0",// (4)!
+});
+
+// register your widget in Telestion
+registerWidgets(...);// (5)!
+
initTelestion
and registerWidgets
functions from the @wuespace/telestion
package.telestion.css
file from the @wuespace/telestion
package. This file contains all the styles (including all Bootstrap styles) you need to get started with frontend development.To install the dependencies, run the following command:
+ +To run the frontend, run the following command:
+ +This will start a development server on port 5173. You can now open your browser and navigate to +http://localhost:5173.
+To build the frontend, run the following command:
+ +Now that you have a basic frontend running, you should have a look at how to add widgets to it.
+ + + + + + + + + + + + + +a?1:i>=a?0:NaN}function v6e(){var i=arguments[0];return arguments[0]=this,i.apply(null,arguments),this}function m6e(){return Array.from(this)}function y6e(){for(var i=this._groups,a=0,f=i.length;a 0&&_<1?0:b,new Xv(b,E,_,i.opacity)}function Mke(i,a,f,p){return arguments.length===1?gMt(i):new Xv(i,a,f,p??1)}function Xv(i,a,f,p){this.h=+i,this.s=+a,this.l=+f,this.opacity=+p}_P(Xv,Mke,MU(U7,{brighter(i){return i=i==null?DU:Math.pow(DU,i),new Xv(this.h,this.s,this.l*i,this.opacity)},darker(i){return i=i==null?SP:Math.pow(SP,i),new Xv(this.h,this.s,this.l*i,this.opacity)},rgb(){var i=this.h%360+(this.h<0)*360,a=isNaN(i)||isNaN(this.s)?0:this.s,f=this.l,p=f+(f<.5?f:1-f)*a,w=2*f-p;return new v0(c1t(i>=240?i-240:i+120,w,p),c1t(i,w,p),c1t(i<120?i+240:i-120,w,p),this.opacity)},clamp(){return new Xv(pMt(this.h),PU(this.s),PU(this.l),OU(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 i=OU(this.opacity);return`${i===1?"hsl(":"hsla("}${pMt(this.h)}, ${PU(this.s)*100}%, ${PU(this.l)*100}%${i===1?")":`, ${i})`}`}}));function pMt(i){return i=(i||0)%360,i<0?i+360:i}function PU(i){return Math.max(0,Math.min(1,i||0))}function c1t(i,a,f){return(i<60?a+(f-a)*i/60:i<180?f:i<240?a+(f-a)*(240-i)/60:a)*255}const Dke=Math.PI/180,Ike=180/Math.PI,FU=18,bMt=.96422,wMt=1,vMt=.82521,mMt=4/29,TA=6/29,yMt=3*TA*TA,Oke=TA*TA*TA;function xMt(i){if(i instanceof u3)return new u3(i.l,i.a,i.b,i.opacity);if(i instanceof b5)return kMt(i);i instanceof v0||(i=lMt(i));var a=f1t(i.r),f=f1t(i.g),p=f1t(i.b),w=u1t((.2225045*a+.7168786*f+.0606169*p)/wMt),m,b;return a===f&&f===p?m=b=w:(m=u1t((.4360747*a+.3850649*f+.1430804*p)/bMt),b=u1t((.0139322*a+.0971045*f+.7141733*p)/vMt)),new u3(116*w-16,500*(m-w),200*(w-b),i.opacity)}function Pke(i,a,f,p){return arguments.length===1?xMt(i):new u3(i,a,f,p??1)}function u3(i,a,f,p){this.l=+i,this.a=+a,this.b=+f,this.opacity=+p}_P(u3,Pke,MU(U7,{brighter(i){return new u3(this.l+FU*(i??1),this.a,this.b,this.opacity)},darker(i){return new u3(this.l-FU*(i??1),this.a,this.b,this.opacity)},rgb(){var i=(this.l+16)/116,a=isNaN(this.a)?i:i+this.a/500,f=isNaN(this.b)?i:i-this.b/200;return a=bMt*l1t(a),i=wMt*l1t(i),f=vMt*l1t(f),new v0(h1t(3.1338561*a-1.6168667*i-.4906146*f),h1t(-.9787684*a+1.9161415*i+.033454*f),h1t(.0719453*a-.2289914*i+1.4052427*f),this.opacity)}}));function u1t(i){return i>Oke?Math.pow(i,1/3):i/yMt+mMt}function l1t(i){return i>TA?i*i*i:yMt*(i-mMt)}function h1t(i){return 255*(i<=.0031308?12.92*i:1.055*Math.pow(i,1/2.4)-.055)}function f1t(i){return(i/=255)<=.04045?i/12.92:Math.pow((i+.055)/1.055,2.4)}function Fke(i){if(i instanceof b5)return new b5(i.h,i.c,i.l,i.opacity);if(i instanceof u3||(i=xMt(i)),i.a===0&&i.b===0)return new b5(NaN,0 a&&(f=i,i=a,a=f),function(p){return Math.max(i,Math.min(a,p))}}function IEe(i,a,f){var p=i[0],w=i[1],m=a[0],b=a[1];return w 2?OEe:IEe,_=A=null,B}function B(N){return N==null||isNaN(N=+N)?m:(_||(_=E(i.map(p),a,f)))(p(b(N)))}return B.invert=function(N){return b(w((A||(A=E(a,i.map(p),Qv)))(N)))},B.domain=function(N){return arguments.length?(i=Array.from(N,MEe),I()):i.slice()},B.range=function(N){return arguments.length?(a=Array.from(N),I()):a.slice()},B.rangeRound=function(N){return a=Array.from(N),f=Uke,I()},B.clamp=function(N){return arguments.length?(b=N?!0:SA,I()):b!==SA},B.interpolate=function(N){return arguments.length?(f=N,I()):f},B.unknown=function(N){return arguments.length?(m=N,B):m},function(N,R){return p=N,w=R,I()}}function QMt(){return PEe()(SA,SA)}function FEe(i,a,f,p){var w=t1t(i,a,f),m;switch(p=WU(p??",f"),p.type){case"s":{var b=Math.max(Math.abs(i),Math.abs(a));return p.precision==null&&!isNaN(m=SEe(w,b))&&(p.precision=m),WMt(p,b)}case"":case"e":case"g":case"p":case"r":{p.precision==null&&!isNaN(m=AEe(w,Math.max(Math.abs(i),Math.abs(a))))&&(p.precision=m-(p.type==="e"));break}case"f":case"%":{p.precision==null&&!isNaN(m=_Ee(w))&&(p.precision=m-(p.type==="%")*2);break}}return UMt(p)}function NEe(i){var a=i.domain;return i.ticks=function(f){var p=a();return Axe(p[0],p[p.length-1],f??10)},i.tickFormat=function(f,p){var w=a();return FEe(w[0],w[w.length-1],f??10,p)},i.nice=function(f){f==null&&(f=10);var p=a(),w=0,m=p.length-1,b=p[w],E=p[m],_,A,I=10;for(E0;){if(A=Jft(b,E,f),A===_)return p[w]=b,p[m]=E,a(p);if(A>0)b=Math.floor(b/A)*A,E=Math.ceil(E/A)*A;else if(A<0)b=Math.ceil(b*A)/A,E=Math.floor(E*A)/A;else break;_=A}return i},i}function AA(){var i=QMt();return i.copy=function(){return XMt(i,AA())},KU.apply(i,arguments),NEe(i)}function BEe(i,a){i=i.slice();var f=0,p=i.length-1,w=i[f],m=i[p],b;return m {f+=zIt(w,a),a=w});const p=f/2;return adt(i,p)}function oSe(i){return i.length===1?i[0]:aSe(i)}const qIt=(i,a=2)=>{const f=Math.pow(10,a);return Math.round(i*f)/f},adt=(i,a)=>{let f,p=a;for(const w of i){if(f){const m=zIt(w,f);if(m =1)return{x:w.x,y:w.y};if(b>0&&b<1)return{x:qIt((1-b)*f.x+b*w.x,5),y:qIt((1-b)*f.y+b*w.y,5)}}}f=w}throw new Error("Could not find a suitable point for the given distance")},cSe=(i,a,f)=>{Ut.info(`our points ${JSON.stringify(a)}`),a[0]!==f&&(a=a.reverse());const w=adt(a,25),m=i?10:5,b=Math.atan2(a[0].y-w.y,a[0].x-w.x),E={x:0,y:0};return E.x=Math.sin(b)*m+(a[0].x+w.x)/2,E.y=-Math.cos(b)*m+(a[0].y+w.y)/2,E};function uSe(i,a,f){const p=structuredClone(f);Ut.info("our points",p),a!=="start_left"&&a!=="start_right"&&p.reverse();const w=25+i,m=adt(p,w),b=10+i*.5,E=Math.atan2(p[0].y-m.y,p[0].x-m.x),_={x:0,y:0};return a==="start_left"?(_.x=Math.sin(E+Math.PI)*b+(p[0].x+m.x)/2,_.y=-Math.cos(E+Math.PI)*b+(p[0].y+m.y)/2):a==="end_right"?(_.x=Math.sin(E-Math.PI)*b+(p[0].x+m.x)/2-5,_.y=-Math.cos(E-Math.PI)*b+(p[0].y+m.y)/2-5):a==="end_left"?(_.x=Math.sin(E)*b+(p[0].x+m.x)/2-5,_.y=-Math.cos(E)*b+(p[0].y+m.y)/2-5):(_.x=Math.sin(E)*b+(p[0].x+m.x)/2,_.y=-Math.cos(E)*b+(p[0].y+m.y)/2),_}function im(i){let a="",f="";for(const p of i)p!==void 0&&(p.startsWith("color:")||p.startsWith("text-align:")?f=f+p+";":a=a+p+";");return{style:a,labelStyle:f}}let HIt=0;const VIt=()=>(HIt++,"id-"+Math.random().toString(36).substr(2,12)+"-"+HIt);function lSe(i){let a="";const f="0123456789abcdef",p=f.length;for(let w=0;wlSe(i.length),hSe=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:""}},fSe=function(i,a){const f=a.text.replace(Kr.lineBreakRegex," "),[,p]=VA(a.fontSize),w=i.append("text");w.attr("x",a.x),w.attr("y",a.y),w.style("text-anchor",a.anchor),w.style("font-family",a.fontFamily),w.style("font-size",p),w.style("font-weight",a.fontWeight),w.attr("fill",a.fill),a.class!==void 0&&w.attr("class",a.class);const m=w.append("tspan");return m.attr("x",a.x+a.textMargin*2),m.attr("fill",a.fill),m.text(f),w},UIt=jA((i,a,f)=>{if(!i||(f=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",joinWith:" 0?N[st]+" "+at:ldt(at,/&\f/g,N[st])))&&(_[et++]=bt);return hdt(i,a,f,w===0?KIt:E,_,A,I)}function MSe(i,a,f){return hdt(i,a,f,YIt,udt(xSe()),sF(i,2,-2),0)}function eOt(i,a,f,p){return hdt(i,a,f,XIt,sF(i,0,p),sF(i,p+1,-1),p)}function pdt(i,a){for(var f="",p=ZIt(i),w=0;w {let f=Z1({},i),p={};for(const w of a)aOt(w),p=Z1(p,w);if(f=Z1(f,p),p.theme&&p.theme in T5){const w=Z1({},rOt),m=Z1(w.themeVariables||{},p.themeVariables);f.theme&&f.theme in T5&&(f.themeVariables=T5[f.theme].getThemeVariables(m))}return aF=f,cOt(aF),aF},ISe=i=>(fp=Z1({},WA),fp=Z1(fp,i),i.theme&&T5[i.theme]&&(fp.themeVariables=T5[i.theme].getThemeVariables(i.themeVariables)),jW(fp,YA),fp),OSe=i=>{rOt=Z1({},i)},PSe=i=>(fp=Z1(fp,i),jW(fp,YA),fp),iOt=()=>Z1({},fp),sOt=i=>(cOt(i),Z1(aF,i),Fd()),Fd=()=>Z1({},aF),aOt=i=>{i&&(["secure",...fp.secure??[]].forEach(a=>{Object.hasOwn(i,a)&&(Ut.debug(`Denied attempt to modify a secure key ${a}`,i[a]),delete i[a])}),Object.keys(i).forEach(a=>{a.startsWith("__")&&delete i[a]}),Object.keys(i).forEach(a=>{typeof i[a]=="string"&&(i[a].includes("<")||i[a].includes(">")||i[a].includes("url(data:"))&&delete i[a],typeof i[a]=="object"&&aOt(i[a])}))},FSe=i=>{mW(i),i.fontFamily&&(!i.themeVariables||!i.themeVariables.fontFamily)&&(i.themeVariables={fontFamily:i.fontFamily}),YA.push(i),jW(fp,YA)},$W=(i=fp)=>{YA=[],jW(i,YA)},NSe={LAZY_LOAD_DEPRECATED:"The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead."},oOt={},BSe=i=>{oOt[i]||(Ut.warn(NSe[i]),oOt[i]=!0)},cOt=i=>{i&&(i.lazyLoadedDiagrams||i.loadExternalDiagramsAtStartup)&&BSe("LAZY_LOAD_DEPRECATED")},uOt="c4",RSe={id:uOt,detector:i=>/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>nIe);return{id:uOt,diagram:i}}},lOt="flowchart",jSe={id:lOt,detector:(i,a)=>{var f,p;return((f=a==null?void 0:a.flowchart)==null?void 0:f.defaultRenderer)==="dagre-wrapper"||((p=a==null?void 0:a.flowchart)==null?void 0:p.defaultRenderer)==="elk"?!1:/^\s*graph/.test(i)},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>cze);return{id:lOt,diagram:i}}},hOt="flowchart-v2",$Se={id:hOt,detector:(i,a)=>{var f,p,w;return((f=a==null?void 0:a.flowchart)==null?void 0:f.defaultRenderer)==="dagre-d3"||((p=a==null?void 0:a.flowchart)==null?void 0:p.defaultRenderer)==="elk"?!1:/^\s*graph/.test(i)&&((w=a==null?void 0:a.flowchart)==null?void 0:w.defaultRenderer)==="dagre-wrapper"?!0:/^\s*flowchart/.test(i)},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>uze);return{id:hOt,diagram:i}}},fOt="er",zSe={id:fOt,detector:i=>/^\s*erDiagram/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>Fze);return{id:fOt,diagram:i}}},dOt="gitGraph",qSe={id:dOt,detector:i=>/^\s*gitGraph/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>aqe);return{id:dOt,diagram:i}}},gOt="gantt",HSe={id:gOt,detector:i=>/^\s*gantt/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>Kqe);return{id:gOt,diagram:i}}},pOt="info",VSe={id:pOt,detector:i=>/^\s*info/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>Qqe);return{id:pOt,diagram:i}}},bOt="pie",GSe={id:bOt,detector:i=>/^\s*pie/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>rHe);return{id:bOt,diagram:i}}},wOt="quadrantChart",USe={id:wOt,detector:i=>/^\s*quadrantChart/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>mHe);return{id:wOt,diagram:i}}},vOt="xychart",WSe={id:vOt,detector:i=>/^\s*xychart-beta/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>HHe);return{id:vOt,diagram:i}}},mOt="requirement",YSe={id:mOt,detector:i=>/^\s*requirement(Diagram)?/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>JHe);return{id:mOt,diagram:i}}},yOt="sequence",KSe={id:yOt,detector:i=>/^\s*sequenceDiagram/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>iGe);return{id:yOt,diagram:i}}},xOt="class",XSe={id:xOt,detector:(i,a)=>{var f;return((f=a==null?void 0:a.class)==null?void 0:f.defaultRenderer)==="dagre-wrapper"?!1:/^\s*classDiagram/.test(i)},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>AGe);return{id:xOt,diagram:i}}},kOt="classDiagram",QSe={id:kOt,detector:(i,a)=>{var f;return/^\s*classDiagram/.test(i)&&((f=a==null?void 0:a.class)==null?void 0:f.defaultRenderer)==="dagre-wrapper"?!0:/^\s*classDiagram-v2/.test(i)},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>PGe);return{id:kOt,diagram:i}}},EOt="state",ZSe={id:EOt,detector:(i,a)=>{var f;return((f=a==null?void 0:a.state)==null?void 0:f.defaultRenderer)==="dagre-wrapper"?!1:/^\s*stateDiagram/.test(i)},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>xUe);return{id:EOt,diagram:i}}},TOt="stateDiagram",JSe={id:TOt,detector:(i,a)=>{var f;return!!(/^\s*stateDiagram-v2/.test(i)||/^\s*stateDiagram/.test(i)&&((f=a==null?void 0:a.state)==null?void 0:f.defaultRenderer)==="dagre-wrapper")},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>$Ue);return{id:TOt,diagram:i}}},COt="journey",tAe={id:COt,detector:i=>/^\s*journey/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>sWe);return{id:COt,diagram:i}}},eAe=function(i,a){for(let f of a)i.attr(f[0],f[1])},nAe=function(i,a,f){let p=new Map;return f?(p.set("width","100%"),p.set("style",`max-width: ${a}px;`)):(p.set("height",i),p.set("width",a)),p},k0=function(i,a,f,p){const w=nAe(a,f,p);eAe(i,w)},fT=function(i,a,f,p){const w=a.node().getBBox(),m=w.width,b=w.height;Ut.info(`SVG bounds: ${m}x${b}`,w);let E=0,_=0;Ut.info(`Graph bounds: ${E}x${_}`,i),E=m+f*2,_=b+f*2,Ut.info(`Calculated bounds: ${E}x${_}`),k0(a,_,E,p);const A=`${w.x-f} ${w.y-f} ${w.width+2*f} ${w.height+2*f}`;a.attr("viewBox",A)},zW={},rAe=(i,a,f)=>{let p="";return i in zW&&zW[i]?p=zW[i](f):Ut.warn(`No theme found for ${i}`),` & {
+ font-family: ${f.fontFamily};
+ font-size: ${f.fontSize};
+ fill: ${f.textColor}
+ }
+
+ /* Classes common for multiple diagrams */
+
+ & .error-icon {
+ fill: ${f.errorBkgColor};
+ }
+ & .error-text {
+ fill: ${f.errorTextColor};
+ stroke: ${f.errorTextColor};
+ }
+
+ & .edge-thickness-normal {
+ stroke-width: 2px;
+ }
+ & .edge-thickness-thick {
+ stroke-width: 3.5px
+ }
+ & .edge-pattern-solid {
+ stroke-dasharray: 0;
+ }
+
+ & .edge-pattern-dashed{
+ stroke-dasharray: 3;
+ }
+ .edge-pattern-dotted {
+ stroke-dasharray: 2;
+ }
+
+ & .marker {
+ fill: ${f.lineColor};
+ stroke: ${f.lineColor};
+ }
+ & .marker.cross {
+ stroke: ${f.lineColor};
+ }
+
+ & svg {
+ font-family: ${f.fontFamily};
+ font-size: ${f.fontSize};
+ }
+
+ ${p}
+
+ ${a}
+`},iAe=(i,a)=>{a!==void 0&&(zW[i]=a)},sAe=rAe;let bdt="",wdt="",vdt="";const mdt=i=>Q1(i,Fd()),hg=()=>{bdt="",vdt="",wdt=""},E0=i=>{bdt=mdt(i).replace(/^\s+/g,"")},fg=()=>bdt,dg=i=>{vdt=mdt(i).replace(/\n\s+/g,`
+`)},gg=()=>vdt,Nb=i=>{wdt=mdt(i)},pg=()=>wdt,_Ot=Object.freeze(Object.defineProperty({__proto__:null,clear:hg,getAccDescription:gg,getAccTitle:fg,getDiagramTitle:pg,setAccDescription:dg,setAccTitle:E0,setDiagramTitle:Nb},Symbol.toStringTag,{value:"Module"})),aAe=Ut,oAe=Xft,Oe=Fd,cAe=sOt,SOt=WA,uAe=i=>Q1(i,Oe()),AOt=fT,lAe=()=>_Ot,qW={},HW=(i,a,f)=>{var p;if(qW[i])throw new Error(`Diagram ${i} already registered.`);qW[i]=a,f&&uIt(i,f),iAe(i,a.styles),(p=a.injectUtils)==null||p.call(a,aAe,oAe,Oe,uAe,AOt,lAe(),()=>{})},ydt=i=>{if(i in qW)return qW[i];throw new hAe(i)};class hAe extends Error{constructor(a){super(`Diagram ${a} not found.`)}}const VW=i=>{var w;const{securityLevel:a}=Oe();let f=yr("body");if(a==="sandbox"){const b=((w=yr(`#i${i}`).node())==null?void 0:w.contentDocument)??document;f=yr(b.body)}return f.select(`#${i}`)},LOt={draw:(i,a,f)=>{Ut.debug(`renering svg for syntax error
+`);const p=VW(a);p.attr("viewBox","0 0 2412 512"),k0(p,100,512,!0);const w=p.append("g");w.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"),w.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"),w.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"),w.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"),w.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"),w.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"),w.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"),w.append("text").attr("class","error-text").attr("x",1250).attr("y",400).attr("font-size","100px").style("text-anchor","middle").text(`mermaid version ${f}`)}},fAe=LOt,dAe={db:{},renderer:LOt,parser:{parser:{yy:{}},parse:()=>{}}},MOt="flowchart-elk",gAe={id:MOt,detector:(i,a)=>{var f;return!!(/^\s*flowchart-elk/.test(i)||/^\s*flowchart|graph/.test(i)&&((f=a==null?void 0:a.flowchart)==null?void 0:f.defaultRenderer)==="elk")},loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>xWe);return{id:MOt,diagram:i}}},DOt="timeline",pAe={id:DOt,detector:i=>/^\s*timeline/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>$We);return{id:DOt,diagram:i}}},IOt="mindmap",bAe={id:IOt,detector:i=>/^\s*mindmap/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>bYe);return{id:IOt,diagram:i}}},OOt="sankey",wAe={id:OOt,detector:i=>/^\s*sankey-beta/.test(i),loader:async()=>{const{diagram:i}=await Promise.resolve().then(()=>UYe);return{id:OOt,diagram:i}}};let POt=!1;const xdt=()=>{POt||(POt=!0,HW("error",dAe,i=>i.toLowerCase().trim()==="error"),HW("---",{db:{clear:()=>{}},styles:{},renderer:{draw:()=>{}},parser:{parser:{yy:{}},parse:()=>{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")}},init:()=>null},i=>i.toLowerCase().trimStart().startsWith("---")),cIt(RSe,QSe,XSe,zSe,HSe,VSe,GSe,YSe,KSe,gAe,$Se,jSe,bAe,pAe,qSe,JSe,ZSe,tAe,USe,wAe,WSe))};class FOt{constructor(a,f={}){this.text=a,this.metadata=f,this.type="graph",this.text+=`
+`;const p=Fd();try{this.type=yW(a,p)}catch(m){this.type="error",this.detectError=m}const w=ydt(this.type);Ut.debug("Type "+this.type),this.db=w.db,this.renderer=w.renderer,this.parser=w.parser,this.parser.parser.yy=this.db,this.init=w.init,this.parse()}parse(){var f,p,w,m,b;if(this.detectError)throw this.detectError;(p=(f=this.db).clear)==null||p.call(f);const a=Fd();(w=this.init)==null||w.call(this,a),this.metadata.title&&((b=(m=this.db).setDiagramTitle)==null||b.call(m,this.metadata.title)),this.parser.parse(this.text)}async render(a,f){await this.renderer.draw(this.text,a,f,this)}getParser(){return this.parser}getType(){return this.type}}const kdt=async(i,a={})=>{const f=yW(i,Fd());try{ydt(f)}catch{const w=ECe(f);if(!w)throw new oIt(`Diagram ${f} not found.`);const{id:m,diagram:b}=await w();HW(m,b)}return new FOt(i,a)};let Edt=[];const vAe=i=>{Edt.push(i)},mAe=()=>{Edt.forEach(i=>{i()}),Edt=[]};var yAe=kIt(Object.keys,Object);const xAe=yAe;var kAe=Object.prototype,EAe=kAe.hasOwnProperty;function NOt(i){if(!_W(i))return xAe(i);var a=[];for(var f in Object(i))EAe.call(i,f)&&f!="constructor"&&a.push(f);return a}var TAe=oT(nm,"DataView");const Tdt=TAe;var CAe=oT(nm,"Promise");const Cdt=CAe;var _Ae=oT(nm,"Set");const KA=_Ae;var SAe=oT(nm,"WeakMap");const _dt=SAe;var BOt="[object Map]",AAe="[object Object]",ROt="[object Promise]",jOt="[object Set]",$Ot="[object WeakMap]",zOt="[object DataView]",LAe=aT(Tdt),MAe=aT(JP),DAe=aT(Cdt),IAe=aT(KA),OAe=aT(_dt),dT=sT;(Tdt&&dT(new Tdt(new ArrayBuffer(1)))!=zOt||JP&&dT(new JP)!=BOt||Cdt&&dT(Cdt.resolve())!=ROt||KA&&dT(new KA)!=jOt||_dt&&dT(new _dt)!=$Ot)&&(dT=function(i){var a=sT(i),f=a==AAe?i.constructor:void 0,p=f?aT(f):"";if(p)switch(p){case LAe:return zOt;case MAe:return BOt;case DAe:return ROt;case IAe:return jOt;case OAe:return $Ot}return a});const XA=dT;var PAe="[object Map]",FAe="[object Set]",NAe=Object.prototype,BAe=NAe.hasOwnProperty;function oF(i){if(i==null)return!0;if(ck(i)&&(If(i)||typeof i=="string"||typeof i.splice=="function"||zA(i)||AW(i)||$A(i)))return!i.length;var a=XA(i);if(a==PAe||a==FAe)return!i.size;if(_W(i))return!NOt(i).length;for(var f in i)if(BAe.call(i,f))return!1;return!0}const RAe="graphics-document document";function jAe(i,a){i.attr("role",RAe),a!==""&&i.attr("aria-roledescription",a)}function $Ae(i,a,f,p){if(i.insert!==void 0){if(f){const w=`chart-desc-${p}`;i.attr("aria-describedby",w),i.insert("desc",":first-child").attr("id",w).text(f)}if(a){const w=`chart-title-${p}`;i.attr("aria-labelledby",w),i.insert("title",":first-child").attr("id",w).text(a)}}}const zAe=i=>i.replace(/^\s*%%(?!{)[^\n]+\n?/gm,"").trimStart();/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */function qOt(i){return typeof i>"u"||i===null}function qAe(i){return typeof i=="object"&&i!==null}function HAe(i){return Array.isArray(i)?i:qOt(i)?[]:[i]}function VAe(i,a){var f,p,w,m;if(a)for(m=Object.keys(a),f=0,p=m.length;f E&&(m=" ... ",a=p-E+m.length),f-p>E&&(b=" ...",f=p+E-b.length),{str:m+i.slice(a,f).replace(/\t/g,"→")+b,pos:p-a+m.length}}function Adt(i,a){return bg.repeat(" ",a-i.length)+i}function JAe(i,a){if(a=Object.create(a||null),!i.buffer)return null;a.maxLength||(a.maxLength=79),typeof a.indent!="number"&&(a.indent=1),typeof a.linesBefore!="number"&&(a.linesBefore=3),typeof a.linesAfter!="number"&&(a.linesAfter=2);for(var f=/\r?\n|\r|\0/g,p=[0],w=[],m,b=-1;m=f.exec(i.buffer);)w.push(m.index),p.push(m.index+m[0].length),i.position<=m.index&&b<0&&(b=p.length-2);b<0&&(b=p.length-1);var E="",_,A,I=Math.min(i.line+a.linesAfter,w.length).toString().length,B=a.maxLength-(a.indent+I+3);for(_=1;_<=a.linesBefore&&!(b-_<0);_++)A=Sdt(i.buffer,p[b-_],w[b-_],i.position-(p[b]-p[b-_]),B),E=bg.repeat(" ",a.indent)+Adt((i.line-_+1).toString(),I)+" | "+A.str+`
+`+E;for(A=Sdt(i.buffer,p[b],w[b],i.position,B),E+=bg.repeat(" ",a.indent)+Adt((i.line+1).toString(),I)+" | "+A.str+`
+`,E+=bg.repeat("-",a.indent+I+3+A.pos)+`^
+`,_=1;_<=a.linesAfter&&!(b+_>=w.length);_++)A=Sdt(i.buffer,p[b+_],w[b+_],i.position-(p[b]-p[b+_]),B),E+=bg.repeat(" ",a.indent)+Adt((i.line+_+1).toString(),I)+" | "+A.str+`
+`;return E.replace(/\n$/,"")}var tLe=JAe,eLe=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],nLe=["scalar","sequence","mapping"];function rLe(i){var a={};return i!==null&&Object.keys(i).forEach(function(f){i[f].forEach(function(p){a[String(p)]=f})}),a}function iLe(i,a){if(a=a||{},Object.keys(a).forEach(function(f){if(eLe.indexOf(f)===-1)throw new A5('Unknown option "'+f+'" is met in definition of "'+i+'" YAML type.')}),this.options=a,this.tag=i,this.kind=a.kind||null,this.resolve=a.resolve||function(){return!0},this.construct=a.construct||function(f){return f},this.instanceOf=a.instanceOf||null,this.predicate=a.predicate||null,this.represent=a.represent||null,this.representName=a.representName||null,this.defaultStyle=a.defaultStyle||null,this.multi=a.multi||!1,this.styleAliases=rLe(a.styleAliases||null),nLe.indexOf(this.kind)===-1)throw new A5('Unknown kind "'+this.kind+'" is specified for "'+i+'" YAML type.')}var T0=iLe;function VOt(i,a){var f=[];return i[a].forEach(function(p){var w=f.length;f.forEach(function(m,b){m.tag===p.tag&&m.kind===p.kind&&m.multi===p.multi&&(w=b)}),f[w]=p}),f}function sLe(){var i={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}},a,f;function p(w){w.multi?(i.multi[w.kind].push(w),i.multi.fallback.push(w)):i[w.kind][w.tag]=i.fallback[w.tag]=w}for(a=0,f=arguments.length;a >10)+55296,(i-65536&1023)+56320)}for(var ePt=new Array(256),nPt=new Array(256),ZA=0;ZA<256;ZA++)ePt[ZA]=tPt(ZA)?1:0,nPt[ZA]=tPt(ZA);function dMe(i,a){this.input=i,this.filename=a.filename||null,this.schema=a.schema||iMe,this.onWarning=a.onWarning||null,this.legacy=a.legacy||!1,this.json=a.json||!1,this.listener=a.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=i.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function rPt(i,a){var f={name:i.filename,buffer:i.input.slice(0,-1),position:i.position,line:i.line,column:i.position-i.lineStart};return f.snippet=tLe(f),new A5(a,f)}function Ss(i,a){throw rPt(i,a)}function WW(i,a){i.onWarning&&i.onWarning.call(null,rPt(i,a))}var iPt={YAML:function(a,f,p){var w,m,b;a.version!==null&&Ss(a,"duplication of %YAML directive"),p.length!==1&&Ss(a,"YAML directive accepts exactly one argument"),w=/^([0-9]+)\.([0-9]+)$/.exec(p[0]),w===null&&Ss(a,"ill-formed argument of the YAML directive"),m=parseInt(w[1],10),b=parseInt(w[2],10),m!==1&&Ss(a,"unacceptable YAML version of the document"),a.version=p[0],a.checkLineBreaks=b<2,b!==1&&b!==2&&WW(a,"unsupported YAML version of the document")},TAG:function(a,f,p){var w,m;p.length!==2&&Ss(a,"TAG directive accepts exactly two arguments"),w=p[0],m=p[1],QOt.test(w)||Ss(a,"ill-formed tag handle (first argument) of the TAG directive"),lk.call(a.tagMap,w)&&Ss(a,'there is a previously declared suffix for "'+w+'" tag handle'),ZOt.test(m)||Ss(a,"ill-formed tag prefix (second argument) of the TAG directive");try{m=decodeURIComponent(m)}catch{Ss(a,"tag prefix is malformed: "+m)}a.tagMap[w]=m}};function hk(i,a,f,p){var w,m,b,E;if(a -1}function Rb(i){return ck(i)?PIt(i):NOt(i)}var LIe=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,MIe=/^\w*$/;function Udt(i,a){if(If(i))return!1;var f=typeof i;return f=="number"||f=="symbol"||f=="boolean"||i==null||vT(i)?!0:MIe.test(i)||!LIe.test(i)||a!=null&&i in Object(a)}var DIe=500;function IIe(i){var a=jA(i,function(p){return f.size===DIe&&f.clear(),p}),f=a.cache;return a}var OIe=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,PIe=/\\(\\)?/g,FIe=IIe(function(i){var a=[];return i.charCodeAt(0)===46&&a.push(""),i.replace(OIe,function(f,p,w,m){a.push(w?m.replace(PIe,"$1"):p||f)}),a});const NIe=FIe;function fFt(i){return i==null?"":oFt(i)}function hY(i,a){return If(i)?i:Udt(i,a)?[i]:NIe(fFt(i))}var BIe=1/0;function gF(i){if(typeof i=="string"||vT(i))return i;var a=i+"";return a=="0"&&1/i==-BIe?"-0":a}function fY(i,a){a=hY(a,i);for(var f=0,p=a.length;i!=null&&f 0&&f(E)?a>1?dY(E,a-1,f,p,w):Wdt(w,E):p||(w[w.length]=E)}return w}function rL(i){var a=i==null?0:i.length;return a?dY(i,1):[]}function $Ie(i){return RIt(BIt(i,void 0,rL),i+"")}function zIe(i,a,f,p){var w=-1,m=i==null?0:i.length;for(p&&m&&(f=i[++w]);++w -1?w[m?a[b]:b]:void 0}}var iFe=Math.max;function sFe(i,a,f){var p=i==null?0:i.length;if(!p)return-1;var w=f==null?0:EIe(f);return w<0&&(w=iFe(p+w,0)),hFt(i,pk(a),w)}var aFe=rFe(sFe);const e0t=aFe;function RFt(i,a){var f=-1,p=ck(i)?Array(i.length):[];return pY(i,function(w,m,b){p[++f]=a(w,m,b)}),p}function Ff(i,a){var f=If(i)?nL:RFt;return f(i,pk(a))}function oFe(i,a){return i==null?i:tdt(i,t0t(a),uT)}function cFe(i,a){return i&&Jdt(i,t0t(a))}function uFe(i,a){return i>a}var lFe=Object.prototype,hFe=lFe.hasOwnProperty;function fFe(i,a){return i!=null&&hFe.call(i,a)}function za(i,a){return i!=null&&PFt(i,a,fFe)}function dFe(i,a){return nL(a,function(f){return i[f]})}function I5(i){return i==null?[]:dFe(i,Rb(i))}function Jh(i){return i===void 0}function jFt(i,a){return ia||m&&b&&_&&!E&&!A||p&&b&&_||!f&&_||!w)return 1;if(!p&&!m&&!A&&i=E)return _;var A=f[p];return _*(A=="desc"?-1:1)}}return i.index-a.index}function mFe(i,a,f){a.length?a=nL(a,function(m){return If(m)?function(b){return fY(b,m.length===1?m[0]:m)}:m}):a=[lT];var p=-1;a=nL(a,SW(pk));var w=RFt(i,function(m,b,E){var _=nL(a,function(A){return A(m)});return{criteria:_,index:++p,value:m}});return bFe(w,function(m,b){return vFe(m,b,f)})}function yFe(i,a){return pFe(i,a,function(f,p){return FFt(i,p)})}var xFe=$Ie(function(i,a){return i==null?{}:yFe(i,a)});const vF=xFe;var kFe=Math.ceil,EFe=Math.max;function TFe(i,a,f,p){for(var w=-1,m=EFe(kFe((a-i)/(f||1)),0),b=Array(m);m--;)b[p?m:++w]=i,i+=f;return b}function CFe(i){return function(a,f,p){return p&&typeof p!="number"&&nF(a,f,p)&&(f=p=void 0),a=lY(a),f===void 0?(f=a,a=0):f=lY(f),p=p===void 0?a ${p.children.map(f).join("")} b&&(N=E-(I-b)/2);const z=1-Oe().state.textHeight;return i.insert("rect",":first-child").attr("x",N).attr("y",z).attr("class",f?"alt-composit":"composit").attr("width",B).attr("height",R.height+Oe().state.textHeight+Oe().state.titleShift+1).attr("rx","0"),_.attr("x",N+p),I<=b&&_.attr("x",E+(B-w)/2-I/2+p),i.insert("rect",":first-child").attr("x",N).attr("y",Oe().state.titleShift-Oe().state.textHeight-Oe().state.padding).attr("width",B).attr("height",Oe().state.textHeight*3).attr("rx",Oe().state.radius),i.insert("rect",":first-child").attr("x",N).attr("y",Oe().state.titleShift-Oe().state.textHeight-Oe().state.padding).attr("width",B).attr("height",R.height+3+2*Oe().state.textHeight).attr("rx",Oe().state.radius),i},fUe=i=>(i.append("circle").attr("class","end-state-outer").attr("r",Oe().state.sizeUnit+Oe().state.miniPadding).attr("cx",Oe().state.padding+Oe().state.sizeUnit+Oe().state.miniPadding).attr("cy",Oe().state.padding+Oe().state.sizeUnit+Oe().state.miniPadding),i.append("circle").attr("class","end-state-inner").attr("r",Oe().state.sizeUnit).attr("cx",Oe().state.padding+Oe().state.sizeUnit+2).attr("cy",Oe().state.padding+Oe().state.sizeUnit+2)),dUe=(i,a)=>{let f=Oe().state.forkWidth,p=Oe().state.forkHeight;if(a.parentId){let w=f;f=p,p=w}return i.append("rect").style("stroke","black").style("fill","black").attr("width",f).attr("height",p).attr("x",Oe().state.padding).attr("y",Oe().state.padding)},gUe=(i,a,f,p)=>{let w=0;const m=p.append("text");m.style("text-anchor","start"),m.attr("class","noteText");let b=i.replace(/\r\n/g,"
/gi,YTe=i=>i?ZDt(i).replace(/\\n/g,"#br#").split("#br#"):[""],XDt=i=>lW.sanitize(i),QDt=(i,a)=>{var f;if(((f=a.flowchart)==null?void 0:f.htmlLabels)!==!1){const p=a.securityLevel;p==="antiscript"||p==="strict"?i=XDt(i):p!=="loose"&&(i=ZDt(i),i=i.replace(//g,">"),i=i.replace(/=/g,"="),i=ZTe(i))}return i},Q1=(i,a)=>i&&(a.dompurifyConfig?i=lW.sanitize(QDt(i,a),a.dompurifyConfig).toString():i=lW.sanitize(QDt(i,a),{FORBID_TAGS:["style"]}).toString(),i),KTe=(i,a)=>typeof i=="string"?Q1(i,a):i.flat().map(f=>Q1(f,a)),XTe=i=>WP.test(i),QTe=i=>i.split(WP),ZTe=i=>i.replace(/#br#/g,"
"),ZDt=i=>i.replace(WP,"#br#"),JTe=i=>{let a="";return i&&(a=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,a=a.replaceAll(/\(/g,"\\("),a=a.replaceAll(/\)/g,"\\)")),a},o1=i=>!(i===!1||["false","null","0"].includes(String(i).trim().toLowerCase())),tCe=function(...i){const a=i.filter(f=>!isNaN(f));return Math.max(...a)},eCe=function(...i){const a=i.filter(f=>!isNaN(f));return Math.min(...a)},YP=function(i){const a=i.split(/(,)/),f=[];for(let p=0;p
"},f),Kr.lineBreakRegex.test(i)))return i;const p=i.split(" "),w=[];let m="";return p.forEach((b,E)=>{const _=d3(`${b} `,f),A=d3(m,f);if(_>a){const{hyphenatedStrings:N,remainingWord:R}=dSe(b,a,"-",f);w.push(m,...N),m=R}else A+_>=a?(w.push(m),m=b):m=[m,b].filter(Boolean).join(" ");E+1===p.length&&w.push(m)}),w.filter(b=>b!=="").join(f.joinWith)},(i,a,f)=>`${i}${a}${f.fontSize}${f.fontWeight}${f.fontFamily}${f.joinWith}`),dSe=jA((i,a,f="-",p)=>{p=Object.assign({fontSize:12,fontWeight:400,fontFamily:"Arial",margin:0},p);const w=[...i],m=[];let b="";return w.forEach((E,_)=>{const A=`${b}${E}`;if(d3(A,p)>=a){const B=_+1,N=w.length===B,R=`${A}${f}`;m.push(N?A:R),b=""}else b=A}),{hyphenatedStrings:m,remainingWord:b}},(i,a,f="-",p)=>`${i}${a}${f}${p.fontSize}${p.fontWeight}${p.fontFamily}`);function odt(i,a){return cdt(i,a).height}function d3(i,a){return cdt(i,a).width}const cdt=jA((i,a)=>{const{fontSize:f=12,fontFamily:p="Arial",fontWeight:w=400}=a;if(!i)return{width:0,height:0};const[,m]=VA(f),b=["sans-serif",p],E=i.split(Kr.lineBreakRegex),_=[],A=yr("body");if(!A.remove)return{width:0,height:0,lineHeight:0};const I=A.append("svg");for(const N of b){let R=0;const z={width:0,height:0,lineHeight:0};for(const W of E){const et=hSe();et.text=W||jIt;const st=fSe(I,et).style("font-size",m).style("font-weight",w).style("font-family",N),at=(st._groups||st)[0][0].getBBox();if(at.width===0&&at.height===0)throw new Error("svg element not in render tree");z.width=Math.round(Math.max(z.width,at.width)),R=Math.round(at.height),z.height+=R,z.lineHeight=Math.round(Math.max(z.lineHeight,R))}_.push(z)}I.remove();const B=isNaN(_[1].height)||isNaN(_[1].width)||isNaN(_[1].lineHeight)||_[0].height>_[1].height&&_[0].width>_[1].width&&_[0].lineHeight>_[1].lineHeight?0:1;return _[B]},(i,a)=>`${i}${a.fontSize}${a.fontWeight}${a.fontFamily}`);class gSe{constructor(a=!1,f){this.count=0,this.count=f?f.length:0,this.next=a?()=>this.count++:()=>Date.now()}}let OW;const pSe=function(i){return OW=OW||document.createElement("div"),i=escape(i).replace(/%26/g,"&").replace(/%23/g,"#").replace(/%3B/g,";"),OW.innerHTML=i,unescape(OW.textContent)};function WIt(i){return"str"in i}const bSe=(i,a,f,p)=>{var m;if(!p)return;const w=(m=i.node())==null?void 0:m.getBBox();w&&i.append("text").text(p).attr("x",w.x+w.width/2).attr("y",-f).attr("class",a)},VA=i=>{if(typeof i=="number")return[i,i+"px"];const a=parseInt(i??"",10);return Number.isNaN(a)?[void 0,void 0]:i===String(a)?[a,i+"px"]:[a,i]};function rF(i,a){return IW({},i,a)}const $a={assignWithDepth:Z1,wrapLabel:UIt,calculateTextHeight:odt,calculateTextWidth:d3,calculateTextDimensions:cdt,cleanAndMerge:rF,detectInit:eSe,detectDirective:$It,isSubstringInArray:rSe,interpolateToCurve:ew,calcLabelPosition:oSe,calcCardinalityPosition:cSe,calcTerminalLabelPosition:uSe,formatUrl:iSe,getStylesFromArray:im,generateId:VIt,random:GIt,runFunc:sSe,entityDecode:pSe,insertTitle:bSe,parseFontSize:VA,InitIDGenerator:gSe};var YIt="comm",KIt="rule",XIt="decl",wSe="@import",vSe="@keyframes",mSe=Math.abs,udt=String.fromCharCode;function QIt(i){return i.trim()}function ldt(i,a,f){return i.replace(a,f)}function ySe(i,a){return i.indexOf(a)}function iF(i,a){return i.charCodeAt(a)|0}function sF(i,a,f){return i.slice(a,f)}function uk(i){return i.length}function ZIt(i){return i.length}function PW(i,a){return a.push(i),i}var FW=1,GA=1,JIt=0,nw=0,Of=0,UA="";function hdt(i,a,f,p,w,m,b){return{value:i,root:a,parent:f,type:p,props:w,children:m,line:FW,column:GA,length:b,return:""}}function xSe(){return Of}function kSe(){return Of=nw>0?iF(UA,--nw):0,GA--,Of===10&&(GA=1,FW--),Of}function sm(){return Of=nw
/g,"
"),p},nDe=(i="",a)=>{var w,m;const f=(m=(w=a==null?void 0:a.viewBox)==null?void 0:w.baseVal)!=null&&m.height?a.viewBox.baseVal.height+"px":VMe,p=btoa(''+i+"");return``},lPt=(i,a,f,p,w)=>{const m=i.append("div");m.attr("id",f),p&&m.attr("style",p);const b=m.append("svg").attr("id",a).attr("width","100%").attr("xmlns",$Me);return w&&b.attr("xmlns:xlink",w),b.append("g"),i};function hPt(i,a){return i.append("iframe").attr("id",a).attr("style","width: 100%; height: 100%;").attr("sandbox","")}const rDe=(i,a,f,p)=>{var w,m,b;(w=i.getElementById(a))==null||w.remove(),(m=i.getElementById(f))==null||m.remove(),(b=i.getElementById(p))==null||b.remove()},iDe=async function(i,a,f){var nt,It,Ot,Bt,Et,Z;xdt();const p=cPt(a);a=p.code;const w=Fd();Ut.debug(w),a.length>((w==null?void 0:w.maxTextSize)??NMe)&&(a=BMe);const m="#"+i,b="i"+i,E="#"+b,_="d"+i,A="#"+_;let I=yr("body");const B=w.securityLevel===RMe,N=w.securityLevel===jMe,R=w.fontFamily;if(f!==void 0){if(f&&(f.innerHTML=""),B){const Ct=hPt(yr(f),b);I=yr(Ct.nodes()[0].contentDocument.body),I.node().style.margin=0}else I=yr(f);lPt(I,i,_,`font-family: ${R}`,zMe)}else{if(rDe(document,i,_,b),B){const Ct=hPt(yr("body"),b);I=yr(Ct.nodes()[0].contentDocument.body),I.node().style.margin=0}else I=yr("body");lPt(I,i,_)}a=ZMe(a);let z,W;try{z=await kdt(a,{title:p.title})}catch(Ct){z=new FOt("error"),W=Ct}const et=I.select(A).node(),st=z.type,at=et.firstChild,bt=at.firstChild,mt=(It=(nt=z.renderer).getClasses)==null?void 0:It.call(nt,a,z),yt=tDe(w,st,mt,m),ft=document.createElement("style");ft.innerHTML=yt,at.insertBefore(ft,bt);try{await z.renderer.draw(a,i,nOt,z)}catch(Ct){throw fAe.draw(a,i,nOt),Ct}const ut=I.select(`${A} svg`),vt=(Bt=(Ot=z.db).getAccTitle)==null?void 0:Bt.call(Ot),X=(Z=(Et=z.db).getAccDescription)==null?void 0:Z.call(Et);aDe(st,ut,vt,X),I.select(`[id="${i}"]`).selectAll("foreignobject > *").attr("xmlns",qMe);let pt=I.select(A).node().innerHTML;if(Ut.debug("config.arrowMarkerAbsolute",w.arrowMarkerAbsolute),pt=eDe(pt,B,o1(w.arrowMarkerAbsolute)),B){const Ct=I.select(A+" svg").node();pt=nDe(pt,Ct)}else N||(pt=lW.sanitize(pt,{ADD_TAGS:KMe,ADD_ATTR:XMe}));if(mAe(),W)throw W;const Tt=yr(B?E:A).node();return Tt&&"remove"in Tt&&Tt.remove(),{svg:pt,bindFunctions:z.db.bindFunctions}};function sDe(i={}){var f;i!=null&&i.fontFamily&&!((f=i.themeVariables)!=null&&f.fontFamily)&&(i.themeVariables||(i.themeVariables={}),i.themeVariables.fontFamily=i.fontFamily),OSe(i),i!=null&&i.theme&&i.theme in T5?i.themeVariables=T5[i.theme].getThemeVariables(i.themeVariables):i&&(i.themeVariables=T5.default.getThemeVariables(i.themeVariables));const a=typeof i=="object"?ISe(i):iOt();Xft(a.logLevel),xdt()}function aDe(i,a,f,p){jAe(a,i),$Ae(a,f,p,a.attr("id"))}const pT=Object.freeze({render:iDe,parse:QMe,getDiagramFromText:kdt,initialize:sDe,getConfig:Fd,setConfig:sOt,getSiteConfig:iOt,updateSiteConfig:PSe,reset:()=>{$W()},globalReset:()=>{$W(WA)},defaultConfig:WA});Xft(Fd().logLevel),$W(Fd());const oDe=async()=>{Ut.debug("Loading registered diagrams");const a=(await Promise.allSettled(Object.entries(NA).map(async([f,{detector:p,loader:w}])=>{if(w)try{ydt(f)}catch{try{const{diagram:b,id:E}=await w();HW(E,b,p)}catch(b){throw Ut.error(`Failed to load external diagram with key ${f}. Removing from detectors.`),delete NA[f],b}}}))).filter(f=>f.status==="rejected");if(a.length>0){Ut.error(`Failed to load ${a.length} external diagrams`);for(const f of a)Ut.error(f);throw new Error(`Failed to load ${a.length} external diagrams`)}},cDe=(i,a,f)=>{Ut.warn(i),WIt(i)?(f&&f(i.str,i.hash),a.push({...i,message:i.str,error:i})):(f&&f(i),i instanceof Error&&a.push({str:i.message,message:i.message,hash:i.name,error:i}))},fPt=async function(i={querySelector:".mermaid"}){try{await uDe(i)}catch(a){if(WIt(a)&&Ut.error(a.str),Bb.parseError&&Bb.parseError(a),!i.suppressErrors)throw Ut.error("Use the suppressErrors option to suppress these errors"),a}},uDe=async function({postRenderCallback:i,querySelector:a,nodes:f}={querySelector:".mermaid"}){const p=pT.getConfig();Ut.debug(`${i?"":"No "}Callback function found`);let w;if(f)w=f;else if(a)w=document.querySelectorAll(a);else throw new Error("Nodes and querySelector are both undefined");Ut.debug(`Found ${w.length} diagrams`),(p==null?void 0:p.startOnLoad)!==void 0&&(Ut.debug("Start On Load: "+(p==null?void 0:p.startOnLoad)),pT.updateSiteConfig({startOnLoad:p==null?void 0:p.startOnLoad}));const m=new $a.InitIDGenerator(p.deterministicIds,p.deterministicIDSeed);let b;const E=[];for(const _ of Array.from(w)){Ut.info("Rendering diagram: "+_.id);/*! Check if previously processed */if(_.getAttribute("data-processed"))continue;_.setAttribute("data-processed","true");const A=`mermaid-${m.next()}`;b=_.innerHTML,b=xA($a.entityDecode(b)).trim().replace(/
/gi,"
");const I=$a.detectInit(b);I&&Ut.debug("Detected early reinit: ",I);try{const{svg:B,bindFunctions:N}=await bPt(A,b,_);_.innerHTML=B,i&&await i(A),N&&N(_)}catch(B){cDe(B,E,Bb.parseError)}}if(E.length>0)throw E[0]},dPt=function(i){pT.initialize(i)},lDe=async function(i,a,f){Ut.warn("mermaid.init is deprecated. Please use run instead."),i&&dPt(i);const p={postRenderCallback:f,querySelector:".mermaid"};typeof a=="string"?p.querySelector=a:a&&(a instanceof HTMLElement?p.nodes=[a]:p.nodes=a),await fPt(p)},hDe=async(i,{lazyLoad:a=!0}={})=>{cIt(...i),a===!1&&await oDe()},gPt=function(){if(Bb.startOnLoad){const{startOnLoad:i}=pT.getConfig();i&&Bb.run().catch(a=>Ut.error("Mermaid failed to initialize",a))}};if(typeof document<"u"){/*!
+ * Wait for document loaded before starting the execution
+ */window.addEventListener("load",gPt,!1)}const fDe=function(i){Bb.parseError=i},KW=[];let Pdt=!1;const pPt=async()=>{if(!Pdt){for(Pdt=!0;KW.length>0;){const i=KW.shift();if(i)try{await i()}catch(a){Ut.error("Error executing queue",a)}}Pdt=!1}},dDe=async(i,a)=>new Promise((f,p)=>{const w=()=>new Promise((m,b)=>{pT.parse(i,a).then(E=>{m(E),f(E)},E=>{var _;Ut.error("Error parsing",E),(_=Bb.parseError)==null||_.call(Bb,E),b(E),p(E)})});KW.push(w),pPt().catch(p)}),bPt=(i,a,f)=>new Promise((p,w)=>{const m=()=>new Promise((b,E)=>{pT.render(i,a,f).then(_=>{b(_),p(_)},_=>{var A;Ut.error("Error parsing",_),(A=Bb.parseError)==null||A.call(Bb,_),E(_),w(_)})});KW.push(m),pPt().catch(w)}),Bb={startOnLoad:!0,mermaidAPI:pT,parse:dDe,render:bPt,init:lDe,run:fPt,registerExternalDiagrams:hDe,initialize:dPt,parseError:void 0,contentLoaded:gPt,setParseErrorHandler:fDe,detectType:yW};var XW=function(){var i=function(Xi,Er,Xn,di){for(Xn=Xn||{},di=Xi.length;di--;Xn[Xi[di]]=Er);return Xn},a=[1,24],f=[1,25],p=[1,26],w=[1,27],m=[1,28],b=[1,63],E=[1,64],_=[1,65],A=[1,66],I=[1,67],B=[1,68],N=[1,69],R=[1,29],z=[1,30],W=[1,31],et=[1,32],st=[1,33],at=[1,34],bt=[1,35],mt=[1,36],yt=[1,37],ft=[1,38],ut=[1,39],vt=[1,40],X=[1,41],pt=[1,42],U=[1,43],Tt=[1,44],nt=[1,45],It=[1,46],Ot=[1,47],Bt=[1,48],Et=[1,50],Z=[1,51],Ct=[1,52],xt=[1,53],Ht=[1,54],Le=[1,55],Ft=[1,56],gn=[1,57],Se=[1,58],me=[1,59],Ve=[1,60],Ye=[14,42],ce=[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],ke=[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],zt=[1,82],re=[1,83],se=[1,84],Pe=[1,85],te=[12,14,42],Me=[12,14,33,42],de=[12,14,33,42,76,77,79,80],on=[12,33],ni=[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],Ks={trace:function(){},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:function(Er,Xn,di,Ee,Kn,He,Ti){var pn=He.length-1;switch(Kn){case 3:Ee.setDirection("TB");break;case 4:Ee.setDirection("BT");break;case 5:Ee.setDirection("RL");break;case 6:Ee.setDirection("LR");break;case 8:case 9:case 10:case 11:case 12:Ee.setC4Type(He[pn-3]);break;case 19:Ee.setTitle(He[pn].substring(6)),this.$=He[pn].substring(6);break;case 20:Ee.setAccDescription(He[pn].substring(15)),this.$=He[pn].substring(15);break;case 21:this.$=He[pn].trim(),Ee.setTitle(this.$);break;case 22:case 23:this.$=He[pn].trim(),Ee.setAccDescription(this.$);break;case 28:case 29:He[pn].splice(2,0,"ENTERPRISE"),Ee.addPersonOrSystemBoundary(...He[pn]),this.$=He[pn];break;case 30:Ee.addPersonOrSystemBoundary(...He[pn]),this.$=He[pn];break;case 31:He[pn].splice(2,0,"CONTAINER"),Ee.addContainerBoundary(...He[pn]),this.$=He[pn];break;case 32:Ee.addDeploymentNode("node",...He[pn]),this.$=He[pn];break;case 33:Ee.addDeploymentNode("nodeL",...He[pn]),this.$=He[pn];break;case 34:Ee.addDeploymentNode("nodeR",...He[pn]),this.$=He[pn];break;case 35:Ee.popBoundaryParseStack();break;case 39:Ee.addPersonOrSystem("person",...He[pn]),this.$=He[pn];break;case 40:Ee.addPersonOrSystem("external_person",...He[pn]),this.$=He[pn];break;case 41:Ee.addPersonOrSystem("system",...He[pn]),this.$=He[pn];break;case 42:Ee.addPersonOrSystem("system_db",...He[pn]),this.$=He[pn];break;case 43:Ee.addPersonOrSystem("system_queue",...He[pn]),this.$=He[pn];break;case 44:Ee.addPersonOrSystem("external_system",...He[pn]),this.$=He[pn];break;case 45:Ee.addPersonOrSystem("external_system_db",...He[pn]),this.$=He[pn];break;case 46:Ee.addPersonOrSystem("external_system_queue",...He[pn]),this.$=He[pn];break;case 47:Ee.addContainer("container",...He[pn]),this.$=He[pn];break;case 48:Ee.addContainer("container_db",...He[pn]),this.$=He[pn];break;case 49:Ee.addContainer("container_queue",...He[pn]),this.$=He[pn];break;case 50:Ee.addContainer("external_container",...He[pn]),this.$=He[pn];break;case 51:Ee.addContainer("external_container_db",...He[pn]),this.$=He[pn];break;case 52:Ee.addContainer("external_container_queue",...He[pn]),this.$=He[pn];break;case 53:Ee.addComponent("component",...He[pn]),this.$=He[pn];break;case 54:Ee.addComponent("component_db",...He[pn]),this.$=He[pn];break;case 55:Ee.addComponent("component_queue",...He[pn]),this.$=He[pn];break;case 56:Ee.addComponent("external_component",...He[pn]),this.$=He[pn];break;case 57:Ee.addComponent("external_component_db",...He[pn]),this.$=He[pn];break;case 58:Ee.addComponent("external_component_queue",...He[pn]),this.$=He[pn];break;case 60:Ee.addRel("rel",...He[pn]),this.$=He[pn];break;case 61:Ee.addRel("birel",...He[pn]),this.$=He[pn];break;case 62:Ee.addRel("rel_u",...He[pn]),this.$=He[pn];break;case 63:Ee.addRel("rel_d",...He[pn]),this.$=He[pn];break;case 64:Ee.addRel("rel_l",...He[pn]),this.$=He[pn];break;case 65:Ee.addRel("rel_r",...He[pn]),this.$=He[pn];break;case 66:Ee.addRel("rel_b",...He[pn]),this.$=He[pn];break;case 67:He[pn].splice(0,1),Ee.addRel("rel",...He[pn]),this.$=He[pn];break;case 68:Ee.updateElStyle("update_el_style",...He[pn]),this.$=He[pn];break;case 69:Ee.updateRelStyle("update_rel_style",...He[pn]),this.$=He[pn];break;case 70:Ee.updateLayoutConfig("update_layout_config",...He[pn]),this.$=He[pn];break;case 71:this.$=[He[pn]];break;case 72:He[pn].unshift(He[pn-1]),this.$=He[pn];break;case 73:case 75:this.$=He[pn].trim();break;case 74:let Es={};Es[He[pn-1].trim()]=He[pn].trim(),this.$=Es;break;case 76:this.$="";break}},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:a,23:f,24:p,26:w,28:m,29:49,30:61,32:62,34:b,36:E,37:_,38:A,39:I,40:B,41:N,43:23,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve},{13:70,19:20,20:21,21:22,22:a,23:f,24:p,26:w,28:m,29:49,30:61,32:62,34:b,36:E,37:_,38:A,39:I,40:B,41:N,43:23,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve},{13:71,19:20,20:21,21:22,22:a,23:f,24:p,26:w,28:m,29:49,30:61,32:62,34:b,36:E,37:_,38:A,39:I,40:B,41:N,43:23,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve},{13:72,19:20,20:21,21:22,22:a,23:f,24:p,26:w,28:m,29:49,30:61,32:62,34:b,36:E,37:_,38:A,39:I,40:B,41:N,43:23,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve},{13:73,19:20,20:21,21:22,22:a,23:f,24:p,26:w,28:m,29:49,30:61,32:62,34:b,36:E,37:_,38:A,39:I,40:B,41:N,43:23,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve},{14:[1,74]},i(Ye,[2,13],{43:23,29:49,30:61,32:62,20:75,34:b,36:E,37:_,38:A,39:I,40:B,41:N,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve}),i(Ye,[2,14]),i(ce,[2,16],{12:[1,76]}),i(Ye,[2,36],{12:[1,77]}),i(ke,[2,19]),i(ke,[2,20]),{25:[1,78]},{27:[1,79]},i(ke,[2,23]),{35:80,75:81,76:zt,77:re,79:se,80:Pe},{35:86,75:81,76:zt,77:re,79:se,80:Pe},{35:87,75:81,76:zt,77:re,79:se,80:Pe},{35:88,75:81,76:zt,77:re,79:se,80:Pe},{35:89,75:81,76:zt,77:re,79:se,80:Pe},{35:90,75:81,76:zt,77:re,79:se,80:Pe},{35:91,75:81,76:zt,77:re,79:se,80:Pe},{35:92,75:81,76:zt,77:re,79:se,80:Pe},{35:93,75:81,76:zt,77:re,79:se,80:Pe},{35:94,75:81,76:zt,77:re,79:se,80:Pe},{35:95,75:81,76:zt,77:re,79:se,80:Pe},{35:96,75:81,76:zt,77:re,79:se,80:Pe},{35:97,75:81,76:zt,77:re,79:se,80:Pe},{35:98,75:81,76:zt,77:re,79:se,80:Pe},{35:99,75:81,76:zt,77:re,79:se,80:Pe},{35:100,75:81,76:zt,77:re,79:se,80:Pe},{35:101,75:81,76:zt,77:re,79:se,80:Pe},{35:102,75:81,76:zt,77:re,79:se,80:Pe},{35:103,75:81,76:zt,77:re,79:se,80:Pe},{35:104,75:81,76:zt,77:re,79:se,80:Pe},i(te,[2,59]),{35:105,75:81,76:zt,77:re,79:se,80:Pe},{35:106,75:81,76:zt,77:re,79:se,80:Pe},{35:107,75:81,76:zt,77:re,79:se,80:Pe},{35:108,75:81,76:zt,77:re,79:se,80:Pe},{35:109,75:81,76:zt,77:re,79:se,80:Pe},{35:110,75:81,76:zt,77:re,79:se,80:Pe},{35:111,75:81,76:zt,77:re,79:se,80:Pe},{35:112,75:81,76:zt,77:re,79:se,80:Pe},{35:113,75:81,76:zt,77:re,79:se,80:Pe},{35:114,75:81,76:zt,77:re,79:se,80:Pe},{35:115,75:81,76:zt,77:re,79:se,80:Pe},{20:116,29:49,30:61,32:62,34:b,36:E,37:_,38:A,39:I,40:B,41:N,43:23,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve},{12:[1,118],33:[1,117]},{35:119,75:81,76:zt,77:re,79:se,80:Pe},{35:120,75:81,76:zt,77:re,79:se,80:Pe},{35:121,75:81,76:zt,77:re,79:se,80:Pe},{35:122,75:81,76:zt,77:re,79:se,80:Pe},{35:123,75:81,76:zt,77:re,79:se,80:Pe},{35:124,75:81,76:zt,77:re,79:se,80:Pe},{35:125,75:81,76:zt,77:re,79:se,80:Pe},{14:[1,126]},{14:[1,127]},{14:[1,128]},{14:[1,129]},{1:[2,8]},i(Ye,[2,15]),i(ce,[2,17],{21:22,19:130,22:a,23:f,24:p,26:w,28:m}),i(Ye,[2,37],{19:20,20:21,21:22,43:23,29:49,30:61,32:62,13:131,22:a,23:f,24:p,26:w,28:m,34:b,36:E,37:_,38:A,39:I,40:B,41:N,44:R,45:z,46:W,47:et,48:st,49:at,50:bt,51:mt,52:yt,53:ft,54:ut,55:vt,56:X,57:pt,58:U,59:Tt,60:nt,61:It,62:Ot,63:Bt,64:Et,65:Z,66:Ct,67:xt,68:Ht,69:Le,70:Ft,71:gn,72:Se,73:me,74:Ve}),i(ke,[2,21]),i(ke,[2,22]),i(te,[2,39]),i(Me,[2,71],{75:81,35:132,76:zt,77:re,79:se,80:Pe}),i(de,[2,73]),{78:[1,133]},i(de,[2,75]),i(de,[2,76]),i(te,[2,40]),i(te,[2,41]),i(te,[2,42]),i(te,[2,43]),i(te,[2,44]),i(te,[2,45]),i(te,[2,46]),i(te,[2,47]),i(te,[2,48]),i(te,[2,49]),i(te,[2,50]),i(te,[2,51]),i(te,[2,52]),i(te,[2,53]),i(te,[2,54]),i(te,[2,55]),i(te,[2,56]),i(te,[2,57]),i(te,[2,58]),i(te,[2,60]),i(te,[2,61]),i(te,[2,62]),i(te,[2,63]),i(te,[2,64]),i(te,[2,65]),i(te,[2,66]),i(te,[2,67]),i(te,[2,68]),i(te,[2,69]),i(te,[2,70]),{31:134,42:[1,135]},{12:[1,136]},{33:[1,137]},i(on,[2,28]),i(on,[2,29]),i(on,[2,30]),i(on,[2,31]),i(on,[2,32]),i(on,[2,33]),i(on,[2,34]),{1:[2,9]},{1:[2,10]},{1:[2,11]},{1:[2,12]},i(ce,[2,18]),i(Ye,[2,38]),i(Me,[2,72]),i(de,[2,74]),i(te,[2,24]),i(te,[2,35]),i(ni,[2,25]),i(ni,[2,26],{12:[1,138]}),i(ni,[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:function(Er,Xn){if(Xn.recoverable)this.trace(Er);else{var di=new Error(Er);throw di.hash=Xn,di}},parse:function(Er){var Xn=this,di=[0],Ee=[],Kn=[null],He=[],Ti=this.table,pn="",Es=0,qa=0,Ma=2,Gs=1,Po=He.slice.call(arguments,1),vs=Object.create(this.lexer),ru={yy:{}};for(var zs in this.yy)Object.prototype.hasOwnProperty.call(this.yy,zs)&&(ru.yy[zs]=this.yy[zs]);vs.setInput(Er,ru.yy),ru.yy.lexer=vs,ru.yy.parser=this,typeof vs.yylloc>"u"&&(vs.yylloc={});var Du=vs.yylloc;He.push(Du);var pm=vs.options&&vs.options.ranges;typeof ru.yy.parseError=="function"?this.parseError=ru.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function uw(){var Dl;return Dl=Ee.pop()||vs.lex()||Gs,typeof Dl!="number"&&(Dl instanceof Array&&(Ee=Dl,Dl=Ee.pop()),Dl=Xn.symbols_[Dl]||Dl),Dl}for(var Wu,th,Fa,Ml,ha={},bc,Cc,pa,Da;;){if(th=di[di.length-1],this.defaultActions[th]?Fa=this.defaultActions[th]:((Wu===null||typeof Wu>"u")&&(Wu=uw()),Fa=Ti[th]&&Ti[th][Wu]),typeof Fa>"u"||!Fa.length||!Fa[0]){var Ha="";Da=[];for(bc in Ti[th])this.terminals_[bc]&&bc>Ma&&Da.push("'"+this.terminals_[bc]+"'");vs.showPosition?Ha="Parse error on line "+(Es+1)+`:
+`+vs.showPosition()+`
+Expecting `+Da.join(", ")+", got '"+(this.terminals_[Wu]||Wu)+"'":Ha="Parse error on line "+(Es+1)+": Unexpected "+(Wu==Gs?"end of input":"'"+(this.terminals_[Wu]||Wu)+"'"),this.parseError(Ha,{text:vs.match,token:this.terminals_[Wu]||Wu,line:vs.yylineno,loc:Du,expected:Da})}if(Fa[0]instanceof Array&&Fa.length>1)throw new Error("Parse Error: multiple actions possible at state: "+th+", token: "+Wu);switch(Fa[0]){case 1:di.push(Wu),Kn.push(vs.yytext),He.push(vs.yylloc),di.push(Fa[1]),Wu=null,qa=vs.yyleng,pn=vs.yytext,Es=vs.yylineno,Du=vs.yylloc;break;case 2:if(Cc=this.productions_[Fa[1]][1],ha.$=Kn[Kn.length-Cc],ha._$={first_line:He[He.length-(Cc||1)].first_line,last_line:He[He.length-1].last_line,first_column:He[He.length-(Cc||1)].first_column,last_column:He[He.length-1].last_column},pm&&(ha._$.range=[He[He.length-(Cc||1)].range[0],He[He.length-1].range[1]]),Ml=this.performAction.apply(ha,[pn,qa,Es,ru.yy,Fa[1],Kn,He].concat(Po)),typeof Ml<"u")return Ml;Cc&&(di=di.slice(0,-1*Cc*2),Kn=Kn.slice(0,-1*Cc),He=He.slice(0,-1*Cc)),di.push(this.productions_[Fa[1]][0]),Kn.push(ha.$),He.push(ha._$),pa=Ti[di[di.length-2]][di[di.length-1]],di.push(pa);break;case 3:return!0}}return!0}},ws=function(){var Xi={EOF:1,parseError:function(Xn,di){if(this.yy.parser)this.yy.parser.parseError(Xn,di);else throw new Error(Xn)},setInput:function(Er,Xn){return this.yy=Xn||this.yy||{},this._input=Er,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},input:function(){var Er=this._input[0];this.yytext+=Er,this.yyleng++,this.offset++,this.match+=Er,this.matched+=Er;var Xn=Er.match(/(?:\r\n?|\n).*/g);return Xn?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),Er},unput:function(Er){var Xn=Er.length,di=Er.split(/(?:\r\n?|\n)/g);this._input=Er+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-Xn),this.offset-=Xn;var Ee=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),di.length-1&&(this.yylineno-=di.length-1);var Kn=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:di?(di.length===Ee.length?this.yylloc.first_column:0)+Ee[Ee.length-di.length].length-di[0].length:this.yylloc.first_column-Xn},this.options.ranges&&(this.yylloc.range=[Kn[0],Kn[0]+this.yyleng-Xn]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return 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).
+`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},less:function(Er){this.unput(this.match.slice(Er))},pastInput:function(){var Er=this.matched.substr(0,this.matched.length-this.match.length);return(Er.length>20?"...":"")+Er.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var Er=this.match;return Er.length<20&&(Er+=this._input.substr(0,20-Er.length)),(Er.substr(0,20)+(Er.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var Er=this.pastInput(),Xn=new Array(Er.length+1).join("-");return Er+this.upcomingInput()+`
+`+Xn+"^"},test_match:function(Er,Xn){var di,Ee,Kn;if(this.options.backtrack_lexer&&(Kn={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&&(Kn.yylloc.range=this.yylloc.range.slice(0))),Ee=Er[0].match(/(?:\r\n?|\n).*/g),Ee&&(this.yylineno+=Ee.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:Ee?Ee[Ee.length-1].length-Ee[Ee.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+Er[0].length},this.yytext+=Er[0],this.match+=Er[0],this.matches=Er,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(Er[0].length),this.matched+=Er[0],di=this.performAction.call(this,this.yy,this,Xn,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),di)return di;if(this._backtrack){for(var He in Kn)this[He]=Kn[He];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var Er,Xn,di,Ee;this._more||(this.yytext="",this.match="");for(var Kn=this._currentRules(),He=0;He
"),Ut.info("vertexText"+w);const m={isNode:p,label:uF(w).replace(/fa[blrs]?:fa-[\w-]+/g,E=>``),labelStyle:a.replace("fill:","color:")};return wRe(m)}else{const m=document.createElementNS("http://www.w3.org/2000/svg","text");m.setAttribute("style",a.replace("color:","fill:"));let b=[];typeof w=="string"?b=w.split(/\\n|\n|
/gi):Array.isArray(w)?b=w:b=[];for(const E of b){const _=document.createElementNS("http://www.w3.org/2000/svg","tspan");_.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),_.setAttribute("dy","1em"),_.setAttribute("x","0"),f?_.setAttribute("class","title-row"):_.setAttribute("class","row"),_.textContent=E.trim(),m.appendChild(_)}return m}},vRe={};function mRe(i,a){const f=a||vRe,p=typeof f.includeImageAlt=="boolean"?f.includeImageAlt:!0,w=typeof f.includeHtml=="boolean"?f.includeHtml:!0;return FNt(i,p,w)}function FNt(i,a,f){if(yRe(i)){if("value"in i)return i.type==="html"&&!f?"":i.value;if(a&&"alt"in i&&i.alt)return i.alt;if("children"in i)return NNt(i.children,a,f)}return Array.isArray(i)?NNt(i,a,f):""}function NNt(i,a,f){const p=[];let w=-1;for(;++w
"):p.type==="strong"?`${p.children.map(f).join("")}`:p.type==="emphasis"?`${p.children.map(f).join("")}`:p.type==="paragraph"?`
"):B,a.labelStyle,!0,!0));if(o1(Oe().flowchart.htmlLabels)){const W=R.children[0],et=yr(R);I=W.getBoundingClientRect(),et.attr("width",I.width),et.attr("height",I.height)}const z=a.padding/2;return yr(R).attr("transform","translate( "+(I.width>N.width?0:(N.width-I.width)/2)+", "+(N.height+z+5)+")"),yr(A).attr("transform","translate( "+(I.width
/gi):Array.isArray(i)?f=i:f=[];for(const p of f){const w=document.createElementNS("http://www.w3.org/2000/svg","tspan");w.setAttributeNS("http://www.w3.org/XML/1998/namespace","xml:space","preserve"),w.setAttribute("dy","1em"),w.setAttribute("x","0"),w.setAttribute("class","row"),w.textContent=p.trim(),a.appendChild(w)}return a},VBt=(i,a,f)=>{const p=Oe().gitGraph,w=i.append("g").attr("class","commit-bullets"),m=i.append("g").attr("class","commit-labels");let b=0;C0==="TB"&&(b=30),Object.keys(a).sort((A,I)=>a[A].seq-a[I].seq).forEach(A=>{const I=a[A],B=C0==="TB"?b+10:td[I.branch].pos,N=C0==="TB"?td[I.branch].pos:b+10;if(f){let R,z=I.customType!==void 0&&I.customType!==""?I.customType:I.type;switch(z){case $b.NORMAL:R="commit-normal";break;case $b.REVERSE:R="commit-reverse";break;case $b.HIGHLIGHT:R="commit-highlight";break;case $b.MERGE:R="commit-merge";break;case $b.CHERRY_PICK:R="commit-cherry-pick";break;default:R="commit-normal"}if(z===$b.HIGHLIGHT){const W=w.append("rect");W.attr("x",N-10),W.attr("y",B-10),W.attr("height",20),W.attr("width",20),W.attr("class",`commit ${I.id} commit-highlight${td[I.branch].index%TT} ${R}-outer`),w.append("rect").attr("x",N-6).attr("y",B-6).attr("height",12).attr("width",12).attr("class",`commit ${I.id} commit${td[I.branch].index%TT} ${R}-inner`)}else if(z===$b.CHERRY_PICK)w.append("circle").attr("cx",N).attr("cy",B).attr("r",10).attr("class",`commit ${I.id} ${R}`),w.append("circle").attr("cx",N-3).attr("cy",B+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${I.id} ${R}`),w.append("circle").attr("cx",N+3).attr("cy",B+2).attr("r",2.75).attr("fill","#fff").attr("class",`commit ${I.id} ${R}`),w.append("line").attr("x1",N+3).attr("y1",B+1).attr("x2",N).attr("y2",B-5).attr("stroke","#fff").attr("class",`commit ${I.id} ${R}`),w.append("line").attr("x1",N-3).attr("y1",B+1).attr("x2",N).attr("y2",B-5).attr("stroke","#fff").attr("class",`commit ${I.id} ${R}`);else{const W=w.append("circle");if(W.attr("cx",N),W.attr("cy",B),W.attr("r",I.type===$b.MERGE?9:10),W.attr("class",`commit ${I.id} commit${td[I.branch].index%TT}`),z===$b.MERGE){const et=w.append("circle");et.attr("cx",N),et.attr("cy",B),et.attr("r",6),et.attr("class",`commit ${R} ${I.id} commit${td[I.branch].index%TT}`)}z===$b.REVERSE&&w.append("path").attr("d",`M ${N-5},${B-5}L${N+5},${B+5}M${N-5},${B+5}L${N+5},${B-5}`).attr("class",`commit ${R} ${I.id} commit${td[I.branch].index%TT}`)}}if(C0==="TB"?DF[I.id]={x:N,y:b+10}:DF[I.id]={x:b+10,y:B},f){if(I.type!==$b.CHERRY_PICK&&(I.customId&&I.type===$b.MERGE||I.type!==$b.MERGE)&&p.showCommitLabel){const W=m.append("g"),et=W.insert("rect").attr("class","commit-label-bkg"),st=W.append("text").attr("x",b).attr("y",B+25).attr("class","commit-label").text(I.id);let at=st.node().getBBox();if(et.attr("x",b+10-at.width/2-2).attr("y",B+13.5).attr("width",at.width+2*2).attr("height",at.height+2*2),C0==="TB"&&(et.attr("x",N-(at.width+4*4+5)).attr("y",B-12),st.attr("x",N-(at.width+4*4)).attr("y",B+at.height-12)),C0!=="TB"&&st.attr("x",b+10-at.width/2),p.rotateCommitLabel)if(C0==="TB")st.attr("transform","rotate(-45, "+N+", "+B+")"),et.attr("transform","rotate(-45, "+N+", "+B+")");else{let bt=-7.5-(at.width+10)/25*9.5,mt=10+at.width/25*8.5;W.attr("transform","translate("+bt+", "+mt+") rotate(-45, "+b+", "+B+")")}}if(I.tag){const W=m.insert("polygon"),et=m.append("circle"),st=m.append("text").attr("y",B-16).attr("class","tag-label").text(I.tag);let at=st.node().getBBox();st.attr("x",b+10-at.width/2);const bt=at.height/2,mt=B-19.2;W.attr("class","tag-label-bkg").attr("points",`
+ ${b-at.width/2-4/2},${mt+2}
+ ${b-at.width/2-4/2},${mt-2}
+ ${b+10-at.width/2-4},${mt-bt-2}
+ ${b+10+at.width/2+4},${mt-bt-2}
+ ${b+10+at.width/2+4},${mt+bt+2}
+ ${b+10-at.width/2-4},${mt+bt+2}`),et.attr("cx",b-at.width/2+4/2).attr("cy",mt).attr("r",1.5).attr("class","tag-hole"),C0==="TB"&&(W.attr("class","tag-label-bkg").attr("points",`
+ ${N},${b+2}
+ ${N},${b-2}
+ ${N+10},${b-bt-2}
+ ${N+10+at.width+4},${b-bt-2}
+ ${N+10+at.width+4},${b+bt+2}
+ ${N+10},${b+bt+2}`).attr("transform","translate(12,12) rotate(45, "+N+","+b+")"),et.attr("cx",N+4/2).attr("cy",b).attr("transform","translate(12,12) rotate(45, "+N+","+b+")"),st.attr("x",N+5).attr("y",b+3).attr("transform","translate(14,14) rotate(45, "+N+","+b+")"))}}b+=50,b>IF&&(IF=b)})},nqe=(i,a,f)=>Object.keys(f).filter(m=>f[m].branch===a.branch&&f[m].seq>i.seq&&f[m].seq
");b=b.replace(/\n/g,"
");const E=b.split(Kr.lineBreakRegex);let _=1.25*Oe().state.noteMargin;for(const A of E){const I=A.trim();if(I.length>0){const B=m.append("tspan");if(B.text(I),_===0){const N=B.node().getBBox();_+=N.height}w+=_,B.attr("x",a+Oe().state.noteMargin),B.attr("y",f+w+1.25*Oe().state.noteMargin)}}return{textWidth:m.node().getBBox().width,textHeight:w}},pUe=(i,a)=>{a.attr("class","state-note");const f=a.append("rect").attr("x",0).attr("y",Oe().state.padding),p=a.append("g"),{textWidth:w,textHeight:m}=gUe(i,0,0,p);return f.attr("height",m+2*Oe().state.noteMargin),f.attr("width",w+Oe().state.noteMargin*2),f},wjt=function(i,a){const f=a.id,p={id:f,label:a.id,width:0,height:0},w=i.append("g").attr("id",f).attr("class","stateGroup");a.type==="start"&&oUe(w),a.type==="end"&&fUe(w),(a.type==="fork"||a.type==="join")&&dUe(w,a),a.type==="note"&&pUe(a.note.text,w),a.type==="divider"&&cUe(w),a.type==="default"&&a.descriptions.length===0&&uUe(w,a),a.type==="default"&&a.descriptions.length>0&&lUe(w,a);const m=w.node().getBBox();return p.width=m.width+2*Oe().state.padding,p.height=m.height+2*Oe().state.padding,aUe.set(f,p),p};let vjt=0;const bUe=function(i,a,f){const p=function(_){switch(_){case $5.relationType.AGGREGATION:return"aggregation";case $5.relationType.EXTENSION:return"extension";case $5.relationType.COMPOSITION:return"composition";case $5.relationType.DEPENDENCY:return"dependency"}};a.points=a.points.filter(_=>!Number.isNaN(_.y));const w=a.points,m=E5().x(function(_){return _.x}).y(function(_){return _.y}).curve(HP),b=i.append("path").attr("d",m(w)).attr("id","edge"+vjt).attr("class","transition");let E="";if(Oe().state.arrowMarkerAbsolute&&(E=window.location.protocol+"//"+window.location.host+window.location.pathname+window.location.search,E=E.replace(/\(/g,"\\("),E=E.replace(/\)/g,"\\)")),b.attr("marker-end","url("+E+"#"+p($5.relationType.DEPENDENCY)+"End)"),f.title!==void 0){const _=i.append("g").attr("class","stateLabel"),{x:A,y:I}=$a.calcLabelPosition(a.points),B=Kr.getRows(f.title);let N=0;const R=[];let z=0,W=0;for(let at=0;at<=B.length;at++){const bt=_.append("text").attr("text-anchor","middle").text(B[at]).attr("x",A).attr("y",I+N),mt=bt.node().getBBox();z=Math.max(z,mt.width),W=Math.min(W,mt.x),Ut.info(mt.x,A,I+N),N===0&&(N=bt.node().getBBox().height,Ut.info("Title height",N,I)),R.push(bt)}let et=N*B.length;if(B.length>1){const at=(B.length-1)*N*.5;R.forEach((bt,mt)=>bt.attr("y",I+mt*N-at)),et=N*B.length}const st=_.node().getBBox();_.insert("rect",":first-child").attr("class","box").attr("x",A-z/2-Oe().state.padding/2).attr("y",I-et/2-Oe().state.padding/2-3.5).attr("width",z+Oe().state.padding).attr("height",et+Oe().state.padding),Ut.info(st)}vjt++};let qb;const jgt={},wUe=function(){},vUe=function(i){i.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")},mUe=function(i,a,f,p){qb=Oe().state;const w=Oe().securityLevel;let m;w==="sandbox"&&(m=yr("#i"+a));const b=yr(w==="sandbox"?m.nodes()[0].contentDocument.body:"body"),E=w==="sandbox"?m.nodes()[0].contentDocument:document;Ut.debug("Rendering diagram "+i);const _=b.select(`[id='${a}']`);vUe(_);const A=p.db.getRootDoc();mjt(A,_,void 0,!1,b,E,p);const I=qb.padding,B=_.node().getBBox(),N=B.width+I*2,R=B.height+I*2,z=N*1.75;k0(_,R,z,qb.useMaxWidth),_.attr("viewBox",`${B.x-qb.padding} ${B.y-qb.padding} `+N+" "+R)},yUe=i=>i?i.length*qb.fontSizeFactor:1,mjt=(i,a,f,p,w,m,b)=>{const E=new c1({compound:!0,multigraph:!0});let _,A=!0;for(_=0;_
/gi);for(let et=0;et0?Fie(t,e):rue(t,-e)}function bmt(t,e){return e==0||t.e==0?t:e>0?rue(t,e):Fie(t,-e)}function Mr(t){if(zr(t))return t.c=t.a,t.a.Pb();throw it(new lc)}function jJt(t){var e,n;return e=t.c.i,n=t.d.i,e.k==(Vn(),ks)&&n.k==ks}function Grt(t){var e;return e=new Vw,Mo(e,t),Jt(e,(Te(),So),null),e}function Urt(t,e,n){var r;return r=t.Yg(e),r>=0?t._g(r,n,!0):dv(t,e,n)}function wmt(t,e,n,r){var s;for(s=0;sr)throw it(new qm(e,r));return t.hi()&&(n=DQt(t,n)),t.Vh(e,n)}function zD(t,e,n){return n==null?(!t.q&&(t.q=new _r),Jx(t.q,e)):(!t.q&&(t.q=new _r),ki(t.q,e,n)),t}function Jt(t,e,n){return n==null?(!t.q&&(t.q=new _r),Jx(t.q,e)):(!t.q&&(t.q=new _r),ki(t.q,e,n)),t}function pre(t){var e,n;return n=new B$,Mo(n,t),Jt(n,(Yp(),I6),t),e=new _r,Pyn(t,n,e),a5n(t,n,e),n}function Oun(t){k4();var e,n,r;for(n=Nt(Ws,ee,8,2,0,1),r=0,e=0;e<2;e++)r+=.5,n[e]=g1n(r,t);return n}function bre(t,e){var n,r,s,o;for(n=!1,r=t.a[e].length,o=0;on)throw it(new yo(Wq+t+Yxt+e+", size: "+n));if(t>e)throw it(new Fn(Wq+t+Dfe+e))}function fh(t,e,n){if(e<0)i5t(t,n);else{if(!n.Ij())throw it(new Fn(lb+n.ne()+X_));u(n,66).Nj().Vj(t,t.yh(),e)}}function Oln(t,e,n,r,s,o,h,d){var v;for(v=n;o=s)return e.c+n;return e.c+e.b.gc()}function xhn(t,e){y8();var n,r,s,o;for(r=Ote(t),s=e,$8(r,0,r.length,s),n=0;n