diff --git a/404.html b/404.html index c78d3b0..79216a7 100644 --- a/404.html +++ b/404.html @@ -5,13 +5,13 @@ Page Not Found | eigr.io - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - + + \ No newline at end of file diff --git a/assets/js/09cf9139.cce595c8.js b/assets/js/09cf9139.0b8e58fb.js similarity index 99% rename from assets/js/09cf9139.cce595c8.js rename to assets/js/09cf9139.0b8e58fb.js index f35269e..65ce1d8 100644 --- a/assets/js/09cf9139.cce595c8.js +++ b/assets/js/09cf9139.0b8e58fb.js @@ -1 +1 @@ -"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[3287],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,r[1]=s;for(var u=2;u {:ok, pid} = GenServer.start_link(Incrementor, [])\niex(2)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 1}}\n\niex(3)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 2}}\n")),(0,i.kt)("h3",{id:"with-spawn-the-same-definition-would-look-like"},"With Spawn, the same definition would look like:"),(0,i.kt)("p",null,"Our process defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},"GenServer"),", we call it an ",(0,i.kt)("em",{parentName:"p"},"Actor"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule IncrementorActor do\n use SpawnSdk.Actor,\n name: "incrementor",\n kind: :named,\n state_type: :json,\n deactivate_timeout: 30_000,\n snapshot_timeout: 10_000\n\n defmodule State do\n @derive {Jason.Encoder, only: [:total]}\n defstruct [total: 0]\n end\n\n defact init(%Context{} = ctx), do: Value.noreply_state!(ctx.state || %State{})\n\n defact add(%{value: value}, %Context{} = ctx) do\n new_total = ctx.state.total + value\n\n Value.of()\n |> Value.state(%State{total: new_total})\n |> Value.response(%{total: new_total})\n end\nend\n')),(0,i.kt)("p",null,"Our application would look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule Example.Application do\n @moduledoc false\n use Application\n\n @impl true\n def start(_type, _args) do\n children = [\n {\n SpawnSdk.System.Supervisor,\n system: "spawn-system",\n actors: [\n IncrementorActor\n ]\n }\n ]\n\n opts = [strategy: :one_for_one, name: Example.Supervisor]\n Supervisor.start_link(children, opts)\n end\nend\n')),(0,i.kt)("p",null,"And the SDK can be installed in your Elixir project with:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'[\n {:spawn_sdk, "~> 1.1"},\n # if using stateful actors\n # {:spawn_statestores_mysql, "~> 1.1"}\n # {:spawn_statestores_postgres, "~> 1.1"}\n # ... others\n]\n')),(0,i.kt)("p",null,"When using a statestore, you need to define a statestore key in ",(0,i.kt)("inlineCode",{parentName:"p"},"config.exs")," or using ",(0,i.kt)("inlineCode",{parentName:"p"},"SPAWN_STATESTORE_KEY")," environment variable to make sure your actor state is properly encrypted."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},"NOTE:")," It is ",(0,i.kt)("strong",{parentName:"p"},"recommended")," to securely store the key in the environment where it is being used.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'config :spawn_statestores, statestore_key: "secure_database_key"\n')),(0,i.kt)("p",null,"Having that defined, the same for ",(0,i.kt)("inlineCode",{parentName:"p"},"Calling")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Casting")," a process in a GenServer, we do it with ",(0,i.kt)("inlineCode",{parentName:"p"},"invoke"),"."),(0,i.kt)("p",null,"Passing any message we want in the payload attribute, it needs to be a struct or map that can be encoded to JSON or a protobuf struct."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'iex(1)> SpawnSdk.invoke("incrementor", system: "spawn-system", action: "add", payload: %{value: 1})\n{:ok, %{total: 1}}\n')),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE")),": We ",(0,i.kt)("strong",{parentName:"p"},"recommend")," to use protobufs as payload and also the state definition, with: ",(0,i.kt)("inlineCode",{parentName:"p"},"state_type: Protos.YourStateType"),", however for this example for the sake of simplicity we are using JSON.")),(0,i.kt)("h2",{id:"unpacking-the-magic-answers-to-your-questions"},"Unpacking the Magic: Answers to Your Questions"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},'What exactly is "spawn-system"?')),(0,i.kt)("p",null,'Spawn operates as a platform that manages infrastructure for you. "spawn-system" is a configuration entity encapsulating multiple actors within a meaningful context.'),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"Why is it an SDK?")),(0,i.kt)("p",null,"Spawn embraces a multi-language approach. SDKs allow different actors, even in different languages, to register with Spawn. For instance, you could have Elixir and NodeJS actors running the same logic seamlessly."),(0,i.kt)("ol",{start:3},(0,i.kt)("li",{parentName:"ol"},"How do I run it?")),(0,i.kt)("p",null,"In development, you can use Spawn as a lib. For production, use Kubernetes CRDs provided by Spawn for easy and scalable deployment."),(0,i.kt)("ol",{start:4},(0,i.kt)("li",{parentName:"ol"},"How do we handle state persistence?")),(0,i.kt)("p",null,"Spawn intelligently handles state persistence through well-defined timeouts and snapshot mechanisms, ensuring reliability even during rollouts."),(0,i.kt)("ol",{start:5},(0,i.kt)("li",{parentName:"ol"},"Why not just use a GenServer?")),(0,i.kt)("p",null,"Managing a distributed system with GenServer requires tackling numerous challenges. Spawn abstracts away these complexities, allowing you to focus on your domain logic without getting lost in infrastructure intricacies."),(0,i.kt)("p",null,"Two items above deserve a little more comment:"),(0,i.kt)("h3",{id:"actor-system"},"Actor System"),(0,i.kt)("p",null,"Spawn is a platform that also handles infrastructure for you, we run on top of kubernetes and have defined some ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"},(0,i.kt)("strong",{parentName:"a"},"Kubernetes CRDs"))," that helps you configure the clustering and lifecycle of your actors."),(0,i.kt)("p",null,"A system is an entity that encapsulates multiple Actors in a context that makes sense for you."),(0,i.kt)("p",null,"We can configure one using the pre-defined Spawn CRDs, and we will also be configuring here which persistent database we are going to use to hold our Actors state."),(0,i.kt)("h3",{id:"sdks"},"SDKs"),(0,i.kt)("p",null,'We can have multiple actors in the same system, with different SDKs registering those actors.\nWe call each deployment that uses an SDK an "ActorHost."'),(0,i.kt)("p",null,"In our example, we could have two SDKs, Elixir and NodeJS, running the same actor or different ones.\nSpawn will then forward any invocations for one of those registered SDKs, with the specified implementation for each action.\nYou can even invoke an actor registered in a different system or in the same system from another SDK."),(0,i.kt)("p",null,"For instance, if we wanted to invoke the same actor we wrote but in a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn-node-sdk"},"NodeJS ActorHost"),", it would look like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import spawn from '@eigr/spawn-sdk'\n\nconst response = await spawn.invoke('incrementor', {\n action: 'add',\n system: 'spawn-system',\n payload: {value: 5}\n})\n\nconsole.log(response)\n// { total: 6 }\n")),(0,i.kt)("p",null,"This way, we can interact with each actor globally, across different Systems and ActorHosts, while still maintaining the same state handling mechanism. And the best part? We can achieve all of this without the need for transactions, locks, or any additional infrastructure to support sequential state write changes of that nature."),(0,i.kt)("h3",{id:"that-sounds-magical-how-do-i-run-it"},"That sounds magical, how do I run it?"),(0,i.kt)("p",null,"In development mode for Elixir, you can take advantage of using Spawn as a lib, you'll be able to use all the features you wan't in a single runtime."),(0,i.kt)("p",null,"However for production we ",(0,i.kt)("strong",{parentName:"p"},"recommend")," using our CRDs set up for you."),(0,i.kt)("p",null,"First of all you need to install our k8s CRD with the following manifest (using kubectl):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create ns eigr-functions && curl -L https://github.com/eigr/spawn/releases/download/v1.1.1/manifest.yaml | kubectl apply -f -\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE:"))," You need to inform the desired release version. Check our github to see the latest one released.")),(0,i.kt)("p",null,"After installing it successfully, you need now to configure your System:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorSystem\nmetadata:\n name: spawn-system # Mandatory. Name of the ActorSystem\n namespace: default # Optional. Default namespace is "default"\nspec:\n statestore:\n type: MySql # Valid are [Postgres, MySql, MariaDB, Sqlite, MSSQL, CockroachDB]\n credentialsSecretRef: mysql-connection-secret # The secret containing connection params created in the previous step.\n pool: # Optional\n size: "10"\n')),(0,i.kt)("p",null,"You can generate the credentialsSecret or use whatever secret you are using to store your database credentials.\nAn example would be, note that the secret needs to be created at the namespace ",(0,i.kt)("inlineCode",{parentName:"p"},"eigr-functions"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create secret generic mysql-connection-secret -n eigr-functions \\\n --from-literal=database=eigr-functions-db \\\n --from-literal=host='mysql' \\\n --from-literal=port='3306' \\\n --from-literal=username='admin' \\\n --from-literal=password='admin' \\\n --from-literal=encryptionKey=$(openssl rand -base64 32)\n")),(0,i.kt)("p",null,"After installing the system, you will need to register your ActorHost, that can look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorHost\nmetadata:\n name: elixir-example\n namespace: default\n annotations:\n spawn-eigr.io/actor-system: spawn-system\nspec:\n host:\n image: org/your-host-image:0.0.1\n embedded: true # this is only for Elixir Sdks, you can ignore this if you will use another language\n ports:\n - name: "http"\n containerPort: 8800\n autoscaler:\n min: 1\n max: 2\n')),(0,i.kt)("p",null,"Just by applying this configuration, and having a container that has the application with the example we wrote in the start of the article, we should see\nthe instances starting that should handle the clustering and all the heavy infrastructure work for you."),(0,i.kt)("h2",{id:"managing-state-resilience-with-spawn"},"Managing State Resilience with Spawn"),(0,i.kt)("p",null,"In the realm of Spawn, we prioritize the resilience of your application's state. Each actor in Spawn comes with configurable parameters, namely the snapshot_timeout and deactivate_timeout. Let's delve into these settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"deactivate_timeout")," determines the duration (in milliseconds) your actor remains actively in memory, even when not in use.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"snapshot_timeout")," how frequently snapshots of your actor's state are saved in your persistent storage."))),(0,i.kt)("p",null,"The magic unfolds after an actor is deactivated, triggered either by the specified timeout or during a Kubernetes rollout. In this scenario, Spawn meticulously manages the lifecycle of each process, ensuring that the state is gracefully saved in the configured persistent storage."),(0,i.kt)("p",null,"Here's the key assurance: even in the face of failures, crashes, or net-splits, Spawn guarantees that the state of your application will always revert to the last valid state. This means if an instance fails, another node seamlessly takes over from where it left off, ensuring the continuity and integrity of your application's data. Our meticulous tuning of Custom Resource Definitions (CRDs) and signal handling ensures that you won't lose data during rollouts or network partitions."),(0,i.kt)("p",null,"With Spawn, you can confidently embrace a resilient state management model, where the reliability and consistency of your application's data are at the forefront of our design philosophy."),(0,i.kt)("h2",{id:"unleashing-gains-in-agility-and-innovation-with-spawn"},"Unleashing Gains in Agility and Innovation with Spawn"),(0,i.kt)("p",null,"Beyond the facade of extensive configurations lies a treasure trove of advantages awaiting exploration. Spawn not only simplifies but significantly enriches your development experience. Imagine bidding farewell to the complexities of defining Kubernetes resources, the intricacies of rollouts, the considerations of HPA, and the worries of scalability, network configurations, and system integrity assessments."),(0,i.kt)("p",null,"Spawn emerges as the driving force behind a newfound sense of agility and innovation. It liberates you from the burdensome aspects of infrastructure management, allowing you to redirect your focus towards what truly matters \u2013 crafting innovative solutions. Step into a future where complexities dissolve, and your journey into agile and innovative Elixir development begins with a resounding hello!"),(0,i.kt)("p",null,"If you choose to go down that path, you will need to face at least the following challenges:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Ensuring proper handling of connections between multiple nodes in your Erlang cluster."),(0,i.kt)("li",{parentName:"ul"},"Ensuring reliable and synchronized data rollouts to avoid message or state loss during instances rolling out."),(0,i.kt)("li",{parentName:"ul"},"Implementing effective persistence mechanisms to recover data in the event of netsplit scenarios, preventing data loss."),(0,i.kt)("li",{parentName:"ul"},"Managing the process lifecycle to ensure predictable recovery and maintain a consistent state in case of errors."),(0,i.kt)("li",{parentName:"ul"},"Designing a well-defined API that integrates your processes seamlessly with other systems, ensuring message synchronization."),(0,i.kt)("li",{parentName:"ul"},"Establishing a reliable distribution mechanism for sending messages to actors within your own edge, with the ability to synchronize them later."),(0,i.kt)("li",{parentName:"ul"},"Mitigating process queue bottlenecks to optimize performance and prevent delays."),(0,i.kt)("li",{parentName:"ul"},"Ensuring atomicity in a distributed system, maintaining data consistency and integrity."),(0,i.kt)("li",{parentName:"ul"},"Ensuring that you can concentrate on your domain-specific code without being burdened by unnecessary complexities and boilerplate."),(0,i.kt)("li",{parentName:"ul"},"Implementing seamless integration patterns, including process pipelines, customized activators, workflows, and effective management of side effects, among others."),(0,i.kt)("li",{parentName:"ul"},"Developing and managing infrastructure code related to brokers, caching, and other components.")),(0,i.kt)("h2",{id:"conclusion"},"Conclusion"),(0,i.kt)("p",null,"This is more than just a practical example; it's an invitation to explore the full potential of Spawn. For a deeper dive into the concepts and foundations, refer to our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn"},"Spawn Full Documentation")," and our insightful article ",(0,i.kt)("a",{parentName:"p",href:"https://eigr.io/blog/beyond-monoliths-and-microservices/"},"Beyond Monoliths and Microservices"),"."),(0,i.kt)("p",null,"Ready to elevate your Elixir development experience? Embrace the future with Spawn. Happy coding! \ud83d\ude80\u2728"))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[3287],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,r[1]=s;for(var u=2;u {:ok, pid} = GenServer.start_link(Incrementor, [])\niex(2)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 1}}\n\niex(3)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 2}}\n")),(0,i.kt)("h3",{id:"with-spawn-the-same-definition-would-look-like"},"With Spawn, the same definition would look like:"),(0,i.kt)("p",null,"Our process defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},"GenServer"),", we call it an ",(0,i.kt)("em",{parentName:"p"},"Actor"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule IncrementorActor do\n use SpawnSdk.Actor,\n name: "incrementor",\n kind: :named,\n state_type: :json,\n deactivate_timeout: 30_000,\n snapshot_timeout: 10_000\n\n defmodule State do\n @derive {Jason.Encoder, only: [:total]}\n defstruct [total: 0]\n end\n\n defact init(%Context{} = ctx), do: Value.noreply_state!(ctx.state || %State{})\n\n defact add(%{value: value}, %Context{} = ctx) do\n new_total = ctx.state.total + value\n\n Value.of()\n |> Value.state(%State{total: new_total})\n |> Value.response(%{total: new_total})\n end\nend\n')),(0,i.kt)("p",null,"Our application would look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule Example.Application do\n @moduledoc false\n use Application\n\n @impl true\n def start(_type, _args) do\n children = [\n {\n SpawnSdk.System.Supervisor,\n system: "spawn-system",\n actors: [\n IncrementorActor\n ]\n }\n ]\n\n opts = [strategy: :one_for_one, name: Example.Supervisor]\n Supervisor.start_link(children, opts)\n end\nend\n')),(0,i.kt)("p",null,"And the SDK can be installed in your Elixir project with:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'[\n {:spawn_sdk, "~> 1.1"},\n # if using stateful actors\n # {:spawn_statestores_mysql, "~> 1.1"}\n # {:spawn_statestores_postgres, "~> 1.1"}\n # ... others\n]\n')),(0,i.kt)("p",null,"When using a statestore, you need to define a statestore key in ",(0,i.kt)("inlineCode",{parentName:"p"},"config.exs")," or using ",(0,i.kt)("inlineCode",{parentName:"p"},"SPAWN_STATESTORE_KEY")," environment variable to make sure your actor state is properly encrypted."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},"NOTE:")," It is ",(0,i.kt)("strong",{parentName:"p"},"recommended")," to securely store the key in the environment where it is being used.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'config :spawn_statestores, statestore_key: "secure_database_key"\n')),(0,i.kt)("p",null,"Having that defined, the same for ",(0,i.kt)("inlineCode",{parentName:"p"},"Calling")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Casting")," a process in a GenServer, we do it with ",(0,i.kt)("inlineCode",{parentName:"p"},"invoke"),"."),(0,i.kt)("p",null,"Passing any message we want in the payload attribute, it needs to be a struct or map that can be encoded to JSON or a protobuf struct."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'iex(1)> SpawnSdk.invoke("incrementor", system: "spawn-system", action: "add", payload: %{value: 1})\n{:ok, %{total: 1}}\n')),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE")),": We ",(0,i.kt)("strong",{parentName:"p"},"recommend")," to use protobufs as payload and also the state definition, with: ",(0,i.kt)("inlineCode",{parentName:"p"},"state_type: Protos.YourStateType"),", however for this example for the sake of simplicity we are using JSON.")),(0,i.kt)("h2",{id:"unpacking-the-magic-answers-to-your-questions"},"Unpacking the Magic: Answers to Your Questions"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},'What exactly is "spawn-system"?')),(0,i.kt)("p",null,'Spawn operates as a platform that manages infrastructure for you. "spawn-system" is a configuration entity encapsulating multiple actors within a meaningful context.'),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"Why is it an SDK?")),(0,i.kt)("p",null,"Spawn embraces a multi-language approach. SDKs allow different actors, even in different languages, to register with Spawn. For instance, you could have Elixir and NodeJS actors running the same logic seamlessly."),(0,i.kt)("ol",{start:3},(0,i.kt)("li",{parentName:"ol"},"How do I run it?")),(0,i.kt)("p",null,"In development, you can use Spawn as a lib. For production, use Kubernetes CRDs provided by Spawn for easy and scalable deployment."),(0,i.kt)("ol",{start:4},(0,i.kt)("li",{parentName:"ol"},"How do we handle state persistence?")),(0,i.kt)("p",null,"Spawn intelligently handles state persistence through well-defined timeouts and snapshot mechanisms, ensuring reliability even during rollouts."),(0,i.kt)("ol",{start:5},(0,i.kt)("li",{parentName:"ol"},"Why not just use a GenServer?")),(0,i.kt)("p",null,"Managing a distributed system with GenServer requires tackling numerous challenges. Spawn abstracts away these complexities, allowing you to focus on your domain logic without getting lost in infrastructure intricacies."),(0,i.kt)("p",null,"Two items above deserve a little more comment:"),(0,i.kt)("h3",{id:"actor-system"},"Actor System"),(0,i.kt)("p",null,"Spawn is a platform that also handles infrastructure for you, we run on top of kubernetes and have defined some ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"},(0,i.kt)("strong",{parentName:"a"},"Kubernetes CRDs"))," that helps you configure the clustering and lifecycle of your actors."),(0,i.kt)("p",null,"A system is an entity that encapsulates multiple Actors in a context that makes sense for you."),(0,i.kt)("p",null,"We can configure one using the pre-defined Spawn CRDs, and we will also be configuring here which persistent database we are going to use to hold our Actors state."),(0,i.kt)("h3",{id:"sdks"},"SDKs"),(0,i.kt)("p",null,'We can have multiple actors in the same system, with different SDKs registering those actors.\nWe call each deployment that uses an SDK an "ActorHost."'),(0,i.kt)("p",null,"In our example, we could have two SDKs, Elixir and NodeJS, running the same actor or different ones.\nSpawn will then forward any invocations for one of those registered SDKs, with the specified implementation for each action.\nYou can even invoke an actor registered in a different system or in the same system from another SDK."),(0,i.kt)("p",null,"For instance, if we wanted to invoke the same actor we wrote but in a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn-node-sdk"},"NodeJS ActorHost"),", it would look like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import spawn from '@eigr/spawn-sdk'\n\nconst response = await spawn.invoke('incrementor', {\n action: 'add',\n system: 'spawn-system',\n payload: {value: 5}\n})\n\nconsole.log(response)\n// { total: 6 }\n")),(0,i.kt)("p",null,"This way, we can interact with each actor globally, across different Systems and ActorHosts, while still maintaining the same state handling mechanism. And the best part? We can achieve all of this without the need for transactions, locks, or any additional infrastructure to support sequential state write changes of that nature."),(0,i.kt)("h3",{id:"that-sounds-magical-how-do-i-run-it"},"That sounds magical, how do I run it?"),(0,i.kt)("p",null,"In development mode for Elixir, you can take advantage of using Spawn as a lib, you'll be able to use all the features you wan't in a single runtime."),(0,i.kt)("p",null,"However for production we ",(0,i.kt)("strong",{parentName:"p"},"recommend")," using our CRDs set up for you."),(0,i.kt)("p",null,"First of all you need to install our k8s CRD with the following manifest (using kubectl):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create ns eigr-functions && curl -L https://github.com/eigr/spawn/releases/download/v1.1.1/manifest.yaml | kubectl apply -f -\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE:"))," You need to inform the desired release version. Check our github to see the latest one released.")),(0,i.kt)("p",null,"After installing it successfully, you need now to configure your System:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorSystem\nmetadata:\n name: spawn-system # Mandatory. Name of the ActorSystem\n namespace: default # Optional. Default namespace is "default"\nspec:\n statestore:\n type: MySql # Valid are [Postgres, MySql, MariaDB, Sqlite, MSSQL, CockroachDB]\n credentialsSecretRef: mysql-connection-secret # The secret containing connection params created in the previous step.\n pool: # Optional\n size: "10"\n')),(0,i.kt)("p",null,"You can generate the credentialsSecret or use whatever secret you are using to store your database credentials.\nAn example would be, note that the secret needs to be created at the namespace ",(0,i.kt)("inlineCode",{parentName:"p"},"eigr-functions"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create secret generic mysql-connection-secret -n eigr-functions \\\n --from-literal=database=eigr-functions-db \\\n --from-literal=host='mysql' \\\n --from-literal=port='3306' \\\n --from-literal=username='admin' \\\n --from-literal=password='admin' \\\n --from-literal=encryptionKey=$(openssl rand -base64 32)\n")),(0,i.kt)("p",null,"After installing the system, you will need to register your ActorHost, that can look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorHost\nmetadata:\n name: elixir-example\n namespace: default\n annotations:\n spawn-eigr.io/actor-system: spawn-system\nspec:\n host:\n image: org/your-host-image:0.0.1\n embedded: true # this is only for Elixir Sdks, you can ignore this if you will use another language\n ports:\n - name: "http"\n containerPort: 8800\n autoscaler:\n min: 1\n max: 2\n')),(0,i.kt)("p",null,"Just by applying this configuration, and having a container that has the application with the example we wrote in the start of the article, we should see\nthe instances starting that should handle the clustering and all the heavy infrastructure work for you."),(0,i.kt)("h2",{id:"managing-state-resilience-with-spawn"},"Managing State Resilience with Spawn"),(0,i.kt)("p",null,"In the realm of Spawn, we prioritize the resilience of your application's state. Each actor in Spawn comes with configurable parameters, namely the snapshot_timeout and deactivate_timeout. Let's delve into these settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"deactivate_timeout")," determines the duration (in milliseconds) your actor remains actively in memory, even when not in use.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"snapshot_timeout")," how frequently snapshots of your actor's state are saved in your persistent storage."))),(0,i.kt)("p",null,"The magic unfolds after an actor is deactivated, triggered either by the specified timeout or during a Kubernetes rollout. In this scenario, Spawn meticulously manages the lifecycle of each process, ensuring that the state is gracefully saved in the configured persistent storage."),(0,i.kt)("p",null,"Here's the key assurance: even in the face of failures, crashes, or net-splits, Spawn guarantees that the state of your application will always revert to the last valid state. This means if an instance fails, another node seamlessly takes over from where it left off, ensuring the continuity and integrity of your application's data. Our meticulous tuning of Custom Resource Definitions (CRDs) and signal handling ensures that you won't lose data during rollouts or network partitions."),(0,i.kt)("p",null,"With Spawn, you can confidently embrace a resilient state management model, where the reliability and consistency of your application's data are at the forefront of our design philosophy."),(0,i.kt)("h2",{id:"unleashing-gains-in-agility-and-innovation-with-spawn"},"Unleashing Gains in Agility and Innovation with Spawn"),(0,i.kt)("p",null,"Beyond the facade of extensive configurations lies a treasure trove of advantages awaiting exploration. Spawn not only simplifies but significantly enriches your development experience. Imagine bidding farewell to the complexities of defining Kubernetes resources, the intricacies of rollouts, the considerations of HPA, and the worries of scalability, network configurations, and system integrity assessments."),(0,i.kt)("p",null,"Spawn emerges as the driving force behind a newfound sense of agility and innovation. It liberates you from the burdensome aspects of infrastructure management, allowing you to redirect your focus towards what truly matters \u2013 crafting innovative solutions. Step into a future where complexities dissolve, and your journey into agile and innovative Elixir development begins with a resounding hello!"),(0,i.kt)("p",null,"If you choose to go down that path, you will need to face at least the following challenges:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Ensuring proper handling of connections between multiple nodes in your Erlang cluster."),(0,i.kt)("li",{parentName:"ul"},"Ensuring reliable and synchronized data rollouts to avoid message or state loss during instances rolling out."),(0,i.kt)("li",{parentName:"ul"},"Implementing effective persistence mechanisms to recover data in the event of netsplit scenarios, preventing data loss."),(0,i.kt)("li",{parentName:"ul"},"Managing the process lifecycle to ensure predictable recovery and maintain a consistent state in case of errors."),(0,i.kt)("li",{parentName:"ul"},"Designing a well-defined API that integrates your processes seamlessly with other systems, ensuring message synchronization."),(0,i.kt)("li",{parentName:"ul"},"Establishing a reliable distribution mechanism for sending messages to actors within your own edge, with the ability to synchronize them later."),(0,i.kt)("li",{parentName:"ul"},"Mitigating process queue bottlenecks to optimize performance and prevent delays."),(0,i.kt)("li",{parentName:"ul"},"Ensuring atomicity in a distributed system, maintaining data consistency and integrity."),(0,i.kt)("li",{parentName:"ul"},"Ensuring that you can concentrate on your domain-specific code without being burdened by unnecessary complexities and boilerplate."),(0,i.kt)("li",{parentName:"ul"},"Implementing seamless integration patterns, including process pipelines, customized activators, workflows, and effective management of side effects, among others."),(0,i.kt)("li",{parentName:"ul"},"Developing and managing infrastructure code related to brokers, caching, and other components.")),(0,i.kt)("h2",{id:"conclusion"},"Conclusion"),(0,i.kt)("p",null,"This is more than just a practical example; it's an invitation to explore the full potential of Spawn. For a deeper dive into the concepts and foundations, refer to our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn"},"Spawn Full Documentation")," and our insightful article ",(0,i.kt)("a",{parentName:"p",href:"https://eigr.io/blog/beyond-monoliths-and-microservices/"},"Beyond Monoliths and Microservices"),"."),(0,i.kt)("p",null,"Ready to elevate your Elixir development experience? Embrace the future with Spawn. Happy coding! \ud83d\ude80\u2728"))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3b36d7b2.b3ae8187.js b/assets/js/3b36d7b2.afc7c2ef.js similarity index 73% rename from assets/js/3b36d7b2.b3ae8187.js rename to assets/js/3b36d7b2.afc7c2ef.js index b5ef008..39170af 100644 --- a/assets/js/3b36d7b2.b3ae8187.js +++ b/assets/js/3b36d7b2.afc7c2ef.js @@ -1 +1 @@ -"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[1138],{3905:function(e,t,n){n.d(t,{Zo:function(){return m},kt:function(){return h}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=p(n),h=a,f=u["".concat(l,".").concat(h)]||u[h]||c[h]||i;return n?r.createElement(f,o(o({ref:t},m),{},{components:n})):r.createElement(f,o({ref:t},m))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),h=a,d=u["".concat(l,".").concat(h)]||u[h]||m[h]||i;return n?r.createElement(d,o(o({ref:t},c),{},{components:n})):r.createElement(d,o({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=p(n),h=a,f=u["".concat(l,".").concat(h)]||u[h]||c[h]||i;return n?r.createElement(f,o(o({ref:t},m),{},{components:n})):r.createElement(f,o({ref:t},m))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),h=a,d=u["".concat(l,".").concat(h)]||u[h]||m[h]||i;return n?r.createElement(d,o(o({ref:t},c),{},{components:n})):r.createElement(d,o({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var p=2;p=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,r[1]=s;for(var u=2;u {:ok, pid} = GenServer.start_link(Incrementor, [])\niex(2)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 1}}\n\niex(3)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 2}}\n")),(0,i.kt)("h3",{id:"with-spawn-the-same-definition-would-look-like"},"With Spawn, the same definition would look like:"),(0,i.kt)("p",null,"Our process defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},"GenServer"),", we call it an ",(0,i.kt)("em",{parentName:"p"},"Actor"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule IncrementorActor do\n use SpawnSdk.Actor,\n name: "incrementor",\n kind: :named,\n state_type: :json,\n deactivate_timeout: 30_000,\n snapshot_timeout: 10_000\n\n defmodule State do\n @derive {Jason.Encoder, only: [:total]}\n defstruct [total: 0]\n end\n\n defact init(%Context{} = ctx), do: Value.noreply_state!(ctx.state || %State{})\n\n defact add(%{value: value}, %Context{} = ctx) do\n new_total = ctx.state.total + value\n\n Value.of()\n |> Value.state(%State{total: new_total})\n |> Value.response(%{total: new_total})\n end\nend\n')),(0,i.kt)("p",null,"Our application would look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule Example.Application do\n @moduledoc false\n use Application\n\n @impl true\n def start(_type, _args) do\n children = [\n {\n SpawnSdk.System.Supervisor,\n system: "spawn-system",\n actors: [\n IncrementorActor\n ]\n }\n ]\n\n opts = [strategy: :one_for_one, name: Example.Supervisor]\n Supervisor.start_link(children, opts)\n end\nend\n')),(0,i.kt)("p",null,"And the SDK can be installed in your Elixir project with:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'[\n {:spawn_sdk, "~> 1.1"},\n # if using stateful actors\n # {:spawn_statestores_mysql, "~> 1.1"}\n # {:spawn_statestores_postgres, "~> 1.1"}\n # ... others\n]\n')),(0,i.kt)("p",null,"When using a statestore, you need to define a statestore key in ",(0,i.kt)("inlineCode",{parentName:"p"},"config.exs")," or using ",(0,i.kt)("inlineCode",{parentName:"p"},"SPAWN_STATESTORE_KEY")," environment variable to make sure your actor state is properly encrypted."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},"NOTE:")," It is ",(0,i.kt)("strong",{parentName:"p"},"recommended")," to securely store the key in the environment where it is being used.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'config :spawn_statestores, statestore_key: "secure_database_key"\n')),(0,i.kt)("p",null,"Having that defined, the same for ",(0,i.kt)("inlineCode",{parentName:"p"},"Calling")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Casting")," a process in a GenServer, we do it with ",(0,i.kt)("inlineCode",{parentName:"p"},"invoke"),"."),(0,i.kt)("p",null,"Passing any message we want in the payload attribute, it needs to be a struct or map that can be encoded to JSON or a protobuf struct."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'iex(1)> SpawnSdk.invoke("incrementor", system: "spawn-system", action: "add", payload: %{value: 1})\n{:ok, %{total: 1}}\n')),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE")),": We ",(0,i.kt)("strong",{parentName:"p"},"recommend")," to use protobufs as payload and also the state definition, with: ",(0,i.kt)("inlineCode",{parentName:"p"},"state_type: Protos.YourStateType"),", however for this example for the sake of simplicity we are using JSON.")),(0,i.kt)("h2",{id:"unpacking-the-magic-answers-to-your-questions"},"Unpacking the Magic: Answers to Your Questions"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},'What exactly is "spawn-system"?')),(0,i.kt)("p",null,'Spawn operates as a platform that manages infrastructure for you. "spawn-system" is a configuration entity encapsulating multiple actors within a meaningful context.'),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"Why is it an SDK?")),(0,i.kt)("p",null,"Spawn embraces a multi-language approach. SDKs allow different actors, even in different languages, to register with Spawn. For instance, you could have Elixir and NodeJS actors running the same logic seamlessly."),(0,i.kt)("ol",{start:3},(0,i.kt)("li",{parentName:"ol"},"How do I run it?")),(0,i.kt)("p",null,"In development, you can use Spawn as a lib. For production, use Kubernetes CRDs provided by Spawn for easy and scalable deployment."),(0,i.kt)("ol",{start:4},(0,i.kt)("li",{parentName:"ol"},"How do we handle state persistence?")),(0,i.kt)("p",null,"Spawn intelligently handles state persistence through well-defined timeouts and snapshot mechanisms, ensuring reliability even during rollouts."),(0,i.kt)("ol",{start:5},(0,i.kt)("li",{parentName:"ol"},"Why not just use a GenServer?")),(0,i.kt)("p",null,"Managing a distributed system with GenServer requires tackling numerous challenges. Spawn abstracts away these complexities, allowing you to focus on your domain logic without getting lost in infrastructure intricacies."),(0,i.kt)("p",null,"Two items above deserve a little more comment:"),(0,i.kt)("h3",{id:"actor-system"},"Actor System"),(0,i.kt)("p",null,"Spawn is a platform that also handles infrastructure for you, we run on top of kubernetes and have defined some ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"},(0,i.kt)("strong",{parentName:"a"},"Kubernetes CRDs"))," that helps you configure the clustering and lifecycle of your actors."),(0,i.kt)("p",null,"A system is an entity that encapsulates multiple Actors in a context that makes sense for you."),(0,i.kt)("p",null,"We can configure one using the pre-defined Spawn CRDs, and we will also be configuring here which persistent database we are going to use to hold our Actors state."),(0,i.kt)("h3",{id:"sdks"},"SDKs"),(0,i.kt)("p",null,'We can have multiple actors in the same system, with different SDKs registering those actors.\nWe call each deployment that uses an SDK an "ActorHost."'),(0,i.kt)("p",null,"In our example, we could have two SDKs, Elixir and NodeJS, running the same actor or different ones.\nSpawn will then forward any invocations for one of those registered SDKs, with the specified implementation for each action.\nYou can even invoke an actor registered in a different system or in the same system from another SDK."),(0,i.kt)("p",null,"For instance, if we wanted to invoke the same actor we wrote but in a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn-node-sdk"},"NodeJS ActorHost"),", it would look like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import spawn from '@eigr/spawn-sdk'\n\nconst response = await spawn.invoke('incrementor', {\n action: 'add',\n system: 'spawn-system',\n payload: {value: 5}\n})\n\nconsole.log(response)\n// { total: 6 }\n")),(0,i.kt)("p",null,"This way, we can interact with each actor globally, across different Systems and ActorHosts, while still maintaining the same state handling mechanism. And the best part? We can achieve all of this without the need for transactions, locks, or any additional infrastructure to support sequential state write changes of that nature."),(0,i.kt)("h3",{id:"that-sounds-magical-how-do-i-run-it"},"That sounds magical, how do I run it?"),(0,i.kt)("p",null,"In development mode for Elixir, you can take advantage of using Spawn as a lib, you'll be able to use all the features you wan't in a single runtime."),(0,i.kt)("p",null,"However for production we ",(0,i.kt)("strong",{parentName:"p"},"recommend")," using our CRDs set up for you."),(0,i.kt)("p",null,"First of all you need to install our k8s CRD with the following manifest (using kubectl):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create ns eigr-functions && curl -L https://github.com/eigr/spawn/releases/download/v1.1.1/manifest.yaml | kubectl apply -f -\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE:"))," You need to inform the desired release version. Check our github to see the latest one released.")),(0,i.kt)("p",null,"After installing it successfully, you need now to configure your System:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorSystem\nmetadata:\n name: spawn-system # Mandatory. Name of the ActorSystem\n namespace: default # Optional. Default namespace is "default"\nspec:\n statestore:\n type: MySql # Valid are [Postgres, MySql, MariaDB, Sqlite, MSSQL, CockroachDB]\n credentialsSecretRef: mysql-connection-secret # The secret containing connection params created in the previous step.\n pool: # Optional\n size: "10"\n')),(0,i.kt)("p",null,"You can generate the credentialsSecret or use whatever secret you are using to store your database credentials.\nAn example would be, note that the secret needs to be created at the namespace ",(0,i.kt)("inlineCode",{parentName:"p"},"eigr-functions"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create secret generic mysql-connection-secret -n eigr-functions \\\n --from-literal=database=eigr-functions-db \\\n --from-literal=host='mysql' \\\n --from-literal=port='3306' \\\n --from-literal=username='admin' \\\n --from-literal=password='admin' \\\n --from-literal=encryptionKey=$(openssl rand -base64 32)\n")),(0,i.kt)("p",null,"After installing the system, you will need to register your ActorHost, that can look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorHost\nmetadata:\n name: elixir-example\n namespace: default\n annotations:\n spawn-eigr.io/actor-system: spawn-system\nspec:\n host:\n image: org/your-host-image:0.0.1\n embedded: true # this is only for Elixir Sdks, you can ignore this if you will use another language\n ports:\n - name: "http"\n containerPort: 8800\n autoscaler:\n min: 1\n max: 2\n')),(0,i.kt)("p",null,"Just by applying this configuration, and having a container that has the application with the example we wrote in the start of the article, we should see\nthe instances starting that should handle the clustering and all the heavy infrastructure work for you."),(0,i.kt)("h2",{id:"managing-state-resilience-with-spawn"},"Managing State Resilience with Spawn"),(0,i.kt)("p",null,"In the realm of Spawn, we prioritize the resilience of your application's state. Each actor in Spawn comes with configurable parameters, namely the snapshot_timeout and deactivate_timeout. Let's delve into these settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"deactivate_timeout")," determines the duration (in milliseconds) your actor remains actively in memory, even when not in use.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"snapshot_timeout")," how frequently snapshots of your actor's state are saved in your persistent storage."))),(0,i.kt)("p",null,"The magic unfolds after an actor is deactivated, triggered either by the specified timeout or during a Kubernetes rollout. In this scenario, Spawn meticulously manages the lifecycle of each process, ensuring that the state is gracefully saved in the configured persistent storage."),(0,i.kt)("p",null,"Here's the key assurance: even in the face of failures, crashes, or net-splits, Spawn guarantees that the state of your application will always revert to the last valid state. This means if an instance fails, another node seamlessly takes over from where it left off, ensuring the continuity and integrity of your application's data. Our meticulous tuning of Custom Resource Definitions (CRDs) and signal handling ensures that you won't lose data during rollouts or network partitions."),(0,i.kt)("p",null,"With Spawn, you can confidently embrace a resilient state management model, where the reliability and consistency of your application's data are at the forefront of our design philosophy."),(0,i.kt)("h2",{id:"unleashing-gains-in-agility-and-innovation-with-spawn"},"Unleashing Gains in Agility and Innovation with Spawn"),(0,i.kt)("p",null,"Beyond the facade of extensive configurations lies a treasure trove of advantages awaiting exploration. Spawn not only simplifies but significantly enriches your development experience. Imagine bidding farewell to the complexities of defining Kubernetes resources, the intricacies of rollouts, the considerations of HPA, and the worries of scalability, network configurations, and system integrity assessments."),(0,i.kt)("p",null,"Spawn emerges as the driving force behind a newfound sense of agility and innovation. It liberates you from the burdensome aspects of infrastructure management, allowing you to redirect your focus towards what truly matters \u2013 crafting innovative solutions. Step into a future where complexities dissolve, and your journey into agile and innovative Elixir development begins with a resounding hello!"),(0,i.kt)("p",null,"If you choose to go down that path, you will need to face at least the following challenges:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Ensuring proper handling of connections between multiple nodes in your Erlang cluster."),(0,i.kt)("li",{parentName:"ul"},"Ensuring reliable and synchronized data rollouts to avoid message or state loss during instances rolling out."),(0,i.kt)("li",{parentName:"ul"},"Implementing effective persistence mechanisms to recover data in the event of netsplit scenarios, preventing data loss."),(0,i.kt)("li",{parentName:"ul"},"Managing the process lifecycle to ensure predictable recovery and maintain a consistent state in case of errors."),(0,i.kt)("li",{parentName:"ul"},"Designing a well-defined API that integrates your processes seamlessly with other systems, ensuring message synchronization."),(0,i.kt)("li",{parentName:"ul"},"Establishing a reliable distribution mechanism for sending messages to actors within your own edge, with the ability to synchronize them later."),(0,i.kt)("li",{parentName:"ul"},"Mitigating process queue bottlenecks to optimize performance and prevent delays."),(0,i.kt)("li",{parentName:"ul"},"Ensuring atomicity in a distributed system, maintaining data consistency and integrity."),(0,i.kt)("li",{parentName:"ul"},"Ensuring that you can concentrate on your domain-specific code without being burdened by unnecessary complexities and boilerplate."),(0,i.kt)("li",{parentName:"ul"},"Implementing seamless integration patterns, including process pipelines, customized activators, workflows, and effective management of side effects, among others."),(0,i.kt)("li",{parentName:"ul"},"Developing and managing infrastructure code related to brokers, caching, and other components.")),(0,i.kt)("h2",{id:"conclusion"},"Conclusion"),(0,i.kt)("p",null,"This is more than just a practical example; it's an invitation to explore the full potential of Spawn. For a deeper dive into the concepts and foundations, refer to our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn"},"Spawn Full Documentation")," and our insightful article ",(0,i.kt)("a",{parentName:"p",href:"https://eigr.io/blog/beyond-monoliths-and-microservices/"},"Beyond Monoliths and Microservices"),"."),(0,i.kt)("p",null,"Ready to elevate your Elixir development experience? Embrace the future with Spawn. Happy coding! \ud83d\ude80\u2728"))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[7290],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||c[m]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:i,r[1]=s;for(var u=2;u {:ok, pid} = GenServer.start_link(Incrementor, [])\niex(2)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 1}}\n\niex(3)> GenServer.call(pid, {:add, 1})\n{:ok, %{total: 2}}\n")),(0,i.kt)("h3",{id:"with-spawn-the-same-definition-would-look-like"},"With Spawn, the same definition would look like:"),(0,i.kt)("p",null,"Our process defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},"GenServer"),", we call it an ",(0,i.kt)("em",{parentName:"p"},"Actor"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule IncrementorActor do\n use SpawnSdk.Actor,\n name: "incrementor",\n kind: :named,\n state_type: :json,\n deactivate_timeout: 30_000,\n snapshot_timeout: 10_000\n\n defmodule State do\n @derive {Jason.Encoder, only: [:total]}\n defstruct [total: 0]\n end\n\n defact init(%Context{} = ctx), do: Value.noreply_state!(ctx.state || %State{})\n\n defact add(%{value: value}, %Context{} = ctx) do\n new_total = ctx.state.total + value\n\n Value.of()\n |> Value.state(%State{total: new_total})\n |> Value.response(%{total: new_total})\n end\nend\n')),(0,i.kt)("p",null,"Our application would look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'defmodule Example.Application do\n @moduledoc false\n use Application\n\n @impl true\n def start(_type, _args) do\n children = [\n {\n SpawnSdk.System.Supervisor,\n system: "spawn-system",\n actors: [\n IncrementorActor\n ]\n }\n ]\n\n opts = [strategy: :one_for_one, name: Example.Supervisor]\n Supervisor.start_link(children, opts)\n end\nend\n')),(0,i.kt)("p",null,"And the SDK can be installed in your Elixir project with:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'[\n {:spawn_sdk, "~> 1.1"},\n # if using stateful actors\n # {:spawn_statestores_mysql, "~> 1.1"}\n # {:spawn_statestores_postgres, "~> 1.1"}\n # ... others\n]\n')),(0,i.kt)("p",null,"When using a statestore, you need to define a statestore key in ",(0,i.kt)("inlineCode",{parentName:"p"},"config.exs")," or using ",(0,i.kt)("inlineCode",{parentName:"p"},"SPAWN_STATESTORE_KEY")," environment variable to make sure your actor state is properly encrypted."),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},"NOTE:")," It is ",(0,i.kt)("strong",{parentName:"p"},"recommended")," to securely store the key in the environment where it is being used.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'config :spawn_statestores, statestore_key: "secure_database_key"\n')),(0,i.kt)("p",null,"Having that defined, the same for ",(0,i.kt)("inlineCode",{parentName:"p"},"Calling")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Casting")," a process in a GenServer, we do it with ",(0,i.kt)("inlineCode",{parentName:"p"},"invoke"),"."),(0,i.kt)("p",null,"Passing any message we want in the payload attribute, it needs to be a struct or map that can be encoded to JSON or a protobuf struct."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elixir"},'iex(1)> SpawnSdk.invoke("incrementor", system: "spawn-system", action: "add", payload: %{value: 1})\n{:ok, %{total: 1}}\n')),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE")),": We ",(0,i.kt)("strong",{parentName:"p"},"recommend")," to use protobufs as payload and also the state definition, with: ",(0,i.kt)("inlineCode",{parentName:"p"},"state_type: Protos.YourStateType"),", however for this example for the sake of simplicity we are using JSON.")),(0,i.kt)("h2",{id:"unpacking-the-magic-answers-to-your-questions"},"Unpacking the Magic: Answers to Your Questions"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},'What exactly is "spawn-system"?')),(0,i.kt)("p",null,'Spawn operates as a platform that manages infrastructure for you. "spawn-system" is a configuration entity encapsulating multiple actors within a meaningful context.'),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},"Why is it an SDK?")),(0,i.kt)("p",null,"Spawn embraces a multi-language approach. SDKs allow different actors, even in different languages, to register with Spawn. For instance, you could have Elixir and NodeJS actors running the same logic seamlessly."),(0,i.kt)("ol",{start:3},(0,i.kt)("li",{parentName:"ol"},"How do I run it?")),(0,i.kt)("p",null,"In development, you can use Spawn as a lib. For production, use Kubernetes CRDs provided by Spawn for easy and scalable deployment."),(0,i.kt)("ol",{start:4},(0,i.kt)("li",{parentName:"ol"},"How do we handle state persistence?")),(0,i.kt)("p",null,"Spawn intelligently handles state persistence through well-defined timeouts and snapshot mechanisms, ensuring reliability even during rollouts."),(0,i.kt)("ol",{start:5},(0,i.kt)("li",{parentName:"ol"},"Why not just use a GenServer?")),(0,i.kt)("p",null,"Managing a distributed system with GenServer requires tackling numerous challenges. Spawn abstracts away these complexities, allowing you to focus on your domain logic without getting lost in infrastructure intricacies."),(0,i.kt)("p",null,"Two items above deserve a little more comment:"),(0,i.kt)("h3",{id:"actor-system"},"Actor System"),(0,i.kt)("p",null,"Spawn is a platform that also handles infrastructure for you, we run on top of kubernetes and have defined some ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"},(0,i.kt)("strong",{parentName:"a"},"Kubernetes CRDs"))," that helps you configure the clustering and lifecycle of your actors."),(0,i.kt)("p",null,"A system is an entity that encapsulates multiple Actors in a context that makes sense for you."),(0,i.kt)("p",null,"We can configure one using the pre-defined Spawn CRDs, and we will also be configuring here which persistent database we are going to use to hold our Actors state."),(0,i.kt)("h3",{id:"sdks"},"SDKs"),(0,i.kt)("p",null,'We can have multiple actors in the same system, with different SDKs registering those actors.\nWe call each deployment that uses an SDK an "ActorHost."'),(0,i.kt)("p",null,"In our example, we could have two SDKs, Elixir and NodeJS, running the same actor or different ones.\nSpawn will then forward any invocations for one of those registered SDKs, with the specified implementation for each action.\nYou can even invoke an actor registered in a different system or in the same system from another SDK."),(0,i.kt)("p",null,"For instance, if we wanted to invoke the same actor we wrote but in a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn-node-sdk"},"NodeJS ActorHost"),", it would look like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import spawn from '@eigr/spawn-sdk'\n\nconst response = await spawn.invoke('incrementor', {\n action: 'add',\n system: 'spawn-system',\n payload: {value: 5}\n})\n\nconsole.log(response)\n// { total: 6 }\n")),(0,i.kt)("p",null,"This way, we can interact with each actor globally, across different Systems and ActorHosts, while still maintaining the same state handling mechanism. And the best part? We can achieve all of this without the need for transactions, locks, or any additional infrastructure to support sequential state write changes of that nature."),(0,i.kt)("h3",{id:"that-sounds-magical-how-do-i-run-it"},"That sounds magical, how do I run it?"),(0,i.kt)("p",null,"In development mode for Elixir, you can take advantage of using Spawn as a lib, you'll be able to use all the features you wan't in a single runtime."),(0,i.kt)("p",null,"However for production we ",(0,i.kt)("strong",{parentName:"p"},"recommend")," using our CRDs set up for you."),(0,i.kt)("p",null,"First of all you need to install our k8s CRD with the following manifest (using kubectl):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create ns eigr-functions && curl -L https://github.com/eigr/spawn/releases/download/v1.1.1/manifest.yaml | kubectl apply -f -\n")),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("em",{parentName:"strong"},"NOTE:"))," You need to inform the desired release version. Check our github to see the latest one released.")),(0,i.kt)("p",null,"After installing it successfully, you need now to configure your System:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorSystem\nmetadata:\n name: spawn-system # Mandatory. Name of the ActorSystem\n namespace: default # Optional. Default namespace is "default"\nspec:\n statestore:\n type: MySql # Valid are [Postgres, MySql, MariaDB, Sqlite, MSSQL, CockroachDB]\n credentialsSecretRef: mysql-connection-secret # The secret containing connection params created in the previous step.\n pool: # Optional\n size: "10"\n')),(0,i.kt)("p",null,"You can generate the credentialsSecret or use whatever secret you are using to store your database credentials.\nAn example would be, note that the secret needs to be created at the namespace ",(0,i.kt)("inlineCode",{parentName:"p"},"eigr-functions"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create secret generic mysql-connection-secret -n eigr-functions \\\n --from-literal=database=eigr-functions-db \\\n --from-literal=host='mysql' \\\n --from-literal=port='3306' \\\n --from-literal=username='admin' \\\n --from-literal=password='admin' \\\n --from-literal=encryptionKey=$(openssl rand -base64 32)\n")),(0,i.kt)("p",null,"After installing the system, you will need to register your ActorHost, that can look like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: spawn-eigr.io/v1\nkind: ActorHost\nmetadata:\n name: elixir-example\n namespace: default\n annotations:\n spawn-eigr.io/actor-system: spawn-system\nspec:\n host:\n image: org/your-host-image:0.0.1\n embedded: true # this is only for Elixir Sdks, you can ignore this if you will use another language\n ports:\n - name: "http"\n containerPort: 8800\n autoscaler:\n min: 1\n max: 2\n')),(0,i.kt)("p",null,"Just by applying this configuration, and having a container that has the application with the example we wrote in the start of the article, we should see\nthe instances starting that should handle the clustering and all the heavy infrastructure work for you."),(0,i.kt)("h2",{id:"managing-state-resilience-with-spawn"},"Managing State Resilience with Spawn"),(0,i.kt)("p",null,"In the realm of Spawn, we prioritize the resilience of your application's state. Each actor in Spawn comes with configurable parameters, namely the snapshot_timeout and deactivate_timeout. Let's delve into these settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"deactivate_timeout")," determines the duration (in milliseconds) your actor remains actively in memory, even when not in use.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"snapshot_timeout")," how frequently snapshots of your actor's state are saved in your persistent storage."))),(0,i.kt)("p",null,"The magic unfolds after an actor is deactivated, triggered either by the specified timeout or during a Kubernetes rollout. In this scenario, Spawn meticulously manages the lifecycle of each process, ensuring that the state is gracefully saved in the configured persistent storage."),(0,i.kt)("p",null,"Here's the key assurance: even in the face of failures, crashes, or net-splits, Spawn guarantees that the state of your application will always revert to the last valid state. This means if an instance fails, another node seamlessly takes over from where it left off, ensuring the continuity and integrity of your application's data. Our meticulous tuning of Custom Resource Definitions (CRDs) and signal handling ensures that you won't lose data during rollouts or network partitions."),(0,i.kt)("p",null,"With Spawn, you can confidently embrace a resilient state management model, where the reliability and consistency of your application's data are at the forefront of our design philosophy."),(0,i.kt)("h2",{id:"unleashing-gains-in-agility-and-innovation-with-spawn"},"Unleashing Gains in Agility and Innovation with Spawn"),(0,i.kt)("p",null,"Beyond the facade of extensive configurations lies a treasure trove of advantages awaiting exploration. Spawn not only simplifies but significantly enriches your development experience. Imagine bidding farewell to the complexities of defining Kubernetes resources, the intricacies of rollouts, the considerations of HPA, and the worries of scalability, network configurations, and system integrity assessments."),(0,i.kt)("p",null,"Spawn emerges as the driving force behind a newfound sense of agility and innovation. It liberates you from the burdensome aspects of infrastructure management, allowing you to redirect your focus towards what truly matters \u2013 crafting innovative solutions. Step into a future where complexities dissolve, and your journey into agile and innovative Elixir development begins with a resounding hello!"),(0,i.kt)("p",null,"If you choose to go down that path, you will need to face at least the following challenges:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Ensuring proper handling of connections between multiple nodes in your Erlang cluster."),(0,i.kt)("li",{parentName:"ul"},"Ensuring reliable and synchronized data rollouts to avoid message or state loss during instances rolling out."),(0,i.kt)("li",{parentName:"ul"},"Implementing effective persistence mechanisms to recover data in the event of netsplit scenarios, preventing data loss."),(0,i.kt)("li",{parentName:"ul"},"Managing the process lifecycle to ensure predictable recovery and maintain a consistent state in case of errors."),(0,i.kt)("li",{parentName:"ul"},"Designing a well-defined API that integrates your processes seamlessly with other systems, ensuring message synchronization."),(0,i.kt)("li",{parentName:"ul"},"Establishing a reliable distribution mechanism for sending messages to actors within your own edge, with the ability to synchronize them later."),(0,i.kt)("li",{parentName:"ul"},"Mitigating process queue bottlenecks to optimize performance and prevent delays."),(0,i.kt)("li",{parentName:"ul"},"Ensuring atomicity in a distributed system, maintaining data consistency and integrity."),(0,i.kt)("li",{parentName:"ul"},"Ensuring that you can concentrate on your domain-specific code without being burdened by unnecessary complexities and boilerplate."),(0,i.kt)("li",{parentName:"ul"},"Implementing seamless integration patterns, including process pipelines, customized activators, workflows, and effective management of side effects, among others."),(0,i.kt)("li",{parentName:"ul"},"Developing and managing infrastructure code related to brokers, caching, and other components.")),(0,i.kt)("h2",{id:"conclusion"},"Conclusion"),(0,i.kt)("p",null,"This is more than just a practical example; it's an invitation to explore the full potential of Spawn. For a deeper dive into the concepts and foundations, refer to our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/eigr/spawn"},"Spawn Full Documentation")," and our insightful article ",(0,i.kt)("a",{parentName:"p",href:"https://eigr.io/blog/beyond-monoliths-and-microservices/"},"Beyond Monoliths and Microservices"),"."),(0,i.kt)("p",null,"Ready to elevate your Elixir development experience? Embrace the future with Spawn. Happy coding! \ud83d\ude80\u2728"))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/814f3328.834a206a.js b/assets/js/814f3328.2489f07f.js similarity index 91% rename from assets/js/814f3328.834a206a.js rename to assets/js/814f3328.2489f07f.js index 9078c44..8f98938 100644 --- a/assets/js/814f3328.834a206a.js +++ b/assets/js/814f3328.2489f07f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[2535],{5641:function(e){e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"Spawn and Flame: A Symphony of Innovation in the Serverless Erlang/BEAM Space","permalink":"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space"},{"title":"Distributed Elixir made easy with Spawn","permalink":"/blog/distributed-elixir-made-easy-with-spawn"},{"title":"Beyond Monoliths and Microservices","permalink":"/blog/beyond-monoliths-and-microservices"},{"title":"Hello Spawn! \u2013 The Actor Mesh","permalink":"/blog/spawn-the-actor-mesh"},{"title":"May 2022 \u2013 Status of the Project","permalink":"/blog/current-status-of-the-project"}]}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[2535],{5641:function(e){e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"Spawn and FLAME: A Symphony of Innovation in the Serverless Erlang/BEAM Space","permalink":"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space"},{"title":"Distributed Elixir made easy with Spawn","permalink":"/blog/distributed-elixir-made-easy-with-spawn"},{"title":"Beyond Monoliths and Microservices","permalink":"/blog/beyond-monoliths-and-microservices"},{"title":"Hello Spawn! \u2013 The Actor Mesh","permalink":"/blog/spawn-the-actor-mesh"},{"title":"May 2022 \u2013 Status of the Project","permalink":"/blog/current-status-of-the-project"}]}')}}]); \ No newline at end of file diff --git a/assets/js/a7023ddc.8e904762.js b/assets/js/a7023ddc.4847b631.js similarity index 93% rename from assets/js/a7023ddc.8e904762.js rename to assets/js/a7023ddc.4847b631.js index 4037a37..f857eaf 100644 --- a/assets/js/a7023ddc.8e904762.js +++ b/assets/js/a7023ddc.4847b631.js @@ -1 +1 @@ -"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[1713],{3457:function(l){l.exports=JSON.parse('[{"label":"spawn","permalink":"/blog/tags/spawn","count":3},{"label":"flame","permalink":"/blog/tags/flame","count":1},{"label":"serverless","permalink":"/blog/tags/serverless","count":7},{"label":"elixir","permalink":"/blog/tags/elixir","count":2},{"label":"distributed","permalink":"/blog/tags/distributed","count":1},{"label":"durable computing","permalink":"/blog/tags/durable-computing","count":1},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions","count":3},{"label":"design","permalink":"/blog/tags/design","count":1},{"label":"architect","permalink":"/blog/tags/architect","count":1},{"label":"cloudstate","permalink":"/blog/tags/cloudstate","count":2},{"label":"project","permalink":"/blog/tags/project","count":2},{"label":"status","permalink":"/blog/tags/status","count":2},{"label":"eigr","permalink":"/blog/tags/eigr","count":2}]')}}]); \ No newline at end of file +"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[1713],{3457:function(l){l.exports=JSON.parse('[{"label":"spawn","permalink":"/blog/tags/spawn","count":3},{"label":"FLAME","permalink":"/blog/tags/flame","count":1},{"label":"serverless","permalink":"/blog/tags/serverless","count":7},{"label":"elixir","permalink":"/blog/tags/elixir","count":2},{"label":"distributed","permalink":"/blog/tags/distributed","count":1},{"label":"durable computing","permalink":"/blog/tags/durable-computing","count":1},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions","count":3},{"label":"design","permalink":"/blog/tags/design","count":1},{"label":"architect","permalink":"/blog/tags/architect","count":1},{"label":"cloudstate","permalink":"/blog/tags/cloudstate","count":2},{"label":"project","permalink":"/blog/tags/project","count":2},{"label":"status","permalink":"/blog/tags/status","count":2},{"label":"eigr","permalink":"/blog/tags/eigr","count":2}]')}}]); \ No newline at end of file diff --git a/assets/js/b2f554cd.a58e8716.js b/assets/js/b2f554cd.5d47a3e1.js similarity index 97% rename from assets/js/b2f554cd.a58e8716.js rename to assets/js/b2f554cd.5d47a3e1.js index 9177ac8..d76fdd3 100644 --- a/assets/js/b2f554cd.a58e8716.js +++ b/assets/js/b2f554cd.5d47a3e1.js @@ -1 +1 @@ -"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[1477],{10:function(e){e.exports=JSON.parse('{"blogPosts":[{"id":"spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space","metadata":{"permalink":"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2023-12-27-spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-erlang-beam-space.md","source":"@site/blog/2023-12-27-spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-erlang-beam-space.md","title":"Spawn and Flame: A Symphony of Innovation in the Serverless Erlang/BEAM Space","description":"In recent times, the eigr community had the privilege of exploring a new addition to the Erlang/BEAM landscape, inspired by the Serverless model: Flame. The excitement surrounding this release was tangible, especially given Flame\'s connection to the renowned Phoenix framework. While Spawn, our software in the same Serverless sphere, might appear as a direct competitor, we believe there is more synergy than competition between them.","date":"2023-12-27T00:00:00.000Z","formattedDate":"December 27, 2023","tags":[{"label":"spawn","permalink":"/blog/tags/spawn"},{"label":"flame","permalink":"/blog/tags/flame"},{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"elixir","permalink":"/blog/tags/elixir"}],"readingTime":2.095,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"}],"frontMatter":{"slug":"spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space","title":"Spawn and Flame: A Symphony of Innovation in the Serverless Erlang/BEAM Space","authors":["sleipnir"],"tags":["spawn","flame","serverless","elixir"],"draft":false},"nextItem":{"title":"Distributed Elixir made easy with Spawn","permalink":"/blog/distributed-elixir-made-easy-with-spawn"}},"content":"In recent times, the eigr community had the privilege of exploring a new addition to the Erlang/BEAM landscape, inspired by the Serverless model: [Flame](https://github.com/phoenixframework/flame). The excitement surrounding this release was tangible, especially given Flame\'s connection to the renowned Phoenix framework. While [Spawn](https://github.com/eigr/spawn), our software in the same Serverless sphere, might appear as a direct competitor, we believe there is more synergy than competition between them.\\n\\nIt may seem peculiar that we express satisfaction with Flame, considering that Spawn also operates in the Serverless space. However, after more than four years of dedicated work and pioneering discussions on topics like Stateful Serverless and durable computing, we recognize that attention is now turning to concepts we championed from the outset. Additionally, Flame is built on the Erlang virtual machine, making it a distant relative and, in a sense, an ally in our journey.\\n\\nWe are genuinely excited about Flame, actively contributing to its ecosystem and [collaboratively engaging with its community of developers](https://github.com/phoenixframework/flame/issues/9) and users. Leveraging our expertise in Kubernetes, we are even developing a [backend](https://github.com/eigr-labs/flame-k8s) for Flame in this area, inviting everyone to join us in this joint endeavor.\\n\\n## Spawn vs. Flame: Exploring Differences and Complementarities\\n\\nDespite some superficial similarities, Spawn and Flame are fundamentally distinct, both inspired by the Serverless model but with complementary approaches. While Flame follows the Function as a Service (FaaS) paradigm, literally sending functions over the wire and adopting a stateless premise, Spawn is more oriented toward applications that require state management.\\n\\nIn Spawn, we not only embrace the Serverless model but also introduce a new layer based on actors, business contracts and a [totally polyglot model of programming](https://github.com/eigr/spawn/blob/main/docs/sdks.md). This approach offers a fresh perspective on software design, encouraging developers to think in terms of business rather than the algorithms needed to ensure the infrastructure functions concerning state or external services. While Flame moves functions across the network, in Spawn, we shift data to computation, fundamentally altering how applications are built and maintained.\\n\\nIn summary, although they may seem like competitors at first glance, Spawn and Flame coexist harmoniously, addressing different needs and providing valuable approaches in the vast universe of Serverless computing in the Erlang/BEAM space. Our goal is not only to highlight the differences but also to promote collaboration between both communities, collectively building a more innovative and robust future for Serverless software development.\\n\\nIn future posts we will discuss more about how Spawn and Flame can be applied in a complementary way. \\nThese are exciting times for serverless computing. Happy coding! \ud83d\ude80\u2728"},{"id":"distributed-elixir-made-easy-with-spawn","metadata":{"permalink":"/blog/distributed-elixir-made-easy-with-spawn","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2023-12-03-distributed-elixir-made-easy.md","source":"@site/blog/2023-12-03-distributed-elixir-made-easy.md","title":"Distributed Elixir made easy with Spawn","description":"Hello Elixir enthusiasts! \ud83d\ude80 As the tech landscape evolves, so should our tools and approaches to development. Today, I\'m excited to introduce you to a significant advancement in Elixir development that can reshape how we build distributed systems \u2013 I present to you Spawn.","date":"2023-12-03T00:00:00.000Z","formattedDate":"December 3, 2023","tags":[{"label":"spawn","permalink":"/blog/tags/spawn"},{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"elixir","permalink":"/blog/tags/elixir"},{"label":"distributed","permalink":"/blog/tags/distributed"},{"label":"durable computing","permalink":"/blog/tags/durable-computing"}],"readingTime":9.695,"hasTruncateMarker":false,"authors":[{"name":"Elias Dal Ben Arruda","title":"eigr.io \u2013 Core Team","url":"https://github.com/eliasdarruda","imageURL":"https://avatars.githubusercontent.com/u/19327513?v=4","key":"eliasdarruda"},{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"}],"frontMatter":{"slug":"distributed-elixir-made-easy-with-spawn","title":"Distributed Elixir made easy with Spawn","authors":["eliasdarruda","sleipnir"],"tags":["spawn","serverless","elixir","distributed","durable computing"],"draft":false},"prevItem":{"title":"Spawn and Flame: A Symphony of Innovation in the Serverless Erlang/BEAM Space","permalink":"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space"},"nextItem":{"title":"Beyond Monoliths and Microservices","permalink":"/blog/beyond-monoliths-and-microservices"}},"content":"Hello Elixir enthusiasts! \ud83d\ude80 As the tech landscape evolves, so should our tools and approaches to development. Today, I\'m excited to introduce you to a significant advancement in Elixir development that can reshape how we build distributed systems \u2013 I present to you Spawn.\\n\\n## The Elixir Actors Dilemma\\n\\nWe\'ve all been there \u2013 struck by that stroke of genius while working with Elixir. The allure of in-memory state storage, backed by the reliability of Erlang/OTP, seems like a dream come true. But reality hits hard, especially in the realm of production environments where Kubernetes often plays a pivotal role. Managing multiple servers autonomously, especially in distributed systems, can quickly turn our dream into a complex nightmare.\\n\\n## Enter Spawn: A New Approach to Actors\\n\\n[**Spawn**](https://github.com/eigr/spawn) is not just another framework; it\'s a paradigm shift in how we implement code. Imagine a world where you can care less about the underlying infrastructure and instead focus on crafting the domain-specific logic that truly matters. That\'s precisely what Spawn brings to the table.\\n\\nLet\'s delve into a quick comparison between a traditional GenServer approach and the innovative Spawn Actor using the [**_Spawn Elixir SDK_**](https://github.com/eigr/spawn/tree/main/spawn_sdk/spawn_sdk).\\n\\n### Consider a GenServer that does the following:\\n\\n```elixir\\ndefmodule Incrementor do\\n use GenServer\\n\\n defmodule State do\\n defstruct [total: 0]\\n end\\n\\n def init(_), do: {:ok, %State{total: 0}}\\n\\n def handle_call({:add, value}, _from, state) do\\n new_total = state.total + value\\n\\n {:reply, {:ok, %{total: new_total}}, %State{state | total: new_total}}\\n end\\nend\\n```\\n\\nIf we execute it, as you probably now already, we can add a specified value to the total stored in memory, and calling add will always return the total amount stored in memory.\\n\\n```elixir\\niex(1)> {:ok, pid} = GenServer.start_link(Incrementor, [])\\niex(2)> GenServer.call(pid, {:add, 1})\\n{:ok, %{total: 1}}\\n\\niex(3)> GenServer.call(pid, {:add, 1})\\n{:ok, %{total: 2}}\\n```\\n\\n### With Spawn, the same definition would look like:\\n\\nOur process defined by the `GenServer`, we call it an _Actor_.\\n\\n```elixir\\ndefmodule IncrementorActor do\\n use SpawnSdk.Actor,\\n name: \\"incrementor\\",\\n kind: :named,\\n state_type: :json,\\n deactivate_timeout: 30_000,\\n snapshot_timeout: 10_000\\n\\n defmodule State do\\n @derive {Jason.Encoder, only: [:total]}\\n defstruct [total: 0]\\n end\\n\\n defact init(%Context{} = ctx), do: Value.noreply_state!(ctx.state || %State{})\\n\\n defact add(%{value: value}, %Context{} = ctx) do\\n new_total = ctx.state.total + value\\n\\n Value.of()\\n |> Value.state(%State{total: new_total})\\n |> Value.response(%{total: new_total})\\n end\\nend\\n```\\n\\nOur application would look like:\\n\\n```elixir\\ndefmodule Example.Application do\\n @moduledoc false\\n use Application\\n\\n @impl true\\n def start(_type, _args) do\\n children = [\\n {\\n SpawnSdk.System.Supervisor,\\n system: \\"spawn-system\\",\\n actors: [\\n IncrementorActor\\n ]\\n }\\n ]\\n\\n opts = [strategy: :one_for_one, name: Example.Supervisor]\\n Supervisor.start_link(children, opts)\\n end\\nend\\n```\\n\\nAnd the SDK can be installed in your Elixir project with:\\n\\n```elixir\\n[\\n {:spawn_sdk, \\"~> 1.1\\"},\\n # if using stateful actors\\n # {:spawn_statestores_mysql, \\"~> 1.1\\"}\\n # {:spawn_statestores_postgres, \\"~> 1.1\\"}\\n # ... others\\n]\\n```\\n\\nWhen using a statestore, you need to define a statestore key in `config.exs` or using `SPAWN_STATESTORE_KEY` environment variable to make sure your actor state is properly encrypted.\\n\\n> **NOTE:** It is **recommended** to securely store the key in the environment where it is being used.\\n\\n```elixir\\nconfig :spawn_statestores, statestore_key: \\"secure_database_key\\"\\n```\\n\\nHaving that defined, the same for `Calling` or `Casting` a process in a GenServer, we do it with `invoke`.\\n\\nPassing any message we want in the payload attribute, it needs to be a struct or map that can be encoded to JSON or a protobuf struct.\\n\\n```elixir\\niex(1)> SpawnSdk.invoke(\\"incrementor\\", system: \\"spawn-system\\", action: \\"add\\", payload: %{value: 1})\\n{:ok, %{total: 1}}\\n```\\n\\n> **_NOTE_**: We **recommend** to use protobufs as payload and also the state definition, with: `state_type: Protos.YourStateType`, however for this example for the sake of simplicity we are using JSON.\\n\\n## Unpacking the Magic: Answers to Your Questions\\n\\n1. What exactly is \\"spawn-system\\"?\\n\\nSpawn operates as a platform that manages infrastructure for you. \\"spawn-system\\" is a configuration entity encapsulating multiple actors within a meaningful context.\\n\\n2. Why is it an SDK?\\n\\nSpawn embraces a multi-language approach. SDKs allow different actors, even in different languages, to register with Spawn. For instance, you could have Elixir and NodeJS actors running the same logic seamlessly.\\n\\n3. How do I run it?\\n\\nIn development, you can use Spawn as a lib. For production, use Kubernetes CRDs provided by Spawn for easy and scalable deployment.\\n\\n4. How do we handle state persistence?\\n\\nSpawn intelligently handles state persistence through well-defined timeouts and snapshot mechanisms, ensuring reliability even during rollouts.\\n\\n5. Why not just use a GenServer?\\n\\nManaging a distributed system with GenServer requires tackling numerous challenges. Spawn abstracts away these complexities, allowing you to focus on your domain logic without getting lost in infrastructure intricacies.\\n\\nTwo items above deserve a little more comment:\\n\\n### Actor System\\n\\nSpawn is a platform that also handles infrastructure for you, we run on top of kubernetes and have defined some [**Kubernetes CRDs**](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) that helps you configure the clustering and lifecycle of your actors.\\n\\nA system is an entity that encapsulates multiple Actors in a context that makes sense for you.\\n\\nWe can configure one using the pre-defined Spawn CRDs, and we will also be configuring here which persistent database we are going to use to hold our Actors state.\\n\\n### SDKs\\n\\nWe can have multiple actors in the same system, with different SDKs registering those actors.\\nWe call each deployment that uses an SDK an \\"ActorHost.\\"\\n\\nIn our example, we could have two SDKs, Elixir and NodeJS, running the same actor or different ones.\\nSpawn will then forward any invocations for one of those registered SDKs, with the specified implementation for each action.\\nYou can even invoke an actor registered in a different system or in the same system from another SDK.\\n\\nFor instance, if we wanted to invoke the same actor we wrote but in a [NodeJS ActorHost](https://github.com/eigr/spawn-node-sdk), it would look like this:\\n\\n```ts\\nimport spawn from \'@eigr/spawn-sdk\'\\n\\nconst response = await spawn.invoke(\'incrementor\', {\\n action: \'add\',\\n system: \'spawn-system\',\\n payload: {value: 5}\\n})\\n\\nconsole.log(response)\\n// { total: 6 }\\n```\\n\\nThis way, we can interact with each actor globally, across different Systems and ActorHosts, while still maintaining the same state handling mechanism. And the best part? We can achieve all of this without the need for transactions, locks, or any additional infrastructure to support sequential state write changes of that nature.\\n\\n### That sounds magical, how do I run it?\\n\\nIn development mode for Elixir, you can take advantage of using Spawn as a lib, you\'ll be able to use all the features you wan\'t in a single runtime.\\n\\nHowever for production we **recommend** using our CRDs set up for you.\\n\\nFirst of all you need to install our k8s CRD with the following manifest (using kubectl):\\n\\n```bash\\nkubectl create ns eigr-functions && curl -L https://github.com/eigr/spawn/releases/download/v1.1.1/manifest.yaml | kubectl apply -f -\\n```\\n\\n> **_NOTE:_** You need to inform the desired release version. Check our github to see the latest one released.\\n\\nAfter installing it successfully, you need now to configure your System:\\n\\n```yaml\\napiVersion: spawn-eigr.io/v1\\nkind: ActorSystem\\nmetadata:\\n name: spawn-system # Mandatory. Name of the ActorSystem\\n namespace: default # Optional. Default namespace is \\"default\\"\\nspec:\\n statestore:\\n type: MySql # Valid are [Postgres, MySql, MariaDB, Sqlite, MSSQL, CockroachDB]\\n credentialsSecretRef: mysql-connection-secret # The secret containing connection params created in the previous step.\\n pool: # Optional\\n size: \\"10\\"\\n```\\n\\nYou can generate the credentialsSecret or use whatever secret you are using to store your database credentials.\\nAn example would be, note that the secret needs to be created at the namespace `eigr-functions`.\\n\\n```bash\\nkubectl create secret generic mysql-connection-secret -n eigr-functions \\\\\\n --from-literal=database=eigr-functions-db \\\\\\n --from-literal=host=\'mysql\' \\\\\\n --from-literal=port=\'3306\' \\\\\\n --from-literal=username=\'admin\' \\\\\\n --from-literal=password=\'admin\' \\\\\\n --from-literal=encryptionKey=$(openssl rand -base64 32)\\n```\\n\\nAfter installing the system, you will need to register your ActorHost, that can look like:\\n\\n```yaml\\napiVersion: spawn-eigr.io/v1\\nkind: ActorHost\\nmetadata:\\n name: elixir-example\\n namespace: default\\n annotations:\\n spawn-eigr.io/actor-system: spawn-system\\nspec:\\n host:\\n image: org/your-host-image:0.0.1\\n embedded: true # this is only for Elixir Sdks, you can ignore this if you will use another language\\n ports:\\n - name: \\"http\\"\\n containerPort: 8800\\n autoscaler:\\n min: 1\\n max: 2\\n```\\n\\nJust by applying this configuration, and having a container that has the application with the example we wrote in the start of the article, we should see\\nthe instances starting that should handle the clustering and all the heavy infrastructure work for you.\\n\\n## Managing State Resilience with Spawn\\n\\nIn the realm of Spawn, we prioritize the resilience of your application\'s state. Each actor in Spawn comes with configurable parameters, namely the snapshot_timeout and deactivate_timeout. Let\'s delve into these settings:\\n\\n- **deactivate_timeout** determines the duration (in milliseconds) your actor remains actively in memory, even when not in use.\\n\\n- **snapshot_timeout** how frequently snapshots of your actor\'s state are saved in your persistent storage.\\n\\nThe magic unfolds after an actor is deactivated, triggered either by the specified timeout or during a Kubernetes rollout. In this scenario, Spawn meticulously manages the lifecycle of each process, ensuring that the state is gracefully saved in the configured persistent storage.\\n\\nHere\'s the key assurance: even in the face of failures, crashes, or net-splits, Spawn guarantees that the state of your application will always revert to the last valid state. This means if an instance fails, another node seamlessly takes over from where it left off, ensuring the continuity and integrity of your application\'s data. Our meticulous tuning of Custom Resource Definitions (CRDs) and signal handling ensures that you won\'t lose data during rollouts or network partitions.\\n\\nWith Spawn, you can confidently embrace a resilient state management model, where the reliability and consistency of your application\'s data are at the forefront of our design philosophy.\\n\\n## Unleashing Gains in Agility and Innovation with Spawn\\n\\nBeyond the facade of extensive configurations lies a treasure trove of advantages awaiting exploration. Spawn not only simplifies but significantly enriches your development experience. Imagine bidding farewell to the complexities of defining Kubernetes resources, the intricacies of rollouts, the considerations of HPA, and the worries of scalability, network configurations, and system integrity assessments.\\n\\nSpawn emerges as the driving force behind a newfound sense of agility and innovation. It liberates you from the burdensome aspects of infrastructure management, allowing you to redirect your focus towards what truly matters \u2013 crafting innovative solutions. Step into a future where complexities dissolve, and your journey into agile and innovative Elixir development begins with a resounding hello!\\n\\nIf you choose to go down that path, you will need to face at least the following challenges:\\n\\n- Ensuring proper handling of connections between multiple nodes in your Erlang cluster.\\n- Ensuring reliable and synchronized data rollouts to avoid message or state loss during instances rolling out.\\n- Implementing effective persistence mechanisms to recover data in the event of netsplit scenarios, preventing data loss.\\n- Managing the process lifecycle to ensure predictable recovery and maintain a consistent state in case of errors.\\n- Designing a well-defined API that integrates your processes seamlessly with other systems, ensuring message synchronization.\\n- Establishing a reliable distribution mechanism for sending messages to actors within your own edge, with the ability to synchronize them later.\\n- Mitigating process queue bottlenecks to optimize performance and prevent delays.\\n- Ensuring atomicity in a distributed system, maintaining data consistency and integrity.\\n- Ensuring that you can concentrate on your domain-specific code without being burdened by unnecessary complexities and boilerplate.\\n- Implementing seamless integration patterns, including process pipelines, customized activators, workflows, and effective management of side effects, among others.\\n- Developing and managing infrastructure code related to brokers, caching, and other components.\\n\\n## Conclusion\\n\\nThis is more than just a practical example; it\'s an invitation to explore the full potential of Spawn. For a deeper dive into the concepts and foundations, refer to our [Spawn Full Documentation](https://github.com/eigr/spawn) and our insightful article [Beyond Monoliths and Microservices](https://eigr.io/blog/beyond-monoliths-and-microservices/).\\n\\nReady to elevate your Elixir development experience? Embrace the future with Spawn. Happy coding! \ud83d\ude80\u2728"},{"id":"beyond-monoliths-and-microservices","metadata":{"permalink":"/blog/beyond-monoliths-and-microservices","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2023-05-10-beyond-monoliths-and-microservices.md","source":"@site/blog/2023-05-10-beyond-monoliths-and-microservices.md","title":"Beyond Monoliths and Microservices","description":"Recently a article","date":"2023-05-10T00:00:00.000Z","formattedDate":"May 10, 2023","tags":[{"label":"spawn","permalink":"/blog/tags/spawn"},{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions"},{"label":"design","permalink":"/blog/tags/design"},{"label":"architect","permalink":"/blog/tags/architect"}],"readingTime":8.4,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"},{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"beyond-monoliths-and-microservices","title":"Beyond Monoliths and Microservices","authors":["sleipnir","marcellanz"],"tags":["spawn","serverless","eigr-functions","design","architect"],"draft":false},"prevItem":{"title":"Distributed Elixir made easy with Spawn","permalink":"/blog/distributed-elixir-made-easy-with-spawn"},"nextItem":{"title":"Hello Spawn! \u2013 The Actor Mesh","permalink":"/blog/spawn-the-actor-mesh"}},"content":"Recently a [article](https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90)\\nlaunched by the Amazon Prime team reactivated the Monoliths versus Microservices discussion. It is remarkable, and often reproachable, \\nhow many fervent feelings there are around this already old discussion.\\nI\'ve always wondered what the point really was between these two conflicting worldviews. And I could never understand why\\nso much energy is expended on this type of discussion.\\n\\nIn this article we intend to introduce you to why it\'s time to move forward and how our Spawn technology can help developers \\nlet go of these age-old issues, and that do not add much value to the business.\\n\\n## Monoliths\\n\\n![Monoliths](/img/monoliths.jpg \\"Monoliths\\")\\n\\nMonolithic architecture is given by a single, undivided system that runs in a single process, a software application in which different components are linked to a single program within a single platform.\\nAs the entire system is in a single block, its initial development can be more agile, making it possible to develop an application in less time and with less initial complexity, notice the initial word.\\n\\nAs a monolithic application evolves, several classes, modules, methods or functions are added to this same code and process.\\nAnother point is that monolithic applications tend not to scale horizontally well, since all the general functionality of a system is tied to a single process it is expected that this type of application scales better vertically than horizontally. This particular characteristic also makes it difficult to implement this type of system in environments such as Kubernetes or other types of Cloud environments, notice that I said difficult and not unfeasible.\\n\\nAnd this is where the problems with this type of architecture usually start to appear. In other words, the issue with monoliths seems to be directly related to the scale of the system in question. The more complexity you add, the harder it gets to maintain, which requires more complexity to mitigate the problem, which makes it harder to maintain.... well, you get the point.\\nTo get around these effects, there are many software engineering patterns that help to mitigate such failures (facades, ports, adapters, interface programming and so on), all this additional complexity turns out to be a good price to pay for its defenders, to a certain extent.\\n\\n## Microservices\\n\\n![Microservices](/img/microservices.jpg \\"Microservices\\")\\n\\nWhat differentiates the microservices architecture from more traditional monolithic approaches is how it decomposes the application into smaller units. Each unit in turn is called a service and can be created and deployed independently. In other words, each individual service can work or fail without compromising the others. This helps you embrace the technology side of DevOps and make constant iteration and constant delivery (CI/CD) more streamlined and feasible (at least in theory).\\nIn terms of scaling microservices tend to scale better horizontally than vertically and this in turn is better for infrastructures powered by Kubernetes, Serververless, or even other types of Cloud environments.\\n\\nBut not everything is flowers with microservices. Microservices, generally, increase the complexity in managing failures and in the control of expenses with infrastructure. Developers had to become experts in distributed and large-scale systems.\\nTo deal with it all, over the years several techniques have emerged to avoid various problems of distributed systems, as well as the advent of Observability and FinOps techniques that helped to control infrastructure costs, allowed the architecture of microservices to become extremely popular.\\n\\n## Spawn and Beyond\\n\\nI could write dozens of pros and cons of each of these architectures and, at least for us, I would never come up with an outright winner. The undeniable fact is that both have great strengths and equally great flaws. We are without a winner and therefore we need to let go and go further.\\n\\nIn simple terms, what we here in the Eigr community believe is that developers, in general, need a platform that is, among other things, be simpler, dynamic, vendor lock free, focused on the business domain and not on precious technicalities, and that adapts well to the granularity your business requirements demand.\\n\\nNow let\'s introduce our Spawn technology and try to explore a little bit of how it can help us go further.\\n\\n[Spawn](https://github.com/eigr/spawn) is primarily based on three very powerful abstractions, the [Sidecar Pattern](https://thenewstack.io/operators-and-sidecars-are-the-new-model-for-software-delivery/), the [Actor Model](https://www.brianstorti.com/the-actor-model/) and the [Serverless](https://www2.eecs.berkeley.edu/Pubs/TechRpts/2019/EECS-2019-3.pdf). The former allows you to deploy an application\'s components in a separate process or container providing isolation and encapsulation. This pattern enables applications to be composed of heterogeneous technologies and components, while allowing this separate process to handle the infrastructure layers without affecting the evolution of your business code. In turn, the second is a fascinating and relatively simple alternative for the development of distributed and concurrent systems. This model allows you to decompose your system into small units, called actors, that communicate only by passing messages. Actors encapsulate state and behavior in a single unit, and are lock-free, that is, when programming with actors you are free of semaphore, mutex and any type of synchronizing code. And finally Serverless lets developers focus on their code without worrying about the infrastructure. Using Kubernetes as an orchestrator for our serverless workloads we can provide a self managed platform without forcing the developer to be tied to any existing public cloud offerings. Free from blockages! \\n\\nHowever, it goes beyond the basics of the Actor Model by exposing several software patterns in a simplified way for the developer. Spawn is also domain oriented to your business, allowing you to focus directly on the business problem, while the Spawn runtime handles things like state management and persistence, caching, inter-process calls, scalability, cluster management, scaling up and down, integration with external middleware, among many other non-functional requirements that software usually needs to achieve its final goals. \\n\\nSpawn is also a polyglot platform, allowing you to write Actors in different languages and allowing them to communicate with each other in a totally transparent way without the need to define REST or RPC interfaces between your components. Being based on the powerful [Erlang technology](https://www.wired.com/2015/09/whatsapp-serves-900-million-users-50-engineers) you get the best of what the, [battle tested](https://elixir-lang.org/blog/2020/10/08/real-time-communication-at-scale-with-elixir-at-discord/), [Erlang Virtual Machine is capable of providing](https://serokell.io/blog/introduction-to-erlang) without giving up your natural domain language, be it [Java, Typescript, Elixir](https://github.com/eigr/spawn#sdks), or another.\\n\\nNow that we have a basic idea about Spawn we can move on to how it can help us move beyond the discussion of Monoliths and Microservices.\\n\\n## Services, Applications, and Granularity\\n\\nTo understand how Spawn can help us move the discussion forward, we first need to understand how Spawn organizes its deployable components.\\nThe most basic unit of Spawn is the Actor, it is through Actors that developers can express their domain problems and as we said before the Actor is responsible for encapsulating the state and its associated behavior in itself.\\n\\n![Actors](/img/actors.jpg \\"Actors\\") \\n\\nThat said, a Spawn application in a simplified way is nothing more than a series of Actors organized in an deployment unit that we can call service or application, but which in our terminology we call ActorHost. An ActorHost is the deployable unit which is made up of the host container (where the developer works) plus the proxy container which is where the actors actually perform their tasks.\\n\\n![ActorHost](/img/actor-host.jpg \\"Actor Host\\")\\n\\nYou can have hundreds or even thousands of actors running on a single ActorHost and that in turn can have multiple replicas running on a cluster. As Spawn Actors are activated only when there is work to be done and are deactivated after a period of inactivity, the workloads are distributed among different replicas of the same ActorHost. From the developer\'s point of view, it doesn\'t matter because the only thing he needs to be able to send a message to an actor is his name. No complicated APIs with additional worries like service discovery, circuit breakers or anything else.\\n\\n![Replicas](/img/actor-host-replicas.jpg \\"Actor Host Distribution\\")\\n\\nAnd finally your ActorHost are grouped within a more general system that we call ActorSystem. All ActorHost applications within the same actor system actively communicate with each other forming a real cluster of nodes. Think of an ActorSystem as a distributed container. An actor within an actor system can still communicate with another actor within another actor system in a transparent way for the developer, but the difference is that this communication is done across different networks. That is, ActorSystem provides the network isolation of a set of ActorHost, allowing even very large systems to maintain a high level of isolation and allowing better resource management and avoiding non-essential communication overhead.\\n\\n![ActorSystem](/img/actor-systems.jpg \\"Actor Systems\\")\\n\\nAs seen above through Spawn you can talk to different grain sizes to achieve your goals without having to think too hard about how to connect the parts. You can group all your actors within a single application or break it into smaller parts, but the way you interact between these components will not change, this type of architecture has become an [industry trend](https://www.infoq.com/news/2023/03/google-weaver-framework/) and we proud to say that Spawn thought of all this a long time ago and has leveraged this initiative with our Spawn technology.\\n\\n## Conclusion\\n\\nThis whole discussion around Microservices vs Monoliths is a lot of fun and a excellent mental exercise, but we as software engineers must remember\\nthat at the end of the day, it is our deliveries of value to the business that will make the difference. Spawn with its polyglot serverless experience, using the full potential of Cloud\'s open standards can help you take big steps in that direction. Without you having to waste precious hours around such warm discussions and far from the big goal. Solve your business problems!\\n\\nIn this post we demonstrate that our Spawn technology based on important industry standards and focused on bringing agility to developers\' day-to-day is a valuable tool for you to achieve your business goals without having to give up the scalability and resiliency that the today\'s world demands. We could talk a lot more about Spawn (Activators, Workflows, exposing APIs in a declarative way and much more) but that will be for other posts, today we focus on how Spawn will help you get out of this discussion about Monolithics and Microservices. See you again soon!"},{"id":"spawn-the-actor-mesh","metadata":{"permalink":"/blog/spawn-the-actor-mesh","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2022-09-08-spawn-the-actor-mesh.md","source":"@site/blog/2022-09-08-spawn-the-actor-mesh.md","title":"Hello Spawn! \u2013 The Actor Mesh","description":"Lately we decided to promote Spawn from eigr-labs to the main eigr github organization//github.com/eigr/spawn.","date":"2022-09-08T00:00:00.000Z","formattedDate":"September 8, 2022","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"cloudstate","permalink":"/blog/tags/cloudstate"},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions"},{"label":"project","permalink":"/blog/tags/project"},{"label":"status","permalink":"/blog/tags/status"}],"readingTime":2.615,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"},{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"spawn-the-actor-mesh","title":"Hello Spawn! \u2013 The Actor Mesh","authors":["sleipnir","marcellanz"],"tags":["serverless","cloudstate","eigr-functions","project","status"],"draft":false},"prevItem":{"title":"Beyond Monoliths and Microservices","permalink":"/blog/beyond-monoliths-and-microservices"},"nextItem":{"title":"May 2022 \u2013 Status of the Project","permalink":"/blog/current-status-of-the-project"}},"content":"Lately we decided to promote Spawn from eigr-labs to the main eigr github organization: https://github.com/eigr/spawn.\\nAt the same time we archived the massa proxy repository and explained our motivation behind it.\\n\\nIt has been three years ago when we met in a new open source community while we tried to make a\\nthen shiny new project successful\u2013https://cloudstate.io/. While we\'ve discovered and also implemented a communications\\nprocotol for a multitude of programming languages, we constantly iterated on ideas how to build a system that is able to\\nscale and also being usable on many places not only on backend services. At the time we discovered the serverless space,\\nhaving also solved the stateful aspect of it by using a then promising new procotol and concept called Cloudstate. After\\nsome re-priorization with the project as a whole, the core OSS community moved on to build eigr.io and discover our\\nideas under this new umbrella organization https://eigr.io/.\\n\\n## The Actor Mesh\\n\\n![The Actor Mesh](/img/the_actor_mesh.svg \\"The Actor Mesh\\")\\n\\nOver the last couple of months, Spawn has been shaped by our vision to have a simpler and more focused way to bring an\\nactor system to a polyglot environment, where the way of how components can interact like Actors and Processes do, is\\nnot that well known in other languages. eigr/Massa always was about to solve the challenge of stateful serverless, like\\nit took the vision from its originating project. But at the same time Massa also tried always to solve two things at the\\nsame time. Building a polyglot serverless runtime and also solve the aspect of statefull serverless has been sometimes\\nbeing too much at the same time. Spawn is a focused effort to solve one problem first, and then, being enabled to build\\nthe stateful aspect of serverless on top of it. In this regard, we focus now on something that is that enabler and\\nperhaps one for other problems to solve.\\n\\nThis has been the work of ours lead by Adriano with help from Wesley and Elias; beside that I was able to participate a\\nbit in discussions and presenting our project a two occasions over the last year. I\'m looking forward to see Spawn\\ngrowing into something really cool, special and useful. There is still a lot of work ahead of us and we\'re very exited\\nto see how we can collaborate and grow as a project.\\n\\n## The Future of Eigr is based on Spawn\\n\\nWe are 100% focused on making Spawn a robust, scalable, dynamic and expandable platform, taking us far beyond what\\nwe imagined we were capable of in the initial Cloudstate project and with our previous implementation of Massa.\\nMassa has served us brilliantly as a means of experimentation, and now I feel deeply that we are ready to accomplish\\nwhatever we set out to do.\\n\\nWe invite everyone who is here to download and try Spawn and that we are ready to welcome those who want to contribute,\\nwhether with doubts, suggestions, a little code is also welcome, or a text review, any contribution is welcome. We\\ngreatly admire all of you who are interested in our project."},{"id":"current-status-of-the-project","metadata":{"permalink":"/blog/current-status-of-the-project","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2022-05-25-current-state-of-project.md","source":"@site/blog/2022-05-25-current-state-of-project.md","title":"May 2022 \u2013 Status of the Project","description":"My name is Adriano, I\'m a software engineer, I\'m 40 years old, I\'m Brazilian, and I\'ve been in the technology area for over 20 years on different fronts and having worked in a long list of companies, I\'m also the co-founder of the Eigr project together with @marcellanz and @guyso, previously the three of us were core members of the Cloudstate project and mainly worked on the supporting SDKs, but we also participated in the central development of Cloudstate technology and collaborated a lot on the development mainly of its protocol.","date":"2022-05-25T00:00:00.000Z","formattedDate":"May 25, 2022","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"cloudstate","permalink":"/blog/tags/cloudstate"},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions"},{"label":"project","permalink":"/blog/tags/project"},{"label":"status","permalink":"/blog/tags/status"}],"readingTime":4.075,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"}],"frontMatter":{"slug":"current-status-of-the-project","title":"May 2022 \u2013 Status of the Project","authors":["sleipnir"],"tags":["serverless","cloudstate","eigr-functions","project","status"],"draft":false},"prevItem":{"title":"Hello Spawn! \u2013 The Actor Mesh","permalink":"/blog/spawn-the-actor-mesh"},"nextItem":{"title":"CodeBEAM Europe, Stockholm 2022","permalink":"/blog/codebeam-sto-2022"}},"content":"My name is Adriano, I\'m a software engineer, I\'m 40 years old, I\'m Brazilian, and I\'ve been in the technology area for over 20 years on different fronts and having worked in a long list of companies, I\'m also the co-founder of the Eigr project together with [@marcellanz](https://github.com/marcellanz) and [@guyso](https://github.com/ralphlaude), previously the three of us were core members of the [Cloudstate](https://cloudstate.io/) project and mainly worked on the supporting SDKs, but we also participated in the central development of Cloudstate technology and collaborated a lot on the development mainly of its protocol.\\n\\nI see that many of you have just arrived here and that\'s why I think it\'s important to give an overview of what we do and talk a little about the current status of the project.\\n\\nWell, let\'s go!\\n\\n## Overview:\\n\\nOur ecosystem is called Eigr, and we focus mainly on the following projects:\\n\\n* [Eigr Functions Controller](https://github.com/eigr/eigr-functions-controller): it\'s our deployment brain in Kubernetes, it controls the entire lifecycle of our sidecar along with user functions.\\n\\n* [Massa](https://github.com/eigr/massa): is a Sidecar Proxy and part of the _Eigr Functions_ offering that aims to \\n provide a high-level abstraction for General Purpose Stateful Serverless application development.\\n\\nMassa is responsible for managing the entire data access infrastructure for user functions, as well as other technical tasks such as providing the implementation of the user contract via [gRPC](https://grpc.io/) to the outside world, [transcoding HTTP requests to gRPC](https://cloud.google.com/endpoints/docs/grpc/transcoding), caching, making requests to external sources when requested and other tasks that would once have to be performed by the developer directly in his application.\\n\\nWith Massa the developer only has to worry about their domain objects and their user service interface via a \\ncontract-first declarative approach. These two components together form Eigr Functions.\\n\\nIn addition to these projects, we also work on several other R&D projects that allow us to understand certain parts \\nof the problem we are trying to solve and thus apply the acquired knowledge to the main projects. Research projects worth noting are the following:\\n\\n* [Falco](https://github.com/eigr/falco): A fork of the elixir-grpc project where we try to improve performance and provide a replacement for the original project that is not being updated by the community that created it. Its development continues in research status.\\n\\n* [Steinadler](https://github.com/eigr-labs/steinadler): A high-level alternative to Erlang Distribution. While we are aware of the incredible capabilities of the Erlang Distribution, we also know that there are numerous deficiencies in this protocol that we are trying to address. Its development is currently at a standstill.\\n\\n* [Spawn](https://github.com/eigr-labs/spawn): The **Actor Mesh Framework** is based on the [sidecar proxy pattern]\\n (https://dzone.com/articles/sidecar-design-pattern-in-your-microservices-ecosy-1) to provide the multi-language \\n Actor Model framework. Spawns\' technology-stack on top of the BEAM VM (the Erlang virtual machine) provides support \\n for different languages from its native Actor model. Spawn is made up of the following components:\\n\\n 1. A semantic protocol based on Protocol Buffers.\\n\\n 2. A Sidecar Proxy written in Elixir that implements this protocol as well as persistent storage adapters.\\n\\n 3. SDKs to support different programming languages.\\n\\n Spawn is currently in full development where its main parts will likely be incorporated into the core of Massa.\\n\\n* Astreu (https://github.com/eigr/Astreu): High-performance Messaging System based on a gRPC protocol written in \\n Elixir. Your development is on hold (usable for testing).\\n\\n:::info\\n\\nIn addition to these projects we have the Eigr Functions SDKs which are written in some programming languages \u200b\u200blike \\nElixir, Go, Java and others. Each of these projects is in different phases of development but none are yet readily \\nfunctional.\\n\\n:::\\n\\n## Eigr Functions!\\n\\nCurrently, the Massa project, where our greatest effort is concentrated, is capable of communicating with user \\nfunctions that implement the Cloudstate protocol in version 0.5 and is capable of dealing only with Action-type \\nentities, which are stateless entities.\\n\\nIn the next version of our proxy, we will probably no longer support the Cloudstate protocol because, once Cloudstate has been discontinued, we will adopt our own Protocol and entities.\\n\\nWe intend to support all the original project entity types, namely Action **a.k.a.** Stateless support, Event \\nSourcing, Value Entity (CRUD), and CRDTs ([Conflict Free Replicated Data Types](https://crdt.tech/)). We \\nwill just not bring the semantics of the previous protocol, and creating our own protocol to support these entities.\\n\\nSo we are in the process of a complete redesign of our protocol and therefore our proxy as well. We are doing this \\nwith proof of concepts in parallel projects and in project-specific branches within Massa.\\n\\nThis is a summary of what we have done and where we intend to go. I hope to be able to count on your \\ncollaboration in any way, with code, with good discussions, answering doubts, or just making small talk around [here](https://discord.gg/Y55eZpyvNs).\\n\\nI\'m curious to know a little more about you and what you expect from us.\\n\\nAh, I was forgetting, for those who want to know the reasons for the name Massa I suggest reading [here](https://github.com/eigr/massa/blob/main/FAQ.md).\\n\\nThanks for reading!"},{"id":"codebeam-sto-2022","metadata":{"permalink":"/blog/codebeam-sto-2022","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2022-05-19-codebeam-sto-2022.md","source":"@site/blog/2022-05-19-codebeam-sto-2022.md","title":"CodeBEAM Europe, Stockholm 2022","description":"We\'re excited to be selected","date":"2022-05-19T00:00:00.000Z","formattedDate":"May 19, 2022","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"eigr","permalink":"/blog/tags/eigr"}],"readingTime":0.655,"hasTruncateMarker":false,"authors":[{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"codebeam-sto-2022","title":"CodeBEAM Europe, Stockholm 2022","authors":["marcellanz"],"tags":["serverless","eigr"]},"prevItem":{"title":"May 2022 \u2013 Status of the Project","permalink":"/blog/current-status-of-the-project"},"nextItem":{"title":"ACM SIGPLAN, ICFP Erlang Workshop 2021","permalink":"/blog/acm-sigplan-ifcp-erlang-workshop-2021"}},"content":"We\'re excited to be selected\\nfor [one of the main talks](https://codesync.global/speaker/marcel-lanz/#947a-serverless-runtime-on-the-beam) at the\\nCodeBEAM Europe conference in Stockholm in May\\n2022 [CodeBEAM Europe](https://codesync.global/conferences/code-beam-sto-2022/).\\n\\n## Abstract\\n\\nServerless runtimes are often hidden in cloud providers offering and exposed solely by their programming API and\\ndeployment procedures. In this talk, we\'ll explore an open-source Serverless runtime built for the cloud and\\non-premises, running on the BEAM with a polyglot programming model to build general-purpose applications.\\n\\nIn this talk, we\'ll present how the BEAM and OTP are an ideal fit to build a Serverless runtime. After an introduction\\nabout Serverless and a polyglot programming model, we\'ll present the open-source project at eigr.io where we implemented\\nthe core of our runtime based on Erlang/OTP and written in Elixir.\\n\\n**Event:**\\nhttps://codesync.global/speaker/marcel-lanz/#947a-serverless-runtime-on-the-beam\\n\\n**\\nSlides:** [Slideshare](https://www.slideshare.net/MarcelLanz/v13eigrioaserverlessruntimeonthebeampptx/MarcelLanz/v13eigrioaserverlessruntimeonthebeampptx)\\n, [Google Slides](https://docs.google.com/presentation/d/1Km-zh2rItr-setoUJjJV9W43tNZVNJmQtXb3_va_vRQ/edit?usp=sharing)"},{"id":"acm-sigplan-ifcp-erlang-workshop-2021","metadata":{"permalink":"/blog/acm-sigplan-ifcp-erlang-workshop-2021","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2021-08-19-acm-sigplan-icfp-erlang-workshop-2021.md","source":"@site/blog/2021-08-19-acm-sigplan-icfp-erlang-workshop-2021.md","title":"ACM SIGPLAN, ICFP Erlang Workshop 2021","description":"We\'re excited to be selected","date":"2021-08-19T00:00:00.000Z","formattedDate":"August 19, 2021","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"eigr","permalink":"/blog/tags/eigr"}],"readingTime":0.81,"hasTruncateMarker":false,"authors":[{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"acm-sigplan-ifcp-erlang-workshop-2021","title":"ACM SIGPLAN, ICFP Erlang Workshop 2021","authors":["marcellanz"],"tags":["serverless","eigr"]},"prevItem":{"title":"CodeBEAM Europe, Stockholm 2022","permalink":"/blog/codebeam-sto-2022"}},"content":"We\'re excited to be selected\\nfor [one of the Lightning Talks](https://icfp21.sigplan.org/details/erlang-2021-papers/13/Lightning-Talk-eigr-io-A-Serverless-Runtime-on-the-BEAM)\\nright after the Erlang Keynote at the ACM\\nSIGPLAN, [ICFP Erlang Workshop 2021](https://icfp21.sigplan.org/home/erlang-2021).\\n\\n## Abstract\\n\\nServerless runtimes are often hidden in a cloud providers offering and exposed\\nsolely by their programming API and deployment procedures. In this talk, we\u2019ll\\nexplore an open-source Serverless runtime built for the cloud and on-premises,\\nrunning on the BEAM with a polyglot programming model to build general purpose\\napplications.\\n\\nBuilding general purpose applications using multiple languages and having a\\nstory how to handle state was our main motivation to explore the space of a\\nServerless runtime to be built. We think the BEAM, OTP and Elixir/Erlang are a\\nperfect match to build on.\\n\\nWith this talk, we combine herein the world of the BEAM with cloud technology\\nlike a gRPC-based protocol, Kubernetes and a polyglot programming model with\\nlanguages supported like Go, JavaScript, JVM-languages, Python and many more.\\n\\n**Event:**\\nhttps://icfp21.sigplan.org/details/erlang-2021-papers/13/Lightning-Talk-eigr-io-A-Serverless-Runtime-on-the-BEAM\\n\\n**\\nSlides:** [Slideshare](https://www.slideshare.net/MarcelLanz/eigrio-a-serverless-runtime-on-the-beam-acm-sigplan-icfp-2021-erlang-workshop)\\n, [Google Slides](https://docs.google.com/presentation/d/1mLmSFY0z6gxoG88-phcFTwyVBMv8R9myBA5MZOWoJso/edit#slide=id.p1)"}]}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[1477],{10:function(e){e.exports=JSON.parse('{"blogPosts":[{"id":"spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space","metadata":{"permalink":"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2023-12-27-spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-erlang-beam-space.md","source":"@site/blog/2023-12-27-spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-erlang-beam-space.md","title":"Spawn and FLAME: A Symphony of Innovation in the Serverless Erlang/BEAM Space","description":"In recent times, the eigr community had the privilege of exploring a new addition to the Erlang/BEAM landscape, inspired by the Serverless model: FLAME. The excitement surrounding this release was tangible, especially given FLAME\'s connection to the renowned Phoenix framework. While Spawn, our software in the same Serverless sphere, might appear as a direct competitor, we believe there is more synergy than competition between them.","date":"2023-12-27T00:00:00.000Z","formattedDate":"December 27, 2023","tags":[{"label":"spawn","permalink":"/blog/tags/spawn"},{"label":"FLAME","permalink":"/blog/tags/flame"},{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"elixir","permalink":"/blog/tags/elixir"}],"readingTime":2.095,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"}],"frontMatter":{"slug":"spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space","title":"Spawn and FLAME: A Symphony of Innovation in the Serverless Erlang/BEAM Space","authors":["sleipnir"],"tags":["spawn","FLAME","serverless","elixir"],"draft":false},"nextItem":{"title":"Distributed Elixir made easy with Spawn","permalink":"/blog/distributed-elixir-made-easy-with-spawn"}},"content":"In recent times, the eigr community had the privilege of exploring a new addition to the Erlang/BEAM landscape, inspired by the Serverless model: [FLAME](https://github.com/phoenixframework/flame). The excitement surrounding this release was tangible, especially given FLAME\'s connection to the renowned Phoenix framework. While [Spawn](https://github.com/eigr/spawn), our software in the same Serverless sphere, might appear as a direct competitor, we believe there is more synergy than competition between them.\\n\\nIt may seem peculiar that we express satisfaction with FLAME, considering that Spawn also operates in the Serverless space. However, after more than four years of dedicated work and pioneering discussions on topics like Stateful Serverless and durable computing, we recognize that attention is now turning to concepts we championed from the outset. Additionally, FLAME is built on the Erlang virtual machine, making it a distant relative and, in a sense, an ally in our journey.\\n\\nWe are genuinely excited about FLAME, actively contributing to its ecosystem and [collaboratively engaging with its community of developers](https://github.com/phoenixframework/flame/issues/9) and users. Leveraging our expertise in Kubernetes, we are even developing a [backend](https://github.com/eigr-labs/flame-k8s) for FLAME in this area, inviting everyone to join us in this joint endeavor.\\n\\n## Spawn vs. FLAME: Exploring Differences and Complementarities\\n\\nDespite some superficial similarities, Spawn and FLAME are fundamentally distinct, both inspired by the Serverless model but with complementary approaches. While FLAME follows the Function as a Service (FaaS) paradigm, literally sending functions over the wire and adopting a stateless premise, Spawn is more oriented toward applications that require state management.\\n\\nIn Spawn, we not only embrace the Serverless model but also introduce a new layer based on actors, business contracts and a [totally polyglot model of programming](https://github.com/eigr/spawn/blob/main/docs/sdks.md). This approach offers a fresh perspective on software design, encouraging developers to think in terms of business rather than the algorithms needed to ensure the infrastructure functions concerning state or external services. While FLAME moves functions across the network, in Spawn, we shift data to computation, fundamentally altering how applications are built and maintained.\\n\\nIn summary, although they may seem like competitors at first glance, Spawn and FLAME coexist harmoniously, addressing different needs and providing valuable approaches in the vast universe of Serverless computing in the Erlang/BEAM space. Our goal is not only to highlight the differences but also to promote collaboration between both communities, collectively building a more innovative and robust future for Serverless software development.\\n\\nIn future posts we will discuss more about how Spawn and FLAME can be applied in a complementary way. \\nThese are exciting times for serverless computing. Happy coding! \ud83d\ude80\u2728"},{"id":"distributed-elixir-made-easy-with-spawn","metadata":{"permalink":"/blog/distributed-elixir-made-easy-with-spawn","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2023-12-03-distributed-elixir-made-easy.md","source":"@site/blog/2023-12-03-distributed-elixir-made-easy.md","title":"Distributed Elixir made easy with Spawn","description":"Hello Elixir enthusiasts! \ud83d\ude80 As the tech landscape evolves, so should our tools and approaches to development. Today, I\'m excited to introduce you to a significant advancement in Elixir development that can reshape how we build distributed systems \u2013 I present to you Spawn.","date":"2023-12-03T00:00:00.000Z","formattedDate":"December 3, 2023","tags":[{"label":"spawn","permalink":"/blog/tags/spawn"},{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"elixir","permalink":"/blog/tags/elixir"},{"label":"distributed","permalink":"/blog/tags/distributed"},{"label":"durable computing","permalink":"/blog/tags/durable-computing"}],"readingTime":9.695,"hasTruncateMarker":false,"authors":[{"name":"Elias Dal Ben Arruda","title":"eigr.io \u2013 Core Team","url":"https://github.com/eliasdarruda","imageURL":"https://avatars.githubusercontent.com/u/19327513?v=4","key":"eliasdarruda"},{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"}],"frontMatter":{"slug":"distributed-elixir-made-easy-with-spawn","title":"Distributed Elixir made easy with Spawn","authors":["eliasdarruda","sleipnir"],"tags":["spawn","serverless","elixir","distributed","durable computing"],"draft":false},"prevItem":{"title":"Spawn and FLAME: A Symphony of Innovation in the Serverless Erlang/BEAM Space","permalink":"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space"},"nextItem":{"title":"Beyond Monoliths and Microservices","permalink":"/blog/beyond-monoliths-and-microservices"}},"content":"Hello Elixir enthusiasts! \ud83d\ude80 As the tech landscape evolves, so should our tools and approaches to development. Today, I\'m excited to introduce you to a significant advancement in Elixir development that can reshape how we build distributed systems \u2013 I present to you Spawn.\\n\\n## The Elixir Actors Dilemma\\n\\nWe\'ve all been there \u2013 struck by that stroke of genius while working with Elixir. The allure of in-memory state storage, backed by the reliability of Erlang/OTP, seems like a dream come true. But reality hits hard, especially in the realm of production environments where Kubernetes often plays a pivotal role. Managing multiple servers autonomously, especially in distributed systems, can quickly turn our dream into a complex nightmare.\\n\\n## Enter Spawn: A New Approach to Actors\\n\\n[**Spawn**](https://github.com/eigr/spawn) is not just another framework; it\'s a paradigm shift in how we implement code. Imagine a world where you can care less about the underlying infrastructure and instead focus on crafting the domain-specific logic that truly matters. That\'s precisely what Spawn brings to the table.\\n\\nLet\'s delve into a quick comparison between a traditional GenServer approach and the innovative Spawn Actor using the [**_Spawn Elixir SDK_**](https://github.com/eigr/spawn/tree/main/spawn_sdk/spawn_sdk).\\n\\n### Consider a GenServer that does the following:\\n\\n```elixir\\ndefmodule Incrementor do\\n use GenServer\\n\\n defmodule State do\\n defstruct [total: 0]\\n end\\n\\n def init(_), do: {:ok, %State{total: 0}}\\n\\n def handle_call({:add, value}, _from, state) do\\n new_total = state.total + value\\n\\n {:reply, {:ok, %{total: new_total}}, %State{state | total: new_total}}\\n end\\nend\\n```\\n\\nIf we execute it, as you probably now already, we can add a specified value to the total stored in memory, and calling add will always return the total amount stored in memory.\\n\\n```elixir\\niex(1)> {:ok, pid} = GenServer.start_link(Incrementor, [])\\niex(2)> GenServer.call(pid, {:add, 1})\\n{:ok, %{total: 1}}\\n\\niex(3)> GenServer.call(pid, {:add, 1})\\n{:ok, %{total: 2}}\\n```\\n\\n### With Spawn, the same definition would look like:\\n\\nOur process defined by the `GenServer`, we call it an _Actor_.\\n\\n```elixir\\ndefmodule IncrementorActor do\\n use SpawnSdk.Actor,\\n name: \\"incrementor\\",\\n kind: :named,\\n state_type: :json,\\n deactivate_timeout: 30_000,\\n snapshot_timeout: 10_000\\n\\n defmodule State do\\n @derive {Jason.Encoder, only: [:total]}\\n defstruct [total: 0]\\n end\\n\\n defact init(%Context{} = ctx), do: Value.noreply_state!(ctx.state || %State{})\\n\\n defact add(%{value: value}, %Context{} = ctx) do\\n new_total = ctx.state.total + value\\n\\n Value.of()\\n |> Value.state(%State{total: new_total})\\n |> Value.response(%{total: new_total})\\n end\\nend\\n```\\n\\nOur application would look like:\\n\\n```elixir\\ndefmodule Example.Application do\\n @moduledoc false\\n use Application\\n\\n @impl true\\n def start(_type, _args) do\\n children = [\\n {\\n SpawnSdk.System.Supervisor,\\n system: \\"spawn-system\\",\\n actors: [\\n IncrementorActor\\n ]\\n }\\n ]\\n\\n opts = [strategy: :one_for_one, name: Example.Supervisor]\\n Supervisor.start_link(children, opts)\\n end\\nend\\n```\\n\\nAnd the SDK can be installed in your Elixir project with:\\n\\n```elixir\\n[\\n {:spawn_sdk, \\"~> 1.1\\"},\\n # if using stateful actors\\n # {:spawn_statestores_mysql, \\"~> 1.1\\"}\\n # {:spawn_statestores_postgres, \\"~> 1.1\\"}\\n # ... others\\n]\\n```\\n\\nWhen using a statestore, you need to define a statestore key in `config.exs` or using `SPAWN_STATESTORE_KEY` environment variable to make sure your actor state is properly encrypted.\\n\\n> **NOTE:** It is **recommended** to securely store the key in the environment where it is being used.\\n\\n```elixir\\nconfig :spawn_statestores, statestore_key: \\"secure_database_key\\"\\n```\\n\\nHaving that defined, the same for `Calling` or `Casting` a process in a GenServer, we do it with `invoke`.\\n\\nPassing any message we want in the payload attribute, it needs to be a struct or map that can be encoded to JSON or a protobuf struct.\\n\\n```elixir\\niex(1)> SpawnSdk.invoke(\\"incrementor\\", system: \\"spawn-system\\", action: \\"add\\", payload: %{value: 1})\\n{:ok, %{total: 1}}\\n```\\n\\n> **_NOTE_**: We **recommend** to use protobufs as payload and also the state definition, with: `state_type: Protos.YourStateType`, however for this example for the sake of simplicity we are using JSON.\\n\\n## Unpacking the Magic: Answers to Your Questions\\n\\n1. What exactly is \\"spawn-system\\"?\\n\\nSpawn operates as a platform that manages infrastructure for you. \\"spawn-system\\" is a configuration entity encapsulating multiple actors within a meaningful context.\\n\\n2. Why is it an SDK?\\n\\nSpawn embraces a multi-language approach. SDKs allow different actors, even in different languages, to register with Spawn. For instance, you could have Elixir and NodeJS actors running the same logic seamlessly.\\n\\n3. How do I run it?\\n\\nIn development, you can use Spawn as a lib. For production, use Kubernetes CRDs provided by Spawn for easy and scalable deployment.\\n\\n4. How do we handle state persistence?\\n\\nSpawn intelligently handles state persistence through well-defined timeouts and snapshot mechanisms, ensuring reliability even during rollouts.\\n\\n5. Why not just use a GenServer?\\n\\nManaging a distributed system with GenServer requires tackling numerous challenges. Spawn abstracts away these complexities, allowing you to focus on your domain logic without getting lost in infrastructure intricacies.\\n\\nTwo items above deserve a little more comment:\\n\\n### Actor System\\n\\nSpawn is a platform that also handles infrastructure for you, we run on top of kubernetes and have defined some [**Kubernetes CRDs**](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) that helps you configure the clustering and lifecycle of your actors.\\n\\nA system is an entity that encapsulates multiple Actors in a context that makes sense for you.\\n\\nWe can configure one using the pre-defined Spawn CRDs, and we will also be configuring here which persistent database we are going to use to hold our Actors state.\\n\\n### SDKs\\n\\nWe can have multiple actors in the same system, with different SDKs registering those actors.\\nWe call each deployment that uses an SDK an \\"ActorHost.\\"\\n\\nIn our example, we could have two SDKs, Elixir and NodeJS, running the same actor or different ones.\\nSpawn will then forward any invocations for one of those registered SDKs, with the specified implementation for each action.\\nYou can even invoke an actor registered in a different system or in the same system from another SDK.\\n\\nFor instance, if we wanted to invoke the same actor we wrote but in a [NodeJS ActorHost](https://github.com/eigr/spawn-node-sdk), it would look like this:\\n\\n```ts\\nimport spawn from \'@eigr/spawn-sdk\'\\n\\nconst response = await spawn.invoke(\'incrementor\', {\\n action: \'add\',\\n system: \'spawn-system\',\\n payload: {value: 5}\\n})\\n\\nconsole.log(response)\\n// { total: 6 }\\n```\\n\\nThis way, we can interact with each actor globally, across different Systems and ActorHosts, while still maintaining the same state handling mechanism. And the best part? We can achieve all of this without the need for transactions, locks, or any additional infrastructure to support sequential state write changes of that nature.\\n\\n### That sounds magical, how do I run it?\\n\\nIn development mode for Elixir, you can take advantage of using Spawn as a lib, you\'ll be able to use all the features you wan\'t in a single runtime.\\n\\nHowever for production we **recommend** using our CRDs set up for you.\\n\\nFirst of all you need to install our k8s CRD with the following manifest (using kubectl):\\n\\n```bash\\nkubectl create ns eigr-functions && curl -L https://github.com/eigr/spawn/releases/download/v1.1.1/manifest.yaml | kubectl apply -f -\\n```\\n\\n> **_NOTE:_** You need to inform the desired release version. Check our github to see the latest one released.\\n\\nAfter installing it successfully, you need now to configure your System:\\n\\n```yaml\\napiVersion: spawn-eigr.io/v1\\nkind: ActorSystem\\nmetadata:\\n name: spawn-system # Mandatory. Name of the ActorSystem\\n namespace: default # Optional. Default namespace is \\"default\\"\\nspec:\\n statestore:\\n type: MySql # Valid are [Postgres, MySql, MariaDB, Sqlite, MSSQL, CockroachDB]\\n credentialsSecretRef: mysql-connection-secret # The secret containing connection params created in the previous step.\\n pool: # Optional\\n size: \\"10\\"\\n```\\n\\nYou can generate the credentialsSecret or use whatever secret you are using to store your database credentials.\\nAn example would be, note that the secret needs to be created at the namespace `eigr-functions`.\\n\\n```bash\\nkubectl create secret generic mysql-connection-secret -n eigr-functions \\\\\\n --from-literal=database=eigr-functions-db \\\\\\n --from-literal=host=\'mysql\' \\\\\\n --from-literal=port=\'3306\' \\\\\\n --from-literal=username=\'admin\' \\\\\\n --from-literal=password=\'admin\' \\\\\\n --from-literal=encryptionKey=$(openssl rand -base64 32)\\n```\\n\\nAfter installing the system, you will need to register your ActorHost, that can look like:\\n\\n```yaml\\napiVersion: spawn-eigr.io/v1\\nkind: ActorHost\\nmetadata:\\n name: elixir-example\\n namespace: default\\n annotations:\\n spawn-eigr.io/actor-system: spawn-system\\nspec:\\n host:\\n image: org/your-host-image:0.0.1\\n embedded: true # this is only for Elixir Sdks, you can ignore this if you will use another language\\n ports:\\n - name: \\"http\\"\\n containerPort: 8800\\n autoscaler:\\n min: 1\\n max: 2\\n```\\n\\nJust by applying this configuration, and having a container that has the application with the example we wrote in the start of the article, we should see\\nthe instances starting that should handle the clustering and all the heavy infrastructure work for you.\\n\\n## Managing State Resilience with Spawn\\n\\nIn the realm of Spawn, we prioritize the resilience of your application\'s state. Each actor in Spawn comes with configurable parameters, namely the snapshot_timeout and deactivate_timeout. Let\'s delve into these settings:\\n\\n- **deactivate_timeout** determines the duration (in milliseconds) your actor remains actively in memory, even when not in use.\\n\\n- **snapshot_timeout** how frequently snapshots of your actor\'s state are saved in your persistent storage.\\n\\nThe magic unfolds after an actor is deactivated, triggered either by the specified timeout or during a Kubernetes rollout. In this scenario, Spawn meticulously manages the lifecycle of each process, ensuring that the state is gracefully saved in the configured persistent storage.\\n\\nHere\'s the key assurance: even in the face of failures, crashes, or net-splits, Spawn guarantees that the state of your application will always revert to the last valid state. This means if an instance fails, another node seamlessly takes over from where it left off, ensuring the continuity and integrity of your application\'s data. Our meticulous tuning of Custom Resource Definitions (CRDs) and signal handling ensures that you won\'t lose data during rollouts or network partitions.\\n\\nWith Spawn, you can confidently embrace a resilient state management model, where the reliability and consistency of your application\'s data are at the forefront of our design philosophy.\\n\\n## Unleashing Gains in Agility and Innovation with Spawn\\n\\nBeyond the facade of extensive configurations lies a treasure trove of advantages awaiting exploration. Spawn not only simplifies but significantly enriches your development experience. Imagine bidding farewell to the complexities of defining Kubernetes resources, the intricacies of rollouts, the considerations of HPA, and the worries of scalability, network configurations, and system integrity assessments.\\n\\nSpawn emerges as the driving force behind a newfound sense of agility and innovation. It liberates you from the burdensome aspects of infrastructure management, allowing you to redirect your focus towards what truly matters \u2013 crafting innovative solutions. Step into a future where complexities dissolve, and your journey into agile and innovative Elixir development begins with a resounding hello!\\n\\nIf you choose to go down that path, you will need to face at least the following challenges:\\n\\n- Ensuring proper handling of connections between multiple nodes in your Erlang cluster.\\n- Ensuring reliable and synchronized data rollouts to avoid message or state loss during instances rolling out.\\n- Implementing effective persistence mechanisms to recover data in the event of netsplit scenarios, preventing data loss.\\n- Managing the process lifecycle to ensure predictable recovery and maintain a consistent state in case of errors.\\n- Designing a well-defined API that integrates your processes seamlessly with other systems, ensuring message synchronization.\\n- Establishing a reliable distribution mechanism for sending messages to actors within your own edge, with the ability to synchronize them later.\\n- Mitigating process queue bottlenecks to optimize performance and prevent delays.\\n- Ensuring atomicity in a distributed system, maintaining data consistency and integrity.\\n- Ensuring that you can concentrate on your domain-specific code without being burdened by unnecessary complexities and boilerplate.\\n- Implementing seamless integration patterns, including process pipelines, customized activators, workflows, and effective management of side effects, among others.\\n- Developing and managing infrastructure code related to brokers, caching, and other components.\\n\\n## Conclusion\\n\\nThis is more than just a practical example; it\'s an invitation to explore the full potential of Spawn. For a deeper dive into the concepts and foundations, refer to our [Spawn Full Documentation](https://github.com/eigr/spawn) and our insightful article [Beyond Monoliths and Microservices](https://eigr.io/blog/beyond-monoliths-and-microservices/).\\n\\nReady to elevate your Elixir development experience? Embrace the future with Spawn. Happy coding! \ud83d\ude80\u2728"},{"id":"beyond-monoliths-and-microservices","metadata":{"permalink":"/blog/beyond-monoliths-and-microservices","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2023-05-10-beyond-monoliths-and-microservices.md","source":"@site/blog/2023-05-10-beyond-monoliths-and-microservices.md","title":"Beyond Monoliths and Microservices","description":"Recently a article","date":"2023-05-10T00:00:00.000Z","formattedDate":"May 10, 2023","tags":[{"label":"spawn","permalink":"/blog/tags/spawn"},{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions"},{"label":"design","permalink":"/blog/tags/design"},{"label":"architect","permalink":"/blog/tags/architect"}],"readingTime":8.4,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"},{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"beyond-monoliths-and-microservices","title":"Beyond Monoliths and Microservices","authors":["sleipnir","marcellanz"],"tags":["spawn","serverless","eigr-functions","design","architect"],"draft":false},"prevItem":{"title":"Distributed Elixir made easy with Spawn","permalink":"/blog/distributed-elixir-made-easy-with-spawn"},"nextItem":{"title":"Hello Spawn! \u2013 The Actor Mesh","permalink":"/blog/spawn-the-actor-mesh"}},"content":"Recently a [article](https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90)\\nlaunched by the Amazon Prime team reactivated the Monoliths versus Microservices discussion. It is remarkable, and often reproachable, \\nhow many fervent feelings there are around this already old discussion.\\nI\'ve always wondered what the point really was between these two conflicting worldviews. And I could never understand why\\nso much energy is expended on this type of discussion.\\n\\nIn this article we intend to introduce you to why it\'s time to move forward and how our Spawn technology can help developers \\nlet go of these age-old issues, and that do not add much value to the business.\\n\\n## Monoliths\\n\\n![Monoliths](/img/monoliths.jpg \\"Monoliths\\")\\n\\nMonolithic architecture is given by a single, undivided system that runs in a single process, a software application in which different components are linked to a single program within a single platform.\\nAs the entire system is in a single block, its initial development can be more agile, making it possible to develop an application in less time and with less initial complexity, notice the initial word.\\n\\nAs a monolithic application evolves, several classes, modules, methods or functions are added to this same code and process.\\nAnother point is that monolithic applications tend not to scale horizontally well, since all the general functionality of a system is tied to a single process it is expected that this type of application scales better vertically than horizontally. This particular characteristic also makes it difficult to implement this type of system in environments such as Kubernetes or other types of Cloud environments, notice that I said difficult and not unfeasible.\\n\\nAnd this is where the problems with this type of architecture usually start to appear. In other words, the issue with monoliths seems to be directly related to the scale of the system in question. The more complexity you add, the harder it gets to maintain, which requires more complexity to mitigate the problem, which makes it harder to maintain.... well, you get the point.\\nTo get around these effects, there are many software engineering patterns that help to mitigate such failures (facades, ports, adapters, interface programming and so on), all this additional complexity turns out to be a good price to pay for its defenders, to a certain extent.\\n\\n## Microservices\\n\\n![Microservices](/img/microservices.jpg \\"Microservices\\")\\n\\nWhat differentiates the microservices architecture from more traditional monolithic approaches is how it decomposes the application into smaller units. Each unit in turn is called a service and can be created and deployed independently. In other words, each individual service can work or fail without compromising the others. This helps you embrace the technology side of DevOps and make constant iteration and constant delivery (CI/CD) more streamlined and feasible (at least in theory).\\nIn terms of scaling microservices tend to scale better horizontally than vertically and this in turn is better for infrastructures powered by Kubernetes, Serververless, or even other types of Cloud environments.\\n\\nBut not everything is flowers with microservices. Microservices, generally, increase the complexity in managing failures and in the control of expenses with infrastructure. Developers had to become experts in distributed and large-scale systems.\\nTo deal with it all, over the years several techniques have emerged to avoid various problems of distributed systems, as well as the advent of Observability and FinOps techniques that helped to control infrastructure costs, allowed the architecture of microservices to become extremely popular.\\n\\n## Spawn and Beyond\\n\\nI could write dozens of pros and cons of each of these architectures and, at least for us, I would never come up with an outright winner. The undeniable fact is that both have great strengths and equally great flaws. We are without a winner and therefore we need to let go and go further.\\n\\nIn simple terms, what we here in the Eigr community believe is that developers, in general, need a platform that is, among other things, be simpler, dynamic, vendor lock free, focused on the business domain and not on precious technicalities, and that adapts well to the granularity your business requirements demand.\\n\\nNow let\'s introduce our Spawn technology and try to explore a little bit of how it can help us go further.\\n\\n[Spawn](https://github.com/eigr/spawn) is primarily based on three very powerful abstractions, the [Sidecar Pattern](https://thenewstack.io/operators-and-sidecars-are-the-new-model-for-software-delivery/), the [Actor Model](https://www.brianstorti.com/the-actor-model/) and the [Serverless](https://www2.eecs.berkeley.edu/Pubs/TechRpts/2019/EECS-2019-3.pdf). The former allows you to deploy an application\'s components in a separate process or container providing isolation and encapsulation. This pattern enables applications to be composed of heterogeneous technologies and components, while allowing this separate process to handle the infrastructure layers without affecting the evolution of your business code. In turn, the second is a fascinating and relatively simple alternative for the development of distributed and concurrent systems. This model allows you to decompose your system into small units, called actors, that communicate only by passing messages. Actors encapsulate state and behavior in a single unit, and are lock-free, that is, when programming with actors you are free of semaphore, mutex and any type of synchronizing code. And finally Serverless lets developers focus on their code without worrying about the infrastructure. Using Kubernetes as an orchestrator for our serverless workloads we can provide a self managed platform without forcing the developer to be tied to any existing public cloud offerings. Free from blockages! \\n\\nHowever, it goes beyond the basics of the Actor Model by exposing several software patterns in a simplified way for the developer. Spawn is also domain oriented to your business, allowing you to focus directly on the business problem, while the Spawn runtime handles things like state management and persistence, caching, inter-process calls, scalability, cluster management, scaling up and down, integration with external middleware, among many other non-functional requirements that software usually needs to achieve its final goals. \\n\\nSpawn is also a polyglot platform, allowing you to write Actors in different languages and allowing them to communicate with each other in a totally transparent way without the need to define REST or RPC interfaces between your components. Being based on the powerful [Erlang technology](https://www.wired.com/2015/09/whatsapp-serves-900-million-users-50-engineers) you get the best of what the, [battle tested](https://elixir-lang.org/blog/2020/10/08/real-time-communication-at-scale-with-elixir-at-discord/), [Erlang Virtual Machine is capable of providing](https://serokell.io/blog/introduction-to-erlang) without giving up your natural domain language, be it [Java, Typescript, Elixir](https://github.com/eigr/spawn#sdks), or another.\\n\\nNow that we have a basic idea about Spawn we can move on to how it can help us move beyond the discussion of Monoliths and Microservices.\\n\\n## Services, Applications, and Granularity\\n\\nTo understand how Spawn can help us move the discussion forward, we first need to understand how Spawn organizes its deployable components.\\nThe most basic unit of Spawn is the Actor, it is through Actors that developers can express their domain problems and as we said before the Actor is responsible for encapsulating the state and its associated behavior in itself.\\n\\n![Actors](/img/actors.jpg \\"Actors\\") \\n\\nThat said, a Spawn application in a simplified way is nothing more than a series of Actors organized in an deployment unit that we can call service or application, but which in our terminology we call ActorHost. An ActorHost is the deployable unit which is made up of the host container (where the developer works) plus the proxy container which is where the actors actually perform their tasks.\\n\\n![ActorHost](/img/actor-host.jpg \\"Actor Host\\")\\n\\nYou can have hundreds or even thousands of actors running on a single ActorHost and that in turn can have multiple replicas running on a cluster. As Spawn Actors are activated only when there is work to be done and are deactivated after a period of inactivity, the workloads are distributed among different replicas of the same ActorHost. From the developer\'s point of view, it doesn\'t matter because the only thing he needs to be able to send a message to an actor is his name. No complicated APIs with additional worries like service discovery, circuit breakers or anything else.\\n\\n![Replicas](/img/actor-host-replicas.jpg \\"Actor Host Distribution\\")\\n\\nAnd finally your ActorHost are grouped within a more general system that we call ActorSystem. All ActorHost applications within the same actor system actively communicate with each other forming a real cluster of nodes. Think of an ActorSystem as a distributed container. An actor within an actor system can still communicate with another actor within another actor system in a transparent way for the developer, but the difference is that this communication is done across different networks. That is, ActorSystem provides the network isolation of a set of ActorHost, allowing even very large systems to maintain a high level of isolation and allowing better resource management and avoiding non-essential communication overhead.\\n\\n![ActorSystem](/img/actor-systems.jpg \\"Actor Systems\\")\\n\\nAs seen above through Spawn you can talk to different grain sizes to achieve your goals without having to think too hard about how to connect the parts. You can group all your actors within a single application or break it into smaller parts, but the way you interact between these components will not change, this type of architecture has become an [industry trend](https://www.infoq.com/news/2023/03/google-weaver-framework/) and we proud to say that Spawn thought of all this a long time ago and has leveraged this initiative with our Spawn technology.\\n\\n## Conclusion\\n\\nThis whole discussion around Microservices vs Monoliths is a lot of fun and a excellent mental exercise, but we as software engineers must remember\\nthat at the end of the day, it is our deliveries of value to the business that will make the difference. Spawn with its polyglot serverless experience, using the full potential of Cloud\'s open standards can help you take big steps in that direction. Without you having to waste precious hours around such warm discussions and far from the big goal. Solve your business problems!\\n\\nIn this post we demonstrate that our Spawn technology based on important industry standards and focused on bringing agility to developers\' day-to-day is a valuable tool for you to achieve your business goals without having to give up the scalability and resiliency that the today\'s world demands. We could talk a lot more about Spawn (Activators, Workflows, exposing APIs in a declarative way and much more) but that will be for other posts, today we focus on how Spawn will help you get out of this discussion about Monolithics and Microservices. See you again soon!"},{"id":"spawn-the-actor-mesh","metadata":{"permalink":"/blog/spawn-the-actor-mesh","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2022-09-08-spawn-the-actor-mesh.md","source":"@site/blog/2022-09-08-spawn-the-actor-mesh.md","title":"Hello Spawn! \u2013 The Actor Mesh","description":"Lately we decided to promote Spawn from eigr-labs to the main eigr github organization//github.com/eigr/spawn.","date":"2022-09-08T00:00:00.000Z","formattedDate":"September 8, 2022","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"cloudstate","permalink":"/blog/tags/cloudstate"},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions"},{"label":"project","permalink":"/blog/tags/project"},{"label":"status","permalink":"/blog/tags/status"}],"readingTime":2.615,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"},{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"spawn-the-actor-mesh","title":"Hello Spawn! \u2013 The Actor Mesh","authors":["sleipnir","marcellanz"],"tags":["serverless","cloudstate","eigr-functions","project","status"],"draft":false},"prevItem":{"title":"Beyond Monoliths and Microservices","permalink":"/blog/beyond-monoliths-and-microservices"},"nextItem":{"title":"May 2022 \u2013 Status of the Project","permalink":"/blog/current-status-of-the-project"}},"content":"Lately we decided to promote Spawn from eigr-labs to the main eigr github organization: https://github.com/eigr/spawn.\\nAt the same time we archived the massa proxy repository and explained our motivation behind it.\\n\\nIt has been three years ago when we met in a new open source community while we tried to make a\\nthen shiny new project successful\u2013https://cloudstate.io/. While we\'ve discovered and also implemented a communications\\nprocotol for a multitude of programming languages, we constantly iterated on ideas how to build a system that is able to\\nscale and also being usable on many places not only on backend services. At the time we discovered the serverless space,\\nhaving also solved the stateful aspect of it by using a then promising new procotol and concept called Cloudstate. After\\nsome re-priorization with the project as a whole, the core OSS community moved on to build eigr.io and discover our\\nideas under this new umbrella organization https://eigr.io/.\\n\\n## The Actor Mesh\\n\\n![The Actor Mesh](/img/the_actor_mesh.svg \\"The Actor Mesh\\")\\n\\nOver the last couple of months, Spawn has been shaped by our vision to have a simpler and more focused way to bring an\\nactor system to a polyglot environment, where the way of how components can interact like Actors and Processes do, is\\nnot that well known in other languages. eigr/Massa always was about to solve the challenge of stateful serverless, like\\nit took the vision from its originating project. But at the same time Massa also tried always to solve two things at the\\nsame time. Building a polyglot serverless runtime and also solve the aspect of statefull serverless has been sometimes\\nbeing too much at the same time. Spawn is a focused effort to solve one problem first, and then, being enabled to build\\nthe stateful aspect of serverless on top of it. In this regard, we focus now on something that is that enabler and\\nperhaps one for other problems to solve.\\n\\nThis has been the work of ours lead by Adriano with help from Wesley and Elias; beside that I was able to participate a\\nbit in discussions and presenting our project a two occasions over the last year. I\'m looking forward to see Spawn\\ngrowing into something really cool, special and useful. There is still a lot of work ahead of us and we\'re very exited\\nto see how we can collaborate and grow as a project.\\n\\n## The Future of Eigr is based on Spawn\\n\\nWe are 100% focused on making Spawn a robust, scalable, dynamic and expandable platform, taking us far beyond what\\nwe imagined we were capable of in the initial Cloudstate project and with our previous implementation of Massa.\\nMassa has served us brilliantly as a means of experimentation, and now I feel deeply that we are ready to accomplish\\nwhatever we set out to do.\\n\\nWe invite everyone who is here to download and try Spawn and that we are ready to welcome those who want to contribute,\\nwhether with doubts, suggestions, a little code is also welcome, or a text review, any contribution is welcome. We\\ngreatly admire all of you who are interested in our project."},{"id":"current-status-of-the-project","metadata":{"permalink":"/blog/current-status-of-the-project","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2022-05-25-current-state-of-project.md","source":"@site/blog/2022-05-25-current-state-of-project.md","title":"May 2022 \u2013 Status of the Project","description":"My name is Adriano, I\'m a software engineer, I\'m 40 years old, I\'m Brazilian, and I\'ve been in the technology area for over 20 years on different fronts and having worked in a long list of companies, I\'m also the co-founder of the Eigr project together with @marcellanz and @guyso, previously the three of us were core members of the Cloudstate project and mainly worked on the supporting SDKs, but we also participated in the central development of Cloudstate technology and collaborated a lot on the development mainly of its protocol.","date":"2022-05-25T00:00:00.000Z","formattedDate":"May 25, 2022","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"cloudstate","permalink":"/blog/tags/cloudstate"},{"label":"eigr-functions","permalink":"/blog/tags/eigr-functions"},{"label":"project","permalink":"/blog/tags/project"},{"label":"status","permalink":"/blog/tags/status"}],"readingTime":4.075,"hasTruncateMarker":false,"authors":[{"name":"Adriano Santos","title":"eigr.io \u2013 Core Team","url":"https://github.com/sleipnir","imageURL":"https://avatars.githubusercontent.com/u/342502?v=4","key":"sleipnir"}],"frontMatter":{"slug":"current-status-of-the-project","title":"May 2022 \u2013 Status of the Project","authors":["sleipnir"],"tags":["serverless","cloudstate","eigr-functions","project","status"],"draft":false},"prevItem":{"title":"Hello Spawn! \u2013 The Actor Mesh","permalink":"/blog/spawn-the-actor-mesh"},"nextItem":{"title":"CodeBEAM Europe, Stockholm 2022","permalink":"/blog/codebeam-sto-2022"}},"content":"My name is Adriano, I\'m a software engineer, I\'m 40 years old, I\'m Brazilian, and I\'ve been in the technology area for over 20 years on different fronts and having worked in a long list of companies, I\'m also the co-founder of the Eigr project together with [@marcellanz](https://github.com/marcellanz) and [@guyso](https://github.com/ralphlaude), previously the three of us were core members of the [Cloudstate](https://cloudstate.io/) project and mainly worked on the supporting SDKs, but we also participated in the central development of Cloudstate technology and collaborated a lot on the development mainly of its protocol.\\n\\nI see that many of you have just arrived here and that\'s why I think it\'s important to give an overview of what we do and talk a little about the current status of the project.\\n\\nWell, let\'s go!\\n\\n## Overview:\\n\\nOur ecosystem is called Eigr, and we focus mainly on the following projects:\\n\\n* [Eigr Functions Controller](https://github.com/eigr/eigr-functions-controller): it\'s our deployment brain in Kubernetes, it controls the entire lifecycle of our sidecar along with user functions.\\n\\n* [Massa](https://github.com/eigr/massa): is a Sidecar Proxy and part of the _Eigr Functions_ offering that aims to \\n provide a high-level abstraction for General Purpose Stateful Serverless application development.\\n\\nMassa is responsible for managing the entire data access infrastructure for user functions, as well as other technical tasks such as providing the implementation of the user contract via [gRPC](https://grpc.io/) to the outside world, [transcoding HTTP requests to gRPC](https://cloud.google.com/endpoints/docs/grpc/transcoding), caching, making requests to external sources when requested and other tasks that would once have to be performed by the developer directly in his application.\\n\\nWith Massa the developer only has to worry about their domain objects and their user service interface via a \\ncontract-first declarative approach. These two components together form Eigr Functions.\\n\\nIn addition to these projects, we also work on several other R&D projects that allow us to understand certain parts \\nof the problem we are trying to solve and thus apply the acquired knowledge to the main projects. Research projects worth noting are the following:\\n\\n* [Falco](https://github.com/eigr/falco): A fork of the elixir-grpc project where we try to improve performance and provide a replacement for the original project that is not being updated by the community that created it. Its development continues in research status.\\n\\n* [Steinadler](https://github.com/eigr-labs/steinadler): A high-level alternative to Erlang Distribution. While we are aware of the incredible capabilities of the Erlang Distribution, we also know that there are numerous deficiencies in this protocol that we are trying to address. Its development is currently at a standstill.\\n\\n* [Spawn](https://github.com/eigr-labs/spawn): The **Actor Mesh Framework** is based on the [sidecar proxy pattern]\\n (https://dzone.com/articles/sidecar-design-pattern-in-your-microservices-ecosy-1) to provide the multi-language \\n Actor Model framework. Spawns\' technology-stack on top of the BEAM VM (the Erlang virtual machine) provides support \\n for different languages from its native Actor model. Spawn is made up of the following components:\\n\\n 1. A semantic protocol based on Protocol Buffers.\\n\\n 2. A Sidecar Proxy written in Elixir that implements this protocol as well as persistent storage adapters.\\n\\n 3. SDKs to support different programming languages.\\n\\n Spawn is currently in full development where its main parts will likely be incorporated into the core of Massa.\\n\\n* Astreu (https://github.com/eigr/Astreu): High-performance Messaging System based on a gRPC protocol written in \\n Elixir. Your development is on hold (usable for testing).\\n\\n:::info\\n\\nIn addition to these projects we have the Eigr Functions SDKs which are written in some programming languages \u200b\u200blike \\nElixir, Go, Java and others. Each of these projects is in different phases of development but none are yet readily \\nfunctional.\\n\\n:::\\n\\n## Eigr Functions!\\n\\nCurrently, the Massa project, where our greatest effort is concentrated, is capable of communicating with user \\nfunctions that implement the Cloudstate protocol in version 0.5 and is capable of dealing only with Action-type \\nentities, which are stateless entities.\\n\\nIn the next version of our proxy, we will probably no longer support the Cloudstate protocol because, once Cloudstate has been discontinued, we will adopt our own Protocol and entities.\\n\\nWe intend to support all the original project entity types, namely Action **a.k.a.** Stateless support, Event \\nSourcing, Value Entity (CRUD), and CRDTs ([Conflict Free Replicated Data Types](https://crdt.tech/)). We \\nwill just not bring the semantics of the previous protocol, and creating our own protocol to support these entities.\\n\\nSo we are in the process of a complete redesign of our protocol and therefore our proxy as well. We are doing this \\nwith proof of concepts in parallel projects and in project-specific branches within Massa.\\n\\nThis is a summary of what we have done and where we intend to go. I hope to be able to count on your \\ncollaboration in any way, with code, with good discussions, answering doubts, or just making small talk around [here](https://discord.gg/Y55eZpyvNs).\\n\\nI\'m curious to know a little more about you and what you expect from us.\\n\\nAh, I was forgetting, for those who want to know the reasons for the name Massa I suggest reading [here](https://github.com/eigr/massa/blob/main/FAQ.md).\\n\\nThanks for reading!"},{"id":"codebeam-sto-2022","metadata":{"permalink":"/blog/codebeam-sto-2022","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2022-05-19-codebeam-sto-2022.md","source":"@site/blog/2022-05-19-codebeam-sto-2022.md","title":"CodeBEAM Europe, Stockholm 2022","description":"We\'re excited to be selected","date":"2022-05-19T00:00:00.000Z","formattedDate":"May 19, 2022","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"eigr","permalink":"/blog/tags/eigr"}],"readingTime":0.655,"hasTruncateMarker":false,"authors":[{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"codebeam-sto-2022","title":"CodeBEAM Europe, Stockholm 2022","authors":["marcellanz"],"tags":["serverless","eigr"]},"prevItem":{"title":"May 2022 \u2013 Status of the Project","permalink":"/blog/current-status-of-the-project"},"nextItem":{"title":"ACM SIGPLAN, ICFP Erlang Workshop 2021","permalink":"/blog/acm-sigplan-ifcp-erlang-workshop-2021"}},"content":"We\'re excited to be selected\\nfor [one of the main talks](https://codesync.global/speaker/marcel-lanz/#947a-serverless-runtime-on-the-beam) at the\\nCodeBEAM Europe conference in Stockholm in May\\n2022 [CodeBEAM Europe](https://codesync.global/conferences/code-beam-sto-2022/).\\n\\n## Abstract\\n\\nServerless runtimes are often hidden in cloud providers offering and exposed solely by their programming API and\\ndeployment procedures. In this talk, we\'ll explore an open-source Serverless runtime built for the cloud and\\non-premises, running on the BEAM with a polyglot programming model to build general-purpose applications.\\n\\nIn this talk, we\'ll present how the BEAM and OTP are an ideal fit to build a Serverless runtime. After an introduction\\nabout Serverless and a polyglot programming model, we\'ll present the open-source project at eigr.io where we implemented\\nthe core of our runtime based on Erlang/OTP and written in Elixir.\\n\\n**Event:**\\nhttps://codesync.global/speaker/marcel-lanz/#947a-serverless-runtime-on-the-beam\\n\\n**\\nSlides:** [Slideshare](https://www.slideshare.net/MarcelLanz/v13eigrioaserverlessruntimeonthebeampptx/MarcelLanz/v13eigrioaserverlessruntimeonthebeampptx)\\n, [Google Slides](https://docs.google.com/presentation/d/1Km-zh2rItr-setoUJjJV9W43tNZVNJmQtXb3_va_vRQ/edit?usp=sharing)"},{"id":"acm-sigplan-ifcp-erlang-workshop-2021","metadata":{"permalink":"/blog/acm-sigplan-ifcp-erlang-workshop-2021","editUrl":"https://github.com/eigr/eigr.github.io/edit/main/website/blog/blog/2021-08-19-acm-sigplan-icfp-erlang-workshop-2021.md","source":"@site/blog/2021-08-19-acm-sigplan-icfp-erlang-workshop-2021.md","title":"ACM SIGPLAN, ICFP Erlang Workshop 2021","description":"We\'re excited to be selected","date":"2021-08-19T00:00:00.000Z","formattedDate":"August 19, 2021","tags":[{"label":"serverless","permalink":"/blog/tags/serverless"},{"label":"eigr","permalink":"/blog/tags/eigr"}],"readingTime":0.81,"hasTruncateMarker":false,"authors":[{"name":"Marcel Lanz","title":"eigr.io \u2013 Core Team","url":"https://github.com/marcellanz","imageURL":"https://avatars.githubusercontent.com/u/12616445?v=4","key":"marcellanz"}],"frontMatter":{"slug":"acm-sigplan-ifcp-erlang-workshop-2021","title":"ACM SIGPLAN, ICFP Erlang Workshop 2021","authors":["marcellanz"],"tags":["serverless","eigr"]},"prevItem":{"title":"CodeBEAM Europe, Stockholm 2022","permalink":"/blog/codebeam-sto-2022"}},"content":"We\'re excited to be selected\\nfor [one of the Lightning Talks](https://icfp21.sigplan.org/details/erlang-2021-papers/13/Lightning-Talk-eigr-io-A-Serverless-Runtime-on-the-BEAM)\\nright after the Erlang Keynote at the ACM\\nSIGPLAN, [ICFP Erlang Workshop 2021](https://icfp21.sigplan.org/home/erlang-2021).\\n\\n## Abstract\\n\\nServerless runtimes are often hidden in a cloud providers offering and exposed\\nsolely by their programming API and deployment procedures. In this talk, we\u2019ll\\nexplore an open-source Serverless runtime built for the cloud and on-premises,\\nrunning on the BEAM with a polyglot programming model to build general purpose\\napplications.\\n\\nBuilding general purpose applications using multiple languages and having a\\nstory how to handle state was our main motivation to explore the space of a\\nServerless runtime to be built. We think the BEAM, OTP and Elixir/Erlang are a\\nperfect match to build on.\\n\\nWith this talk, we combine herein the world of the BEAM with cloud technology\\nlike a gRPC-based protocol, Kubernetes and a polyglot programming model with\\nlanguages supported like Go, JavaScript, JVM-languages, Python and many more.\\n\\n**Event:**\\nhttps://icfp21.sigplan.org/details/erlang-2021-papers/13/Lightning-Talk-eigr-io-A-Serverless-Runtime-on-the-BEAM\\n\\n**\\nSlides:** [Slideshare](https://www.slideshare.net/MarcelLanz/eigrio-a-serverless-runtime-on-the-beam-acm-sigplan-icfp-2021-erlang-workshop)\\n, [Google Slides](https://docs.google.com/presentation/d/1mLmSFY0z6gxoG88-phcFTwyVBMv8R9myBA5MZOWoJso/edit#slide=id.p1)"}]}')}}]); \ No newline at end of file diff --git a/assets/js/main.b21a9018.js b/assets/js/main.6c06d1b1.js similarity index 98% rename from assets/js/main.b21a9018.js rename to assets/js/main.6c06d1b1.js index 4d10629..b291f7e 100644 --- a/assets/js/main.b21a9018.js +++ b/assets/js/main.6c06d1b1.js @@ -1,2 +1,2 @@ -/*! For license information please see main.b21a9018.js.LICENSE.txt */ -(self.webpackChunkeigr_io=self.webpackChunkeigr_io||[]).push([[179],{4334:function(e,t,n){"use strict";function r(e){var t,n,o="";if("string"==typeof e||"number"==typeof e)o+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t=d.reach);S+=E.value.length,E=E.next){var _=E.value;if(t.length>e.length)return;if(!(_ instanceof o)){var x,C=1;if(v){if(!(x=a(k,S,e,b))||x.index>=e.length)break;var T=x.index,A=x.index+x[0].length,L=S;for(L+=E.value.length;T>=L;)L+=(E=E.next).value.length;if(S=L-=E.value.length,E.value instanceof o)continue;for(var N=E;N!==t.tail&&(Ld.reach&&(d.reach=R);var M=E.prev;if(P&&(M=s(t,M,P),S+=P.length),u(t,M,C),E=s(t,M,new o(f,h?r.tokenize(O,h):O,y,O)),I&&s(t,E,I),C>1){var D={cause:f+","+g,reach:R};i(e,t,n,E.prev,S,D),d&&D.reach>d.reach&&(d.reach=D.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,o={value:n,prev:t,next:r};return t.next=o,r.prev=o,e.length++,o}function u(e,t,n){for(var r=t.next,o=0;o"+a.content+""},r}(),r=n;n.default=n,r.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},r.languages.markup.tag.inside["attr-value"].inside.entity=r.languages.markup.entity,r.languages.markup.doctype.inside["internal-subset"].inside=r.languages.markup,r.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(r.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:r.languages[t]},n.cdata=/^$/i;var o={"included-cdata":{pattern://i,inside:n}};o["language-"+t]={pattern:/[\s\S]+/,inside:r.languages[t]};var a={};a[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:o},r.languages.insertBefore("markup","cdata",a)}}),Object.defineProperty(r.languages.markup.tag,"addAttribute",{value:function(e,t){r.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:r.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),r.languages.html=r.languages.markup,r.languages.mathml=r.languages.markup,r.languages.svg=r.languages.markup,r.languages.xml=r.languages.extend("markup",{}),r.languages.ssml=r.languages.xml,r.languages.atom=r.languages.xml,r.languages.rss=r.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var o=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],a=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},r.languages.c=r.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),r.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),r.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},r.languages.c.string],char:r.languages.c.char,comment:r.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:r.languages.c}}}}),r.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete r.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(r),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(r),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},o={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:o,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:o})}(r),r.languages.javascript=r.languages.extend("clike",{"class-name":[r.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),r.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,r.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:r.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:r.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:r.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:r.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:r.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),r.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:r.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),r.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),r.languages.markup&&(r.languages.markup.tag.addInlined("script","javascript"),r.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),r.languages.js=r.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(r),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",o=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return"(?:"+o+"|"+a+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(a),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(r),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(//g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,o=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),a=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+o+a+"(?:"+o+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+o+a+")(?:"+o+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+o+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+o+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\b|\*\*(?:(?!\*)|\*(?:(?!\*))+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)|__(?:(?!_))+__)+_\b|\*(?:(?!\*)|\*\*(?:(?!\*))+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\]))+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(r),r.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:r.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},r.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n0)){var l=f(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s=0&&p(u,"variable-input")}}}}function c(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,o=r.inside["interpolation-punctuation"],a=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var o={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",o),o.tokens=e.tokenize(o.code,o.grammar),e.hooks.run("after-tokenize",o),o.tokens}function u(t){var n={};n["interpolation-punctuation"]=o;var a=e.tokenize(t,n);if(3===a.length){var i=[1,1];i.push.apply(i,s(a[1],e.languages.javascript,"javascript")),a.splice.apply(a,i)}return new e.Token("interpolation",a,r.alias,t)}function c(t,n,r){var o=e.tokenize(t,{interpolation:{pattern:RegExp(a),lookbehind:!0}}),i=0,c={},d=s(o.map((function(e){if("string"==typeof e)return e;for(var n,o=e.content;-1!==t.indexOf(n=l(i++,r)););return c[n]=o,n})).join(""),n,r),f=Object.keys(c);return i=0,function e(t){for(var n=0;n=f.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var o=f[i],a="string"==typeof r?r:r.content,l=a.indexOf(o);if(-1!==l){++i;var s=a.substring(0,l),d=u(c[o]),p=a.substring(l+o.length),g=[];if(s&&g.push(s),g.push(d),p){var m=[p];e(m),g.push.apply(g,m)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(g)),n+=g.length-1):r.content=g}}else{var h=r.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return"string"==typeof e?e:Array.isArray(e)?e.map(f).join(""):f(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,o=n.length;r]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(r),function(e){function t(e,t){return RegExp(e.replace(//g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:(?:\s*,\s*(?:\*\s*as\s+|\{[^{}]*\}))?|\*\s*as\s+|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r*\.{3}(?:[^{}]|)*\})/.source;function a(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return o})),RegExp(e,t)}o=a(o).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=a(/<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:a(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:a(/=/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},l=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===i(o.content[0].content[1])&&n.pop():"/>"===o.content[o.content.length-1].content||n.push({tagName:i(o.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===o.type&&"{"===o.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===o.type&&"}"===o.content?n[n.length-1].openedBraces--:a=!0),(a||"string"==typeof o)&&n.length>0&&0===n[n.length-1].openedBraces){var s=i(o);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=i(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}o.content&&"string"!=typeof o.content&&l(o.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(r),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],o=[];/^\w+$/.test(n)||o.push(/\w+/.exec(n)[0]),"diff"===n&&o.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:o,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(r),r.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},r.languages.go=r.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),r.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete r.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,l=i.length;-1!==n.code.indexOf(o=t(r,l));)++l;return i[l]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=a.length);s++){var u=l[s];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=a[o],d=n.tokenStack[c],f="string"==typeof u?u:u.content,p=t(r,c),g=f.indexOf(p);if(g>-1){++o;var m=f.substring(0,g),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=f.substring(g+p.length),v=[];m&&v.push.apply(v,i([m])),v.push(h),b&&v.push.apply(v,i([b])),"string"==typeof u?l.splice.apply(l,[s,1].concat(v)):u.content=v}}else u.content&&i(u.content)}return l}(n.tokens)}}}})}(r),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(r),r.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},r.languages.webmanifest=r.languages.json,r.languages.less=r.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),r.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),r.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},r.languages.objectivec=r.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete r.languages.objectivec["class-name"],r.languages.objc=r.languages.objectivec,r.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},r.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},r.languages.python["string-interpolation"].inside.interpolation.inside.rest=r.languages.python,r.languages.py=r.languages.python,r.languages.reason=r.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),r.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete r.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(r),r.languages.scss=r.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),r.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),r.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),r.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),r.languages.scss.atrule.inside.rest=r.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(r),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(r),r.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/},t.Z=r},7459:function(e,t,n){"use strict";function r(e){var t,n,o="";if("string"==typeof e||"number"==typeof e)o+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;tPromise.all([n.e(532),n.e(4013)]).then(n.bind(n,1223)),"@theme/BlogTagsListPage",1223],"09cf9139":[()=>n.e(3287).then(n.bind(n,2491)),"@site/blog/2023-12-03-distributed-elixir-made-easy.md?truncated=true",2491],"0d5331fe":[()=>n.e(4850).then(n.bind(n,7918)),"@site/docs/history.md",7918],"0d824db2":[()=>n.e(7204).then(n.bind(n,4389)),"@site/docs/projects-functions/tck/introdution.md",4389],"110403ef":[()=>n.e(3443).then(n.t.bind(n,5687,19)),"~blog/default/blog-tags-project-34b.json",5687],"14e2cbb9":[()=>n.e(6825).then(n.bind(n,9574)),"@site/docs/concepts/polyglot-programming.md",9574],"16a426e1":[()=>n.e(2974).then(n.bind(n,9982)),"@site/blog/2022-05-19-codebeam-sto-2022.md?truncated=true",9982],17896441:[()=>Promise.all([n.e(532),n.e(9588),n.e(7918)]).then(n.bind(n,9055)),"@theme/DocItem",9055],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1db64337":[()=>n.e(1372).then(n.bind(n,6777)),"@site/docs/overview.md",6777],"1f391b9e":[()=>Promise.all([n.e(532),n.e(9588),n.e(3085)]).then(n.bind(n,4247)),"@theme/MDXPage",4247],"29ef2733":[()=>n.e(2324).then(n.t.bind(n,3769,19)),"/home/runner/work/eigr.github.io/eigr.github.io/eigr_io/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],"2eef520d":[()=>n.e(515).then(n.bind(n,3659)),"@site/docs/projects-functions/sdk/go/event-sourcing.md",3659],"2f57cc6e":[()=>n.e(8561).then(n.t.bind(n,5745,19)),"/home/runner/work/eigr.github.io/eigr.github.io/eigr_io/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],"3680d81d":[()=>n.e(8003).then(n.bind(n,5004)),"@site/docs/projects-functions/sdk/go/replicated-data.md",5004],"393be207":[()=>n.e(7414).then(n.bind(n,3123)),"@site/src/pages/markdown-page.md",3123],"3ad5576f":[()=>n.e(4851).then(n.bind(n,9337)),"@site/protodocs/google/protobuf/any.proto.mdx",9337],"3b36d7b2":[()=>n.e(1138).then(n.bind(n,3533)),"@site/blog/2023-12-27-spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-erlang-beam-space.md?truncated=true",3533],"3cc51bd1":[()=>n.e(6272).then(n.t.bind(n,1952,19)),"~blog/default/blog-tags-cloudstate-510-list.json",1952],"3dd2979a":[()=>n.e(4183).then(n.t.bind(n,7293,19)),"~blog/default/blog-tags-spawn-d42-list.json",7293],"4b7e6199":[()=>n.e(9383).then(n.t.bind(n,7838,19)),"~blog/default/blog-tags-spawn-d42.json",7838],"4c071e48":[()=>n.e(1186).then(n.bind(n,2300)),"@site/protodocs/eigr/functions/protocol/actors/protocol.proto.mdx",2300],"4c79ca05":[()=>n.e(475).then(n.bind(n,6314)),"@site/blog/2023-12-27-spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-erlang-beam-space.md",6314],"5032377e":[()=>n.e(7679).then(n.bind(n,6356)),"@site/docs/projects-functions/eigr-functions.md",6356],54227455:[()=>n.e(5427).then(n.bind(n,6348)),"@site/protodocs/google/api/httpbody.proto.mdx",6348],"54626a35":[()=>n.e(3878).then(n.bind(n,6029)),"@site/blog/2021-08-19-acm-sigplan-icfp-erlang-workshop-2021.md?truncated=true",6029],"54eec65a":[()=>n.e(984).then(n.t.bind(n,3757,19)),"~blog/default/blog-tags-project-34b-list.json",3757],58002943:[()=>n.e(603).then(n.bind(n,6401)),"@site/blog/2023-05-10-beyond-monoliths-and-microservices.md?truncated=true",6401],"58b0fb08":[()=>n.e(1921).then(n.t.bind(n,418,19)),"~blog/default/blog-tags-durable-computing-aff-list.json",418],"58ec1ee1":[()=>n.e(7607).then(n.bind(n,6500)),"@site/docs/concepts/inversion-of-state.md",6500],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"5fa41df9":[()=>n.e(8463).then(n.bind(n,1019)),"@site/blog/2022-05-25-current-state-of-project.md",1019],"6017b094":[()=>n.e(1654).then(n.t.bind(n,1627,19)),"~blog/default/blog-tags-flame-c84-list.json",1627],"64b1a91c":[()=>n.e(387).then(n.bind(n,1887)),"@site/docs/projects-functions/sdk/go/getting-started.md",1887],"660669fe":[()=>n.e(1020).then(n.bind(n,6382)),"@site/blog/2022-05-19-codebeam-sto-2022.md",6382],"6875c492":[()=>Promise.all([n.e(532),n.e(9588),n.e(2529),n.e(8610)]).then(n.bind(n,1714)),"@theme/BlogTagsPostsPage",1714],"68f16e3f":[()=>n.e(5859).then(n.t.bind(n,9217,19)),"~blog/default/blog-tags-status-d5a.json",9217],"6b4c9811":[()=>n.e(2348).then(n.t.bind(n,6240,19)),"~blog/default/blog-tags-eigr-functions-be3-list.json",6240],"6b75d0a5":[()=>n.e(1428).then(n.t.bind(n,440,19)),"~blog/default/blog-tags-flame-c84.json",440],"6ceffbfc":[()=>n.e(781).then(n.t.bind(n,8822,19)),"~blog/default/blog-tags-elixir-8c7-list.json",8822],"6dde4f70":[()=>n.e(7537).then(n.t.bind(n,3974,19)),"~docs/protodocs/version-current-metadata-prop-751.json",3974],"6e31ee28":[()=>n.e(4776).then(n.t.bind(n,6202,19)),"~blog/default/blog-tags-durable-computing-aff.json",6202],"71b047c5":[()=>n.e(7290).then(n.bind(n,1654)),"@site/blog/2023-12-03-distributed-elixir-made-easy.md",1654],"76e0faff":[()=>n.e(6393).then(n.bind(n,5105)),"@site/docs/projects-functions/functions-protocol.md",5105],"7efc92b3":[()=>n.e(394).then(n.bind(n,6790)),"@site/docs/projects-other/eigr-astreu.md",6790],"814f3328":[()=>n.e(2535).then(n.t.bind(n,5641,19)),"~blog/default/blog-post-list-prop-default.json",5641],"8632f908":[()=>n.e(7515).then(n.bind(n,875)),"@site/protodocs/google/api/annotations.proto.mdx",875],"8b9f1315":[()=>n.e(9125).then(n.t.bind(n,876,19)),"~blog/default/blog-tags-distributed-111.json",876],"8d244af6":[()=>n.e(3154).then(n.bind(n,4053)),"@site/docs/projects-functions/sdk/go/serialization.md",4053],"8edf2aa3":[()=>n.e(7268).then(n.bind(n,9692)),"@site/blog/2022-09-08-spawn-the-actor-mesh.md",9692],"902b170a":[()=>n.e(8005).then(n.bind(n,3893)),"@site/docs/projects-functions/sdk/go/forwarding-and-effects.md",3893],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"9a990fcd":[()=>n.e(6573).then(n.t.bind(n,9920,19)),"~blog/default/blog-tags-design-6c6-list.json",9920],"9e4087bc":[()=>n.e(3608).then(n.bind(n,3169)),"@theme/BlogArchivePage",3169],"9f7423f8":[()=>n.e(6779).then(n.t.bind(n,4017,19)),"/home/runner/work/eigr.github.io/eigr.github.io/eigr_io/.docusaurus/docusaurus-plugin-content-docs/protodocs/plugin-route-context-module-100.json",4017],a032fedf:[()=>n.e(9799).then(n.t.bind(n,4469,19)),"/home/runner/work/eigr.github.io/eigr.github.io/eigr_io/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",4469],a0d50ef4:[()=>n.e(2626).then(n.t.bind(n,3525,19)),"~blog/default/blog-tags-architect-70c.json",3525],a2d4c66d:[()=>n.e(7540).then(n.bind(n,2383)),"@site/blog/2022-09-08-spawn-the-actor-mesh.md?truncated=true",2383],a555771a:[()=>n.e(2414).then(n.t.bind(n,8548,19)),"~blog/default/blog-tags-eigr-91a.json",8548],a6aa9e1f:[()=>Promise.all([n.e(532),n.e(9588),n.e(2529),n.e(3089)]).then(n.bind(n,46)),"@theme/BlogListPage",46],a7023ddc:[()=>n.e(1713).then(n.t.bind(n,3457,19)),"~blog/default/blog-tags-tags-4c2.json",3457],aa057471:[()=>n.e(1545).then(n.t.bind(n,7788,19)),"~blog/default/blog-tags-serverless-347-list.json",7788],b0bcc4ff:[()=>n.e(5786).then(n.t.bind(n,7044,19)),"~blog/default/blog-tags-elixir-8c7.json",7044],b2b675dd:[()=>n.e(533).then(n.t.bind(n,8017,19)),"~blog/default/blog-c06.json",8017],b2f554cd:[()=>n.e(1477).then(n.t.bind(n,10,19)),"~blog/default/blog-archive-80c.json",10],b8c0c4ce:[()=>n.e(5019).then(n.t.bind(n,1945,19)),"~blog/default/blog-tags-eigr-91a-list.json",1945],bbbf57c7:[()=>n.e(2144).then(n.bind(n,1760)),"@site/blog/2021-08-19-acm-sigplan-icfp-erlang-workshop-2021.md",1760],bd3c61ea:[()=>n.e(5421).then(n.bind(n,3472)),"@site/protodocs/google/api/http.proto.mdx",3472],c0fbda2a:[()=>n.e(4807).then(n.bind(n,9231)),"@site/docs/projects-functions/eigr-massa.md",9231],c4f5d8e4:[()=>Promise.all([n.e(532),n.e(4195)]).then(n.bind(n,6701)),"@site/src/pages/index.js",6701],c5402c84:[()=>n.e(8).then(n.bind(n,6907)),"@site/protodocs/eigr/functions/protocol/actors/actor.proto.mdx",6907],c5a6cc0b:[()=>n.e(1255).then(n.bind(n,1243)),"@site/docs/projects-functions/eigr-permastate.md",1243],c69469fc:[()=>n.e(480).then(n.t.bind(n,2845,19)),"~blog/default/blog-tags-cloudstate-510.json",2845],ccc49370:[()=>Promise.all([n.e(532),n.e(9588),n.e(2529),n.e(6103)]).then(n.bind(n,5203)),"@theme/BlogPostPage",5203],cfffd04c:[()=>n.e(2203).then(n.bind(n,7276)),"@site/docs/concepts/service-proxy.md",7276],da5a731f:[()=>n.e(3813).then(n.t.bind(n,5358,19)),"~blog/default/blog-tags-architect-70c-list.json",5358],dd242a65:[()=>n.e(1399).then(n.bind(n,7016)),"@site/docs/projects-functions/sdk/go/api-docs.md",7016],e012cda3:[()=>n.e(5603).then(n.t.bind(n,8546,19)),"~blog/default/blog-tags-eigr-functions-be3.json",8546],e0d830a9:[()=>n.e(5142).then(n.bind(n,3001)),"@site/blog/2023-05-10-beyond-monoliths-and-microservices.md",3001],e1911bb1:[()=>n.e(6457).then(n.t.bind(n,4603,19)),"~blog/default/blog-tags-status-d5a-list.json",4603],e98d5b44:[()=>n.e(7960).then(n.t.bind(n,5502,19)),"~blog/default/blog-tags-serverless-347.json",5502],eb04623a:[()=>n.e(362).then(n.t.bind(n,5978,19)),"~blog/default/blog-tags-distributed-111-list.json",5978],ed8d3277:[()=>n.e(7301).then(n.bind(n,8442)),"@site/docs/projects-spawn/spawn-introduction.md",8442],f358f7a4:[()=>n.e(1782).then(n.bind(n,6061)),"@site/blog/2022-05-25-current-state-of-project.md?truncated=true",6061],f3effa1d:[()=>n.e(4).then(n.bind(n,3341)),"@site/docs/projects-functions/functions-operator.md",3341],f9d73fb9:[()=>n.e(4139).then(n.bind(n,820)),"@site/docs/concepts/the-actor-mesh.md",820],fbf59bd9:[()=>n.e(5203).then(n.bind(n,8923)),"@site/docs/projects-functions/tck/cloudstate-tck.md",8923],fdb5e17a:[()=>n.e(3840).then(n.t.bind(n,1674,19)),"~blog/default/blog-tags-design-6c6.json",1674]};function u(e){let{error:t,retry:n,pastDelay:o}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):o?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var c=n(9670),d=n(226);function f(e,t){if("*"===e)return i()({loading:u,loader:()=>n.e(4972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const a=l[e+"-"+t],f={},p=[],g=[],m=(0,c.Z)(a);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=s[n];r&&(f[t]=r[0],p.push(r[1]),g.push(r[2]))})),i().Map({loading:u,loader:f,modules:p,webpack:()=>g,render(t,n){const i=JSON.parse(JSON.stringify(a));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error("The page component at "+e+" doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.");"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let a=i;const l=n.split(".");l.slice(0,-1).forEach((e=>{a=a[e]})),a[l[l.length-1]]=o}));const l=i.__comp;delete i.__comp;const s=i.__context;return delete i.__context,r.createElement(d.z,{value:s},r.createElement(l,(0,o.Z)({},i,n)))}})}var p=[{path:"/blog/",component:f("/blog/","c1e"),exact:!0},{path:"/blog/acm-sigplan-ifcp-erlang-workshop-2021/",component:f("/blog/acm-sigplan-ifcp-erlang-workshop-2021/","9a5"),exact:!0},{path:"/blog/archive/",component:f("/blog/archive/","f15"),exact:!0},{path:"/blog/beyond-monoliths-and-microservices/",component:f("/blog/beyond-monoliths-and-microservices/","07b"),exact:!0},{path:"/blog/codebeam-sto-2022/",component:f("/blog/codebeam-sto-2022/","93e"),exact:!0},{path:"/blog/current-status-of-the-project/",component:f("/blog/current-status-of-the-project/","3f4"),exact:!0},{path:"/blog/distributed-elixir-made-easy-with-spawn/",component:f("/blog/distributed-elixir-made-easy-with-spawn/","dc8"),exact:!0},{path:"/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space/",component:f("/blog/spawn-and-flame-a-symphony-of-Innovation-in-the-serverless-beam-space/","468"),exact:!0},{path:"/blog/spawn-the-actor-mesh/",component:f("/blog/spawn-the-actor-mesh/","0e1"),exact:!0},{path:"/blog/tags/",component:f("/blog/tags/","e1f"),exact:!0},{path:"/blog/tags/architect/",component:f("/blog/tags/architect/","44d"),exact:!0},{path:"/blog/tags/cloudstate/",component:f("/blog/tags/cloudstate/","3cf"),exact:!0},{path:"/blog/tags/design/",component:f("/blog/tags/design/","bde"),exact:!0},{path:"/blog/tags/distributed/",component:f("/blog/tags/distributed/","1f1"),exact:!0},{path:"/blog/tags/durable-computing/",component:f("/blog/tags/durable-computing/","264"),exact:!0},{path:"/blog/tags/eigr-functions/",component:f("/blog/tags/eigr-functions/","cd6"),exact:!0},{path:"/blog/tags/eigr/",component:f("/blog/tags/eigr/","3ef"),exact:!0},{path:"/blog/tags/elixir/",component:f("/blog/tags/elixir/","188"),exact:!0},{path:"/blog/tags/flame/",component:f("/blog/tags/flame/","b24"),exact:!0},{path:"/blog/tags/project/",component:f("/blog/tags/project/","c27"),exact:!0},{path:"/blog/tags/serverless/",component:f("/blog/tags/serverless/","719"),exact:!0},{path:"/blog/tags/spawn/",component:f("/blog/tags/spawn/","4c8"),exact:!0},{path:"/blog/tags/status/",component:f("/blog/tags/status/","edd"),exact:!0},{path:"/markdown-page/",component:f("/markdown-page/","751"),exact:!0},{path:"/docs/",component:f("/docs/","3f3"),routes:[{path:"/docs/concepts/inversion-of-state/",component:f("/docs/concepts/inversion-of-state/","13e"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/concepts/polyglot-programming/",component:f("/docs/concepts/polyglot-programming/","d38"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/concepts/service-proxy/",component:f("/docs/concepts/service-proxy/","6b7"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/concepts/the-actor-mesh/",component:f("/docs/concepts/the-actor-mesh/","cd4"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/history/",component:f("/docs/history/","649"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/overview/",component:f("/docs/overview/","52a"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/eigr-functions/",component:f("/docs/projects-functions/eigr-functions/","264"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/eigr-massa/",component:f("/docs/projects-functions/eigr-massa/","e41"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/eigr-permastate/",component:f("/docs/projects-functions/eigr-permastate/","a6a"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/functions-operator/",component:f("/docs/projects-functions/functions-operator/","3bf"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/functions-protocol/",component:f("/docs/projects-functions/functions-protocol/","3ed"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/sdk/go/api-docs/",component:f("/docs/projects-functions/sdk/go/api-docs/","f1f"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/sdk/go/event-sourcing/",component:f("/docs/projects-functions/sdk/go/event-sourcing/","6ed"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/sdk/go/forwarding-and-effects/",component:f("/docs/projects-functions/sdk/go/forwarding-and-effects/","e76"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/sdk/go/getting-started/",component:f("/docs/projects-functions/sdk/go/getting-started/","bab"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/sdk/go/replicated-data/",component:f("/docs/projects-functions/sdk/go/replicated-data/","360"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/sdk/go/serialization/",component:f("/docs/projects-functions/sdk/go/serialization/","f44"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/tck/cloudstate-tck/",component:f("/docs/projects-functions/tck/cloudstate-tck/","457"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-functions/tck/introdution/",component:f("/docs/projects-functions/tck/introdution/","df9"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-other/eigr-astreu/",component:f("/docs/projects-other/eigr-astreu/","753"),exact:!0,sidebar:"eigrSidebar"},{path:"/docs/projects-spawn/spawn-introduction/",component:f("/docs/projects-spawn/spawn-introduction/","082"),exact:!0,sidebar:"eigrSidebar"}]},{path:"/protodocs/",component:f("/protodocs/","0ea"),routes:[{path:"/protodocs/eigr/functions/protocol/actors/actor.proto/",component:f("/protodocs/eigr/functions/protocol/actors/actor.proto/","d25"),exact:!0,sidebar:"protodocs"},{path:"/protodocs/eigr/functions/protocol/actors/protocol.proto/",component:f("/protodocs/eigr/functions/protocol/actors/protocol.proto/","c19"),exact:!0,sidebar:"protodocs"},{path:"/protodocs/google/api/annotations.proto/",component:f("/protodocs/google/api/annotations.proto/","c40"),exact:!0},{path:"/protodocs/google/api/http.proto/",component:f("/protodocs/google/api/http.proto/","2dc"),exact:!0},{path:"/protodocs/google/api/httpbody.proto/",component:f("/protodocs/google/api/httpbody.proto/","c1e"),exact:!0},{path:"/protodocs/google/protobuf/any.proto/",component:f("/protodocs/google/protobuf/any.proto/","e54"),exact:!0,sidebar:"protodocs"}]},{path:"/",component:f("/","337"),exact:!0},{path:"*",component:f("*")}]},8934:function(e,t,n){"use strict";n.d(t,{_:function(){return o},t:function(){return a}});var r=n(7294);const o=r.createContext(!1);function a(e){let{children:t}=e;const[n,a]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{a(!0)}),[]),r.createElement(o.Provider,{value:n},t)}},9383:function(e,t,n){"use strict";var r=n(7294),o=n(3935),a=n(3727),i=n(405),l=n(412),s=[n(2497),n(3310),n(8320),n(2295)],u=n(723),c=n(6775),d=n(8790);function f(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var p=n(3117),g=n(5742),m=n(2263),h=n(4996),b=n(6668),v=n(1944),y=n(4711),w=n(9727),k=n(3320),E=n(197);function S(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,m.Z)(),n=(0,y.l)();return r.createElement(g.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:o}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:o})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,m.Z)(),o=function(){const{siteConfig:{url:e}}=(0,m.Z)(),{pathname:t}=(0,c.TH)();return e+(0,h.Z)(t)}(),a=t?""+n+t:o;return r.createElement(g.Z,null,r.createElement("meta",{property:"og:url",content:a}),r.createElement("link",{rel:"canonical",href:a}))}function x(){const{i18n:{currentLocale:e}}=(0,m.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(g.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(v.d,{image:n}),r.createElement(_,null),r.createElement(S,null),r.createElement(E.Z,{tag:k.HX,locale:e}),r.createElement(g.Z,null,t.map(((e,t)=>r.createElement("meta",(0,p.Z)({key:t},e))))))}const C=new Map;function T(e){if(C.has(e.pathname))return{...e,pathname:C.get(e.pathname)};if((0,d.f)(u.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return C.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return C.set(e.pathname,t),{...e,pathname:t}}var A=n(8934),L=n(8940);function N(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{var r,o;const a=null!=(r=null==(o=t.default)?void 0:o[e])?r:t[e];return null==a?void 0:a(...n)}));return()=>o.forEach((e=>null==e?void 0:e()))}var O=function(e){let{children:t,location:n,previousLocation:o}=e;return(0,r.useLayoutEffect)((()=>{o!==n&&(o&&function(e){const{hash:t}=e;if(t){const e=decodeURIComponent(t.substring(1)),n=document.getElementById(e);null==n||n.scrollIntoView()}else window.scrollTo(0,0)}(n),N("onRouteDidUpdate",{previousLocation:o,location:n}))}),[o,n]),t};function P(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(u.Z,e))).flat();return Promise.all(t.map((e=>null==e.route.component.preload?void 0:e.route.component.preload())))}class I extends r.Component{constructor(e){super(e),this.previousLocation=void 0,this.routeUpdateCleanupCb=void 0,this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?N("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=N("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),P(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(O,{previousLocation:this.previousLocation,location:t},r.createElement(c.AW,{location:t,render:()=>e}))}}var R=I;const M="docusaurus-base-url-issue-banner-container",D="docusaurus-base-url-issue-banner-suggestion-container",j="__DOCUSAURUS_INSERT_BASEURL_BANNER";function F(e){return"\nwindow['"+j+"'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['"+j+"'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('"+M+"');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = "+JSON.stringify(function(e){return'\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = '+e+" "+("/"===e?" (default value)":"")+'

\n

We suggest trying baseUrl =

\n
\n'}(e)).replace(/{window[j]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(g.Z,null,r.createElement("script",null,F(e))),r.createElement("div",{id:M}))}function z(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,m.Z)(),{pathname:n}=(0,c.TH)();return t&&n===e?r.createElement(B,null):null}function U(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:o,localeConfigs:a}}=(0,m.Z)(),i=(0,h.Z)(e),{htmlLang:l,direction:s}=a[o];return r.createElement(g.Z,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var $=n(4763);function Z(){const e=(0,d.H)(u.Z),t=(0,c.TH)();return r.createElement($.Z,null,r.createElement(L.M,null,r.createElement(A.t,null,r.createElement(f,null,r.createElement(U,null),r.createElement(x,null),r.createElement(z,null),r.createElement(R,{location:T(t)},e)))))}var H=n(6887);const V=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{var r,o;if("undefined"==typeof document)return void n();const a=document.createElement("link");a.setAttribute("rel","prefetch"),a.setAttribute("href",e),a.onload=()=>t(),a.onerror=()=>n();const i=null!=(r=document.getElementsByTagName("head")[0])?r:null==(o=document.getElementsByName("script")[0])?void 0:o.parentNode;null==i||i.appendChild(a)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var W=n(9670);const G=new Set,q=new Set,Y=()=>{var e,t;return(null==(e=navigator.connection)?void 0:e.effectiveType.includes("2g"))||(null==(t=navigator.connection)?void 0:t.saveData)},K={prefetch(e){if(!(e=>!Y()&&!q.has(e)&&!G.has(e))(e))return!1;G.add(e);const t=(0,d.f)(u.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(H).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,W.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?V(t).catch((()=>{})):Promise.resolve()})))},preload(e){return!!(e=>!Y()&&!q.has(e))(e)&&(q.add(e),P(e))}};var X=Object.freeze(K);if(l.Z.canUseDOM){window.docusaurus=X;const e=o.hydrate;P(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(a.VK,null,r.createElement(Z,null))),document.getElementById("__docusaurus"))}))}},8940:function(e,t,n){"use strict";n.d(t,{_:function(){return c},M:function(){return d}});var r=n(7294),o=n(6809),a=JSON.parse('{"docusaurus-plugin-content-docs":{"protodocs":{"path":"/protodocs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/protodocs","mainDocId":"eigr/functions/protocol/actors/actor.proto","docs":[{"id":"eigr/functions/protocol/actors/actor.proto","path":"/protodocs/eigr/functions/protocol/actors/actor.proto","sidebar":"protodocs"},{"id":"eigr/functions/protocol/actors/protocol.proto","path":"/protodocs/eigr/functions/protocol/actors/protocol.proto","sidebar":"protodocs"},{"id":"google/api/annotations.proto","path":"/protodocs/google/api/annotations.proto"},{"id":"google/api/http.proto","path":"/protodocs/google/api/http.proto"},{"id":"google/api/httpbody.proto","path":"/protodocs/google/api/httpbody.proto"},{"id":"google/protobuf/any.proto","path":"/protodocs/google/protobuf/any.proto","sidebar":"protodocs"}],"draftIds":[],"sidebars":{"protodocs":{"link":{"path":"/protodocs/eigr/functions/protocol/actors/actor.proto","label":"eigr/functions/protocol/actors/actor.proto"}}}}],"breadcrumbs":true},"default":{"path":"/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/docs","mainDocId":"overview","docs":[{"id":"concepts/inversion-of-state","path":"/docs/concepts/inversion-of-state","sidebar":"eigrSidebar"},{"id":"concepts/polyglot-programming","path":"/docs/concepts/polyglot-programming","sidebar":"eigrSidebar"},{"id":"concepts/service-proxy","path":"/docs/concepts/service-proxy","sidebar":"eigrSidebar"},{"id":"concepts/the-actor-mesh","path":"/docs/concepts/the-actor-mesh","sidebar":"eigrSidebar"},{"id":"history","path":"/docs/history","sidebar":"eigrSidebar"},{"id":"overview","path":"/docs/overview","sidebar":"eigrSidebar"},{"id":"projects-functions/eigr-functions","path":"/docs/projects-functions/eigr-functions","sidebar":"eigrSidebar"},{"id":"projects-functions/eigr-massa","path":"/docs/projects-functions/eigr-massa","sidebar":"eigrSidebar"},{"id":"projects-functions/eigr-permastate","path":"/docs/projects-functions/eigr-permastate","sidebar":"eigrSidebar"},{"id":"projects-functions/functions-operator","path":"/docs/projects-functions/functions-operator","sidebar":"eigrSidebar"},{"id":"projects-functions/functions-protocol","path":"/docs/projects-functions/functions-protocol","sidebar":"eigrSidebar"},{"id":"projects-functions/sdk/go/api-docs","path":"/docs/projects-functions/sdk/go/api-docs","sidebar":"eigrSidebar"},{"id":"projects-functions/sdk/go/event-sourcing","path":"/docs/projects-functions/sdk/go/event-sourcing","sidebar":"eigrSidebar"},{"id":"projects-functions/sdk/go/forwarding-and-effects","path":"/docs/projects-functions/sdk/go/forwarding-and-effects","sidebar":"eigrSidebar"},{"id":"projects-functions/sdk/go/getting-started","path":"/docs/projects-functions/sdk/go/getting-started","sidebar":"eigrSidebar"},{"id":"projects-functions/sdk/go/replicated-data","path":"/docs/projects-functions/sdk/go/replicated-data","sidebar":"eigrSidebar"},{"id":"projects-functions/sdk/go/serialization","path":"/docs/projects-functions/sdk/go/serialization","sidebar":"eigrSidebar"},{"id":"projects-functions/tck/cloudstate-tck","path":"/docs/projects-functions/tck/cloudstate-tck","sidebar":"eigrSidebar"},{"id":"projects-functions/tck/introdution","path":"/docs/projects-functions/tck/introdution","sidebar":"eigrSidebar"},{"id":"projects-other/eigr-astreu","path":"/docs/projects-other/eigr-astreu","sidebar":"eigrSidebar"},{"id":"projects-spawn/spawn-introduction","path":"/docs/projects-spawn/spawn-introduction","sidebar":"eigrSidebar"}],"draftIds":[],"sidebars":{"eigrSidebar":{"link":{"path":"/docs/overview","label":"overview"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}'),l=n(7529),s=JSON.parse('{"docusaurusVersion":"2.1.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.1.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.1.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.1.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.1.0"},"docusaurus-protobuffet-plugin":{"type":"package","name":"docusaurus-protobuffet-plugin","version":"0.3.2"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.1.0"}}}');const u={siteConfig:o.default,siteMetadata:s,globalData:a,i18n:i,codeTranslations:l},c=r.createContext(u);function d(e){let{children:t}=e;return r.createElement(c.Provider,{value:u},t)}},4763:function(e,t,n){"use strict";n.d(t,{Z:function(){return c}});var r=n(7294),o=n(412),a=n(5742),i=n(215);function l(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",height:"50vh",width:"100%",fontSize:"20px"}},r.createElement("h1",null,"This page crashed."),r.createElement("p",null,t.message),r.createElement("button",{type:"button",onClick:n},"Try again"))}function s(e){let{error:t,tryAgain:n}=e;return r.createElement(c,{fallback:()=>r.createElement(l,{error:t,tryAgain:n})},r.createElement(a.Z,null,r.createElement("title",null,"Page Error")),r.createElement(i.Z,null,r.createElement(l,{error:t,tryAgain:n})))}const u=e=>r.createElement(s,e);class c extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){o.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){var n;const e={error:t,tryAgain:()=>this.setState({error:null})};return(null!=(n=this.props.fallback)?n:u)(e)}return null!=e?e:null}}},412:function(e,t){"use strict";const n="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,r={canUseDOM:n,canUseEventListeners:n&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:n&&"IntersectionObserver"in window,canUseViewport:n&&"screen"in window};t.Z=r},5742:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(7294),o=n(405);function a(e){return r.createElement(o.ql,e)}},9960:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return p}});var r=n(3117),o=n(7294),a=n(3727),i=n(8780),l=n(2263),s=n(3919),u=n(412);const c=o.createContext({collectLink:()=>{}});var d=n(4996);function f(e,t){var n,f;let{isNavLink:p,to:g,href:m,activeClassName:h,isActive:b,"data-noBrokenLinkCheck":v,autoAddBaseUrl:y=!0,...w}=e;const{siteConfig:{trailingSlash:k,baseUrl:E}}=(0,l.Z)(),{withBaseUrl:S}=(0,d.C)(),_=(0,o.useContext)(c),x=(0,o.useRef)(null);(0,o.useImperativeHandle)(t,(()=>x.current));const C=g||m;const T=(0,s.Z)(C),A=null==C?void 0:C.replace("pathname://","");let L=void 0!==A?(N=A,y&&(e=>e.startsWith("/"))(N)?S(N):N):void 0;var N;L&&T&&(L=(0,i.applyTrailingSlash)(L,{trailingSlash:k,baseUrl:E}));const O=(0,o.useRef)(!1),P=p?a.OL:a.rU,I=u.Z.canUseIntersectionObserver,R=(0,o.useRef)();(0,o.useEffect)((()=>(!I&&T&&null!=L&&window.docusaurus.prefetch(L),()=>{I&&R.current&&R.current.disconnect()})),[R,L,I,T]);const M=null!=(n=null==(f=L)?void 0:f.startsWith("#"))&&n,D=!L||!T||M;return D||v||_.collectLink(L),D?o.createElement("a",(0,r.Z)({ref:x,href:L},C&&!T&&{target:"_blank",rel:"noopener noreferrer"},w)):o.createElement(P,(0,r.Z)({},w,{onMouseEnter:()=>{O.current||null==L||(window.docusaurus.preload(L),O.current=!0)},innerRef:e=>{x.current=e,I&&e&&T&&(R.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(R.current.unobserve(e),R.current.disconnect(),null!=L&&window.docusaurus.prefetch(L))}))})),R.current.observe(e))},to:L},p&&{isActive:b,activeClassName:h}))}var p=o.forwardRef(f)},5999:function(e,t,n){"use strict";n.d(t,{Z:function(){return s},I:function(){return l}});var r=n(7294);function o(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=null==t?void 0:t[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var a=n(7529);function i(e){var t,n;let{id:r,message:o}=e;if(void 0===r&&void 0===o)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return null!=(t=null!=(n=a[null!=r?r:o])?n:o)?t:r}function l(e,t){let{message:n,id:r}=e;return o(i({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:a}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const l=i({message:t,id:n});return r.createElement(r.Fragment,null,o(l,a))}},9935:function(e,t,n){"use strict";n.d(t,{m:function(){return r}});const r="default"},3919:function(e,t,n){"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function o(e){return void 0!==e&&!r(e)}n.d(t,{Z:function(){return o},b:function(){return r}})},4996:function(e,t,n){"use strict";n.d(t,{C:function(){return a},Z:function(){return i}});var r=n(2263),o=n(3919);function a(){const{siteConfig:{baseUrl:e,url:t}}=(0,r.Z)();return{withBaseUrl:(n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)}}function i(e,t){void 0===t&&(t={});const{withBaseUrl:n}=a();return n(e,t)}},2263:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(7294),o=n(8940);function a(){return(0,r.useContext)(o._)}},2389:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(7294),o=n(8934);function a(){return(0,r.useContext)(o._)}},9670:function(e,t,n){"use strict";n.d(t,{Z:function(){return r}});function r(e){const t={};return function e(n,r){Object.entries(n).forEach((n=>{let[o,a]=n;const i=r?r+"."+o:o;var l;"object"==typeof(l=a)&&l&&Object.keys(l).length>0?e(a,i):t[i]=a}))}(e),t}},226:function(e,t,n){"use strict";n.d(t,{_:function(){return o},z:function(){return a}});var r=n(7294);const o=r.createContext(null);function a(e){let{children:t,value:n}=e;const a=r.useContext(o),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...null==n?void 0:n.data};return{plugin:t.plugin,data:r}}({parent:a,value:n})),[a,n]);return r.createElement(o.Provider,{value:i},t)}},143:function(e,t,n){"use strict";n.d(t,{Iw:function(){return m},gA:function(){return f},_r:function(){return c},Jo:function(){return h},zh:function(){return d},yW:function(){return g},gB:function(){return p}});var r=n(6775),o=n(2263),a=n(9935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,o.Z)();return e}()[e];if(!n&&t.failfast)throw new Error('Docusaurus plugin global data not found for "'+e+'" plugin.');return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=function(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),o=null==n?void 0:n.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:o,alternateDocVersions:o?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(o.id):{}}}const u={},c=()=>{var e;return null!=(e=i("docusaurus-plugin-content-docs"))?e:u},d=e=>function(e,t,n){void 0===t&&(t=a.m),void 0===n&&(n={});const r=i(e),o=null==r?void 0:r[t];if(!o&&n.failfast)throw new Error('Docusaurus plugin global data not found for "'+e+'" plugin with id "'+t+'".');return o}("docusaurus-plugin-content-docs",e,{failfast:!0});function f(e){void 0===e&&(e={});const t=c(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const o=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),a=o?{pluginId:o[0],pluginData:o[1]}:void 0;if(!a&&n.failfast)throw new Error("Can't find active docs plugin for \""+t+'" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: '+Object.values(e).map((e=>e.path)).join(", "));return a}(t,n,e)}function p(e){return d(e).versions}function g(e){const t=d(e);return l(t)}function m(e){const t=d(e),{pathname:n}=(0,r.TH)();return s(t,n)}function h(e){const t=d(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:function(e,t,n){"use strict";n.r(t);var r=n(4865),o=n.n(r);o().configure({showSpinner:!1});const a={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{o().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){o().done()}};t.default=a},3310:function(e,t,n){"use strict";n.r(t);var r=n(1205),o=n(6809);!function(e){const{themeConfig:{prism:t}}=o.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(1247)("./prism-"+e)})),delete globalThis.Prism}(r.Z)},9471:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(7294),o="iconExternalLink_nPIU";function a(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:o},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},215:function(e,t,n){"use strict";n.d(t,{Z:function(){return lt}});var r=n(7294),o=n(4334),a=n(4763),i=n(1944),l=n(5281),s=n(9727),u=n(5999),c=n(6775),d=n(5936);function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}var p="skipToContent_fXgn";function g(){const{containerRef:e,handleSkip:t}=function(){const e=(0,r.useRef)(null),{action:t}=(0,c.k6)(),n=(0,r.useCallback)((e=>{var t;e.preventDefault();const n=null!=(t=document.querySelector("main:first-of-type"))?t:document.querySelector("."+l.k.wrapper.main);n&&f(n)}),[]);return(0,d.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,handleSkip:n}}();return r.createElement("div",{ref:e,role:"region","aria-label":(0,u.I)({id:"theme.common.skipToMainContent"})},r.createElement("a",{href:"#",className:p,onClick:t},r.createElement(u.Z,{id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"},"Skip to main content")))}var m=n(6668),h=n(9689),b=n(3117);function v(e){let{width:t=21,height:n=21,color:o="currentColor",strokeWidth:a=1.2,className:i,...l}=e;return r.createElement("svg",(0,b.Z)({viewBox:"0 0 15 15",width:t,height:n},l),r.createElement("g",{stroke:o,strokeWidth:a},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}var y="closeButton_CVFx";function w(e){return r.createElement("button",(0,b.Z)({type:"button","aria-label":(0,u.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,o.Z)("clean-btn close",y,e.className)}),r.createElement(v,{width:14,height:14,strokeWidth:3.1}))}var k="content_knG7";function E(e){const{announcementBar:t}=(0,m.L)(),{content:n}=t;return r.createElement("div",(0,b.Z)({},e,{className:(0,o.Z)(k,e.className),dangerouslySetInnerHTML:{__html:n}}))}var S="announcementBar_mb4j",_="announcementBarPlaceholder_vyr4",x="announcementBarClose_gvF7",C="announcementBarContent_xLdY";function T(){const{announcementBar:e}=(0,m.L)(),{isActive:t,close:n}=(0,h.nT)();if(!t)return null;const{backgroundColor:o,textColor:a,isCloseable:i}=e;return r.createElement("div",{className:S,style:{backgroundColor:o,color:a},role:"banner"},i&&r.createElement("div",{className:_}),r.createElement(E,{className:C}),i&&r.createElement(w,{onClick:n,className:x}))}var A=n(2961),L=n(2466);var N=n(902),O=n(3102);const P=r.createContext(null);function I(e){let{children:t}=e;const n=function(){const e=(0,A.e)(),t=(0,O.HY)(),[n,o]=(0,r.useState)(!1),a=null!==t.component,i=(0,N.D9)(a);return(0,r.useEffect)((()=>{a&&!i&&o(!0)}),[a,i]),(0,r.useEffect)((()=>{a?e.shown||o(!0):o(!1)}),[e.shown,a]),(0,r.useMemo)((()=>[n,o]),[n])}();return r.createElement(P.Provider,{value:n},t)}function R(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(P);if(!e)throw new N.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,o=(0,r.useCallback)((()=>n(!1)),[n]),a=(0,O.HY)();return(0,r.useMemo)((()=>({shown:t,hide:o,content:R(a)})),[o,a,t])}function D(e){let{header:t,primaryMenu:n,secondaryMenu:a}=e;const{shown:i}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,o.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},a)))}var j=n(2949),F=n(2389);function B(e){return r.createElement("svg",(0,b.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function z(e){return r.createElement("svg",(0,b.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}var U={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function $(e){let{className:t,value:n,onChange:a}=e;const i=(0,F.Z)(),l=(0,u.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===n?(0,u.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,u.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,o.Z)(U.toggle,t)},r.createElement("button",{className:(0,o.Z)("clean-btn",U.toggleButton,!i&&U.toggleButtonDisabled),type:"button",onClick:()=>a("dark"===n?"light":"dark"),disabled:!i,title:l,"aria-label":l},r.createElement(B,{className:(0,o.Z)(U.toggleIcon,U.lightToggleIcon)}),r.createElement(z,{className:(0,o.Z)(U.toggleIcon,U.darkToggleIcon)})))}var Z=r.memo($);function H(e){let{className:t}=e;const n=(0,m.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:a}=(0,j.I)();return n?null:r.createElement(Z,{className:t,value:o,onChange:a})}var V=n(1327);function W(){return r.createElement(V.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function G(){const e=(0,A.e)();return r.createElement("button",{type:"button",className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(v,{color:"var(--ifm-color-emphasis-600)"}))}function q(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(W,null),r.createElement(H,{className:"margin-right--md"}),r.createElement(G,null))}var Y=n(9960),K=n(4996),X=n(3919);function Q(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var J=n(9471);function ee(e){let{activeBasePath:t,activeBaseRegex:n,to:o,href:a,label:i,html:l,isDropdownLink:s,prependBaseUrlToHref:u,...c}=e;const d=(0,K.Z)(o),f=(0,K.Z)(t),p=(0,K.Z)(a,{forcePrependBaseUrl:!0}),g=i&&a&&!(0,X.Z)(a),m=l?{dangerouslySetInnerHTML:{__html:l}}:{children:r.createElement(r.Fragment,null,i,g&&r.createElement(J.Z,s&&{width:12,height:12}))};return a?r.createElement(Y.default,(0,b.Z)({href:u?p:a},c,m)):r.createElement(Y.default,(0,b.Z)({to:d,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?Q(n,t.pathname):t.pathname.startsWith(f)},c,m))}function te(e){let{className:t,isDropdownItem:n=!1,...a}=e;const i=r.createElement(ee,(0,b.Z)({className:(0,o.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},a));return n?r.createElement("li",null,i):i}function ne(e){let{className:t,isDropdownItem:n,...a}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ee,(0,b.Z)({className:(0,o.Z)("menu__link",t)},a)))}function re(e){var t;let{mobile:n=!1,position:o,...a}=e;const i=n?ne:te;return r.createElement(i,(0,b.Z)({},a,{activeClassName:null!=(t=a.activeClassName)?t:n?"menu__link--active":"navbar__link--active"}))}var oe=n(6043),ae=n(8596),ie=n(2263);function le(e,t){return e.some((e=>function(e,t){return!!(0,ae.Mg)(e.to,t)||!!Q(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function se(e){var t;let{items:n,position:a,className:i,onClick:l,...s}=e;const u=(0,r.useRef)(null),[c,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{u.current&&!u.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[u]),r.createElement("div",{ref:u,className:(0,o.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===a,"dropdown--show":c})},r.createElement(ee,(0,b.Z)({"aria-haspopup":"true","aria-expanded":c,role:"button",href:s.to?void 0:"#",className:(0,o.Z)("navbar__link",i)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!c))}}),null!=(t=s.children)?t:s.label),r.createElement("ul",{className:"dropdown__menu"},n.map(((e,t)=>r.createElement(Ee,(0,b.Z)({isDropdownItem:!0,onKeyDown:e=>{if(t===n.length-1&&"Tab"===e.key){e.preventDefault(),d(!1);const t=u.current.nextElementSibling;if(t){(t instanceof HTMLAnchorElement?t:t.querySelector("a")).focus()}}},activeClassName:"dropdown__link--active"},e,{key:t}))))))}function ue(e){var t;let{items:n,className:a,position:i,onClick:l,...s}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,ie.Z)(),{pathname:t}=(0,c.TH)();return t.replace(e,"/")}(),d=le(n,u),{collapsed:f,toggleCollapsed:p,setCollapsed:g}=(0,oe.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&g(!d)}),[u,d,g]),r.createElement("li",{className:(0,o.Z)("menu__list-item",{"menu__list-item--collapsed":f})},r.createElement(ee,(0,b.Z)({role:"button",className:(0,o.Z)("menu__link menu__link--sublist menu__link--sublist-caret",a)},s,{onClick:e=>{e.preventDefault(),p()}}),null!=(t=s.children)?t:s.label),r.createElement(oe.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:f},n.map(((e,t)=>r.createElement(Ee,(0,b.Z)({mobile:!0,isDropdownItem:!0,onClick:l,activeClassName:"menu__link--active"},e,{key:t}))))))}function ce(e){let{mobile:t=!1,...n}=e;const o=t?ue:se;return r.createElement(o,n)}var de=n(4711);function fe(e){let{width:t=20,height:n=20,...o}=e;return r.createElement("svg",(0,b.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},o),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}var pe="iconLanguage_nlXk";var ge=()=>null,me="searchBox_ZlJk";function he(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,o.Z)(n,me)},t)}var be=n(143),ve=n(2802);var ye=n(373);const we=e=>e.docs.find((t=>t.id===e.mainDocId));var ke={default:re,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:o,...a}=e;const{i18n:{currentLocale:i,locales:l,localeConfigs:s}}=(0,ie.Z)(),c=(0,de.l)(),d=[...n,...l.map((e=>{const n="pathname://"+c.createUrl({locale:e,fullyQualified:!1});return{label:s[e].label,lang:s[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...o],f=t?(0,u.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):s[i].label;return r.createElement(ce,(0,b.Z)({},a,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(fe,{className:pe}),f),items:d}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(he,{className:n},r.createElement(ge,null))},dropdown:ce,html:function(e){let{value:t,className:n,mobile:a=!1,isDropdownItem:i=!1}=e;const l=i?"li":"div";return r.createElement(l,{className:(0,o.Z)({navbar__item:!a&&!i,"menu__list-item":a},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:o,...a}=e;const{activeDoc:i}=(0,be.Iw)(o),l=(0,ve.vY)(t,o);return null===l?null:r.createElement(re,(0,b.Z)({exact:!0},a,{isActive:()=>(null==i?void 0:i.path)===l.path||!(null==i||!i.sidebar)&&i.sidebar===l.sidebar,label:null!=n?n:l.id,to:l.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:o,...a}=e;const{activeDoc:i}=(0,be.Iw)(o),l=(0,ve.oz)(t,o).link;if(!l)throw new Error('DocSidebarNavbarItem: Sidebar with ID "'+t+"\" doesn't have anything to be linked to.");return r.createElement(re,(0,b.Z)({exact:!0},a,{isActive:()=>(null==i?void 0:i.sidebar)===t,label:null!=n?n:l.label,to:l.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:o,...a}=e;const i=(0,ve.lO)(o)[0],l=null!=t?t:i.label,s=null!=n?n:(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(re,(0,b.Z)({},a,{label:l,to:s}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:o,dropdownItemsBefore:a,dropdownItemsAfter:i,...l}=e;const s=(0,be.Iw)(n),c=(0,be.gB)(n),{savePreferredVersionName:d}=(0,ye.J)(n),f=[...a,...c.map((e=>{var t;const n=null!=(t=s.alternateDocVersions[e.name])?t:we(e);return{label:e.label,to:n.path,isActive:()=>e===s.activeVersion,onClick:()=>d(e.name)}})),...i],p=(0,ve.lO)(n)[0],g=t&&f.length>1?(0,u.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):p.label,m=t&&f.length>1?void 0:we(p).path;return f.length<=1?r.createElement(re,(0,b.Z)({},l,{mobile:t,label:g,to:m,isActive:o?()=>!1:void 0})):r.createElement(ce,(0,b.Z)({},l,{mobile:t,label:g,to:m,items:f,isActive:o?()=>!1:void 0}))}};function Ee(e){let{type:t,...n}=e;const o=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),a=ke[o];if(!a)throw new Error('No NavbarItem component found for type "'+t+'".');return r.createElement(a,n)}function Se(){const e=(0,A.e)(),t=(0,m.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(Ee,(0,b.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function _e(e){return r.createElement("button",(0,b.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(u.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function xe(){const e=0===(0,m.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(_e,{onClick:()=>t.hide()}),t.content)}function Ce(){const e=(0,A.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(D,{header:r.createElement(q,null),primaryMenu:r.createElement(Se,null),secondaryMenu:r.createElement(xe,null)}):null}var Te="navbarHideable_m1mJ",Ae="navbarHidden_jGov";function Le(e){return r.createElement("div",(0,b.Z)({role:"presentation"},e,{className:(0,o.Z)("navbar-sidebar__backdrop",e.className)}))}function Ne(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:a}}=(0,m.L)(),i=(0,A.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),o=(0,r.useRef)(!1),a=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(a.current=e.getBoundingClientRect().height)}),[]);return(0,L.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+u{if(e)return t.location.hash?(o.current=!0,void n(!1)):void n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,className:(0,o.Z)("navbar","navbar--fixed-top",n&&[Te,!s&&Ae],{"navbar--dark":"dark"===a,"navbar--primary":"primary"===a,"navbar-sidebar--show":i.shown})},t,r.createElement(Le,{onClick:i.toggle}),r.createElement(Ce,null))}function Oe(e){let{width:t=30,height:n=30,className:o,...a}=e;return r.createElement("svg",(0,b.Z)({className:o,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},a),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Pe(){const e=(0,A.e)();return r.createElement("button",{onClick:e.toggle,onKeyDown:e.toggle,"aria-label":"Navigation bar toggle",className:"navbar__toggle clean-btn",type:"button",tabIndex:0},r.createElement(Oe,null))}var Ie="colorModeToggle_DEke";function Re(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Ee,(0,b.Z)({},e,{key:t})))))}function Me(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function De(){const e=(0,A.e)(),t=(0,m.L)().navbar.items,[n,o]=function(e){function t(e){var t;return"left"===(null!=(t=e.position)?t:"right")}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return r.createElement(Me,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Pe,null),r.createElement(W,null),r.createElement(Re,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Re,{items:o}),r.createElement(H,{className:Ie}),!a&&r.createElement(he,null,r.createElement(ge,null)))})}function je(){return r.createElement(Ne,null,r.createElement(De,null))}function Fe(e){let{item:t}=e;const{to:n,href:o,label:a,prependBaseUrlToHref:i,...l}=t,s=(0,K.Z)(n),u=(0,K.Z)(o,{forcePrependBaseUrl:!0});return r.createElement(Y.default,(0,b.Z)({className:"footer__link-item"},o?{href:i?u:o}:{to:s},l),a,o&&!(0,X.Z)(o)&&r.createElement(J.Z,null))}function Be(e){var t;let{item:n}=e;return n.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:n.html}}):r.createElement("li",{key:null!=(t=n.href)?t:n.to,className:"footer__item"},r.createElement(Fe,{item:n}))}function ze(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(Be,{key:t,item:e})))))}function Ue(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(ze,{key:t,column:e}))))}function $e(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function Ze(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(Fe,{item:t})}function He(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(Ze,{item:e}),t.length!==n+1&&r.createElement($e,null))))))}function Ve(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(Ue,{columns:t}):r.createElement(He,{links:t})}var We=n(941),Ge="footerLogoLink_BH7S";function qe(e){var t;let{logo:n}=e;const{withBaseUrl:a}=(0,K.C)(),i={light:a(n.src),dark:a(null!=(t=n.srcDark)?t:n.src)};return r.createElement(We.Z,{className:(0,o.Z)("footer__logo",n.className),alt:n.alt,sources:i,width:n.width,height:n.height,style:n.style})}function Ye(e){let{logo:t}=e;return t.href?r.createElement(Y.default,{href:t.href,className:Ge,target:t.target},r.createElement(qe,{logo:t})):r.createElement(qe,{logo:t})}function Ke(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Xe(e){let{style:t,links:n,logo:a,copyright:i}=e;return r.createElement("footer",{className:(0,o.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(a||i)&&r.createElement("div",{className:"footer__bottom text--center"},a&&r.createElement("div",{className:"margin-bottom--sm"},a),i)))}function Qe(){const{footer:e}=(0,m.L)();if(!e)return null;const{copyright:t,links:n,logo:o,style:a}=e;return r.createElement(Xe,{style:a,links:n&&n.length>0&&r.createElement(Ve,{links:n}),logo:o&&r.createElement(Ye,{logo:o}),copyright:t&&r.createElement(Ke,{copyright:t})})}var Je=r.memo(Qe),et=n(12);const tt="docusaurus.tab.",nt=r.createContext(void 0);const rt=(0,N.Qc)([j.S,h.pl,function(e){let{children:t}=e;const n=function(){const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,et.W)("docusaurus.tab."+e).set(t)}),[]);(0,r.useEffect)((()=>{try{const e={};(0,et._)().forEach((t=>{if(t.startsWith(tt)){const n=t.substring(tt.length);e[n]=(0,et.W)(t).get()}})),t(e)}catch(e){console.error(e)}}),[]);const o=(0,r.useCallback)(((e,r)=>{t((t=>({...t,[e]:r}))),n(e,r)}),[n]);return(0,r.useMemo)((()=>({tabGroupChoices:e,setTabGroupChoices:o})),[e,o])}();return r.createElement(nt.Provider,{value:n},t)},L.OC,ye.L5,i.VC,function(e){let{children:t}=e;return r.createElement(O.n2,null,r.createElement(A.M,null,r.createElement(I,null,t)))}]);function ot(e){let{children:t}=e;return r.createElement(rt,null,t)}function at(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(u.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("p",null,t.message),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},r.createElement(u.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}var it="mainWrapper_z2l0";function lt(e){const{children:t,noFooter:n,wrapperClassName:u,title:c,description:d}=e;return(0,s.t)(),r.createElement(ot,null,r.createElement(i.d,{title:c,description:d}),r.createElement(g,null),r.createElement(T,null),r.createElement(je,null),r.createElement("div",{className:(0,o.Z)(l.k.wrapper.main,it,u)},r.createElement(a.Z,{fallback:e=>r.createElement(at,e)},t)),!n&&r.createElement(Je,null))}},1327:function(e,t,n){"use strict";n.d(t,{Z:function(){return d}});var r=n(3117),o=n(7294),a=n(9960),i=n(4996),l=n(2263),s=n(6668),u=n(941);function c(e){let{logo:t,alt:n,imageClassName:r}=e;const a={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},l=o.createElement(u.Z,{className:t.className,sources:a,height:t.height,width:t.width,alt:n,style:t.style});return r?o.createElement("div",{className:r},l):l}function d(e){var t;const{siteConfig:{title:n}}=(0,l.Z)(),{navbar:{title:u,logo:d}}=(0,s.L)(),{imageClassName:f,titleClassName:p,...g}=e,m=(0,i.Z)((null==d?void 0:d.href)||"/"),h=u?"":n,b=null!=(t=null==d?void 0:d.alt)?t:h;return o.createElement(a.default,(0,r.Z)({to:m},g,(null==d?void 0:d.target)&&{target:d.target}),d&&o.createElement(c,{logo:d,alt:b,imageClassName:f}),null!=u&&o.createElement("b",{className:p},u))}},197:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(7294),o=n(5742);function a(e){let{locale:t,version:n,tag:a}=e;const i=t;return r.createElement(o.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),a&&r.createElement("meta",{name:"docusaurus_tag",content:a}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),a&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:a}))}},941:function(e,t,n){"use strict";n.d(t,{Z:function(){return u}});var r=n(3117),o=n(7294),a=n(4334),i=n(2389),l=n(2949),s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function u(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:u,className:c,alt:d,...f}=e,p=t?"dark"===n?["dark"]:["light"]:["light","dark"];return o.createElement(o.Fragment,null,p.map((e=>o.createElement("img",(0,r.Z)({key:e,src:u[e],alt:d,className:(0,a.Z)(s.themedImage,s["themedImage--"+e],c)},f)))))}},6043:function(e,t,n){"use strict";n.d(t,{u:function(){return i},z:function(){return g}});var r=n(3117),o=n(7294),a=n(412);function i(e){let{initialState:t}=e;const[n,r]=(0,o.useState)(null!=t&&t),a=(0,o.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:a}}const l={display:"none",overflow:"hidden",height:"0px"},s={display:"block",overflow:"visible",height:"auto"};function u(e,t){const n=t?l:s;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function c(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const a=(0,o.useRef)(!1);(0,o.useEffect)((()=>{const e=t.current;function o(){var t,n;const o=e.scrollHeight,a=null!=(t=null==r?void 0:r.duration)?t:function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(o);return{transition:"height "+a+"ms "+(null!=(n=null==r?void 0:r.easing)?n:"ease-in-out"),height:o+"px"}}function i(){const t=o();e.style.transition=t.transition,e.style.height=t.height}if(!a.current)return u(e,n),void(a.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(i(),requestAnimationFrame((()=>{e.style.height=l.height,e.style.overflow=l.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{i()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function d(e){if(!a.Z.canUseDOM)return e?l:s}function f(e){let{as:t="div",collapsed:n,children:r,animation:a,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const f=(0,o.useRef)(null);return c({collapsibleRef:f,collapsed:n,animation:a}),o.createElement(t,{ref:f,style:s?void 0:d(n),onTransitionEnd:e=>{"height"===e.propertyName&&(u(f.current,n),null==i||i(n))},className:l},r)}function p(e){let{collapsed:t,...n}=e;const[a,i]=(0,o.useState)(!t),[l,s]=(0,o.useState)(t);return(0,o.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,o.useLayoutEffect)((()=>{a&&s(t)}),[a,t]),a?o.createElement(f,(0,r.Z)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?p:f;return o.createElement(r,n)}},9689:function(e,t,n){"use strict";n.d(t,{nT:function(){return g},pl:function(){return p}});var r=n(7294),o=n(2389),a=n(12),i=n(902),l=n(6668);const s=(0,a.W)("docusaurus.announcement.dismiss"),u=(0,a.W)("docusaurus.announcement.id"),c=()=>"true"===s.get(),d=e=>s.set(String(e)),f=r.createContext(null);function p(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,o.Z)(),[n,a]=(0,r.useState)((()=>!!t&&c()));(0,r.useEffect)((()=>{a(c())}),[]);const i=(0,r.useCallback)((()=>{d(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&d(!1),!r&&c()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(f.Provider,{value:n},t)}function g(){const e=(0,r.useContext)(f);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:function(e,t,n){"use strict";n.d(t,{I:function(){return h},S:function(){return m}});var r=n(7294),o=n(412),a=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),u="theme",c=(0,i.W)(u),d="light",f="dark",p=e=>e===f?f:d;function g(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,i]=(0,r.useState)((e=>o.Z.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e))(e));(0,r.useEffect)((()=>{t&&c.del()}),[t]);const s=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:o=!0}=r;t?(i(t),o&&(e=>{c.set(p(e))})(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?f:d:e),c.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=c.get();null!==t&&s(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,s]);const g=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||g.current?g.current=window.matchMedia("print").matches:s(null)};return e.addListener(r),()=>e.removeListener(r)}),[s,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:s,get isDarkTheme(){return a===f},setLightTheme(){s(d)},setDarkTheme(){s(f)}})),[a,s])}function m(e){let{children:t}=e;const n=g();return r.createElement(s.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(s);if(null==e)throw new a.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:function(e,t,n){"use strict";n.d(t,{J:function(){return y},L5:function(){return b}});var r=n(7294),o=n(143),a=n(9935),i=n(6668),l=n(2802),s=n(902),u=n(12);const c=e=>"docs-preferred-version-"+e,d=(e,t,n)=>{(0,u.W)(c(e),{persistence:t}).set(n)},f=(e,t)=>(0,u.W)(c(e),{persistence:t}).get(),p=(e,t)=>{(0,u.W)(c(e),{persistence:t}).del()};const g=r.createContext(null);function m(){const e=(0,o._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[a,l]=(0,r.useState)((()=>(e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}]))))(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function o(e){const t=f(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(p(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,o(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[a,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function h(e){let{children:t}=e;const n=m();return r.createElement(g.Provider,{value:n},t)}function b(e){let{children:t}=e;return l.cE?r.createElement(h,null,t):r.createElement(r.Fragment,null,t)}function v(){const e=(0,r.useContext)(g);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function y(e){var t;void 0===e&&(e=a.m);const n=(0,o.zh)(e),[i,l]=v(),{preferredVersionName:s}=i[e];return{preferredVersion:null!=(t=n.versions.find((e=>e.name===s)))?t:null,savePreferredVersionName:(0,r.useCallback)((t=>{l.savePreferredVersion(e,t)}),[l,e])}}},1116:function(e,t,n){"use strict";n.d(t,{V:function(){return s},b:function(){return l}});var r=n(7294),o=n(902);const a=Symbol("EmptyContext"),i=r.createContext(a);function l(e){let{children:t,name:n,items:o}=e;const a=(0,r.useMemo)((()=>n&&o?{name:n,items:o}:null),[n,o]);return r.createElement(i.Provider,{value:a},t)}function s(){const e=(0,r.useContext)(i);if(e===a)throw new o.i6("DocsSidebarProvider");return e}},2961:function(e,t,n){"use strict";n.d(t,{M:function(){return f},e:function(){return p}});var r=n(7294),o=n(3102),a=n(7524),i=n(6775),l=n(902);function s(e){!function(e){const t=(0,i.k6)(),n=(0,l.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var u=n(6668);const c=r.createContext(void 0);function d(){const e=function(){const e=(0,o.HY)(),{items:t}=(0,u.L)().navbar;return 0===t.length&&!e.component}(),t=(0,a.i)(),n=!e&&"mobile"===t,[i,l]=(0,r.useState)(!1);s((()=>{if(i)return l(!1),!1}));const c=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:c,shown:i})),[e,n,c,i])}function f(e){let{children:t}=e;const n=d();return r.createElement(c.Provider,{value:n},t)}function p(){const e=r.useContext(c);if(void 0===e)throw new l.i6("NavbarMobileSidebarProvider");return e}},3102:function(e,t,n){"use strict";n.d(t,{HY:function(){return l},Zo:function(){return s},n2:function(){return i}});var r=n(7294),o=n(902);const a=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(a.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(a);if(!e)throw new o.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const i=(0,r.useContext)(a);if(!i)throw new o.i6("NavbarSecondaryMenuContentProvider");const[,l]=i,s=(0,o.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:function(e,t,n){"use strict";n.d(t,{h:function(){return o},t:function(){return a}});var r=n(7294);const o="navigation-with-keyboard";function a(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:function(e,t,n){"use strict";n.d(t,{i:function(){return u}});var r=n(7294),o=n(412);const a="desktop",i="mobile",l="ssr";function s(){return o.Z.canUseDOM?window.innerWidth>996?a:i:l}function u(){const[e,t]=(0,r.useState)((()=>s()));return(0,r.useEffect)((()=>{function e(){t(s())}return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(undefined)}}),[]),e}},5281:function(e,t,n){"use strict";n.d(t,{k:function(){return r}});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>"theme-admonition-"+e},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>"theme-doc-sidebar-item-category-level-"+e,docSidebarItemLinkLevel:e=>"theme-doc-sidebar-item-link-level-"+e},blog:{}}},2802:function(e,t,n){"use strict";n.d(t,{Wl:function(){return f},_F:function(){return g},cE:function(){return d},hI:function(){return w},lO:function(){return b},vY:function(){return y},oz:function(){return v},s1:function(){return h}});var r=n(7294),o=n(6775),a=n(8790),i=n(143),l=n(373),s=n(1116);function u(e){return Array.from(new Set(e))}var c=n(8596);const d=!!i._r;function f(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=f(t);if(e)return e}}}const p=(e,t)=>void 0!==e&&(0,c.Mg)(e,t);function g(e,t){return"link"===e.type?p(e.href,t):"category"===e.type&&(p(e.href,t)||((e,t)=>e.some((e=>g(e,t))))(e.items,t))}function m(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const o=[];return function e(t){for(const a of t)if("category"===a.type&&((0,c.Mg)(a.href,n)||e(a.items))||"link"===a.type&&(0,c.Mg)(a.href,n)){return r&&"category"!==a.type||o.unshift(a),!0}return!1}(t),o}function h(){var e;const t=(0,s.V)(),{pathname:n}=(0,o.TH)();return!1!==(null==(e=(0,i.gA)())?void 0:e.pluginData.breadcrumbs)&&t?m({sidebarItems:t.items,pathname:n}):null}function b(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),o=(0,i.yW)(e);return(0,r.useMemo)((()=>u([t,n,o].filter(Boolean))),[t,n,o])}function v(e,t){const n=b(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error("Can't find any sidebar with id \""+e+'" in version'+(n.length>1?"s":"")+" "+n.map((e=>e.name)).join(", ")+'".\n Available sidebar ids are:\n - '+Object.keys(t).join("\n- "));return r[1]}),[e,n])}function y(e,t){const n=b(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error("DocNavbarItem: couldn't find any doc with id \""+e+'" in version'+(n.length>1?"s":"")+" "+n.map((e=>e.name)).join(", ")+'".\nAvailable doc ids are:\n- '+u(t.map((e=>e.id))).join("\n- "))}return r}),[e,n])}function w(e){let{route:t,versionMetadata:n}=e;const r=(0,o.TH)(),i=t.routes,l=i.find((e=>(0,o.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,u=s?n.docsSidebars[s]:void 0;return{docElement:(0,a.H)(i),sidebarName:s,sidebarItems:u}}},1944:function(e,t,n){"use strict";n.d(t,{FG:function(){return f},d:function(){return c},VC:function(){return p}});var r=n(7294),o=n(7459),a=n(5742),i=n(226);function l(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),u=n(2263);function c(e){let{title:t,description:n,keywords:o,image:i,children:l}=e;const c=function(e){const{siteConfig:t}=(0,u.Z)(),{title:n,titleDelimiter:r}=t;return null!=e&&e.trim().length?e.trim()+" "+r+" "+n:n}(t),{withBaseUrl:d}=(0,s.C)(),f=i?d(i,{absolute:!0}):void 0;return r.createElement(a.Z,null,t&&r.createElement("title",null,c),t&&r.createElement("meta",{property:"og:title",content:c}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),o&&r.createElement("meta",{name:"keywords",content:Array.isArray(o)?o.join(","):o}),f&&r.createElement("meta",{property:"og:image",content:f}),f&&r.createElement("meta",{name:"twitter:image",content:f}),l)}const d=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(d),l=(0,o.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(a.Z,null,r.createElement("html",{className:l})),n)}function p(e){let{children:t}=e;const n=l(),a="plugin-"+n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"");const i="plugin-id-"+n.plugin.id;return r.createElement(f,{className:(0,o.Z)(a,i)},t)}},902:function(e,t,n){"use strict";n.d(t,{D9:function(){return i},Qc:function(){return u},Ql:function(){return s},i6:function(){return l},zX:function(){return a}});var r=n(7294);const o=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function a(e){const t=(0,r.useRef)(e);return o((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return o((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){var n,r,o,a;super(),this.name="ReactContextError",this.message="Hook "+(null!=(n=null==(r=this.stack)||null==(o=r.split("\n")[1])||null==(a=o.match(/at (?:\w+\.)?(?\w+)/))?void 0:a.groups.name)?n:"")+" is called outside the <"+e+">. "+(null!=t?t:"")}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function u(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8596:function(e,t,n){"use strict";n.d(t,{Mg:function(){return i},Ns:function(){return l}});var r=n(7294),o=n(723),a=n(2263);function i(e,t){const n=e=>{var t;return null==(t=!e||e.endsWith("/")?e:e+"/")?void 0:t.toLowerCase()};return n(e)===n(t)}function l(){const{baseUrl:e}=(0,a.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function o(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(o).flatMap((e=>{var t;return null!=(t=e.routes)?t:[]})))}(n)}({routes:o.Z,baseUrl:e})),[e])}},2466:function(e,t,n){"use strict";n.d(t,{Ct:function(){return f},OC:function(){return s},RF:function(){return d}});var r=n(7294),o=n(412),a=n(2389),i=n(902);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function u(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const c=()=>o.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=u(),o=(0,r.useRef)(c()),a=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=c();a(e,o.current),o.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[a,n,...t])}function f(){const e=(0,r.useRef)(null),t=(0,a.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const o=document.documentElement.scrollTop;(n&&o>e||!n&&ot&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>null==e.current?void 0:e.current()}}},3320:function(e,t,n){"use strict";n.d(t,{HX:function(){return r},os:function(){return o}});n(2263);const r="default";function o(e,t){return"docs-"+e+"-"+t}},12:function(e,t,n){"use strict";n.d(t,{W:function(){return l},_:function(){return s}});const r="localStorage";function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,a||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),a=!0),null}var t}let a=!1;const i={get:()=>null,set:()=>{},del:()=>{}};function l(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error('Illegal storage API usage for storage key "'+e+'".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.')}return{get:t,set:t,del:t}}(e);const n=o(null==t?void 0:t.persistence);return null===n?i:{get:()=>{try{return n.getItem(e)}catch(t){return console.error("Docusaurus storage error, can't get key="+e,t),null}},set:t=>{try{n.setItem(e,t)}catch(r){console.error("Docusaurus storage error, can't set "+e+"="+t,r)}},del:()=>{try{n.removeItem(e)}catch(t){console.error("Docusaurus storage error, can't delete key="+e,t)}}}}function s(e){void 0===e&&(e=r);const t=o(e);if(!t)return[];const n=[];for(let r=0;r{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:function(e,t,n){"use strict";n.d(t,{L:function(){return o}});var r=n(2263);function o(){return(0,r.Z)().siteConfig.themeConfig}},8802:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[o]=e.split(/[#?]/),a="/"===o||o===r?o:(i=o,n?function(e){return e.endsWith("/")?e:e+"/"}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(o,a)}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="post-content";var o=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(o).default}})},9318:function(e,t,n){"use strict";n.d(t,{lX:function(){return w},q_:function(){return C},ob:function(){return p},PP:function(){return A},Ep:function(){return f}});var r=n(3117);function o(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,o=e.length;r=0;f--){var p=i[f];"."===p?a(i,f):".."===p?(a(i,f),d++):d&&(a(i,f),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&o(i[0])||i.unshift("");var g=i.join("/");return n&&"/"!==g.substr(-1)&&(g+="/"),g},l=n(2177);function s(e){return"/"===e.charAt(0)?e:"/"+e}function u(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,o=t||"/";return n&&"?"!==n&&(o+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(o+="#"===r.charAt(0)?r:"#"+r),o}function p(e,t,n,o){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",o=t.indexOf("#");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf("?");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=(0,r.Z)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(a.key=n),o?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname="/"),a}function g(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,o):n.push(o),d({action:r,location:o,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",o=p(e,t,m(),w.location);c.confirmTransitionTo(o,r,n,(function(e){e&&(w.entries[w.index]=o,d({action:r,location:o}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t
'};function o(e,t,n){return en?n:e}function a(e){return 100*(-1+e)}function i(e,t,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+a(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+a(e)+"%,0)"}:{"margin-left":a(e)+"%"}).transition="all "+t+"ms "+n,o}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=o(e,r.minimum,1),n.status=1===e?null:e;var a=n.render(!t),u=a.querySelector(r.barSelector),c=r.speed,d=r.easing;return a.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(a,{transition:"none",opacity:1}),a.offsetWidth,setTimeout((function(){s(a,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*o(Math.random()*t,.1,.95)),t=o(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var o,i=t.querySelector(r.barSelector),l=e?"-100":a(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(o=t.querySelector(r.spinnerSelector))&&p(o),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,o=e.length,a=t.charAt(0).toUpperCase()+t.slice(1);o--;)if((r=e[o]+a)in n)return r;return t}function o(e){return e=n(e),t[e]||(t[e]=r(e))}function a(e,t,n){t=o(t),e.style[t]=n}return function(e,t){var n,r,o=arguments;if(2==o.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&a(e,n,r);else a(e,o[1],o[2])}}();function u(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=f(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},7418:function(e){"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function o(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(o){return!1}}()?Object.assign:function(e,a){for(var i,l,s=o(e),u=1;u\r\n])+>)[uismxfr]*/,greedy:!0},string:[{pattern:/~[cCsSwW](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|#\{[^}]+\}|#(?!\{)|[^#\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[csa]?/,greedy:!0,inside:{}},{pattern:/("""|''')[\s\S]*?\1/,greedy:!0,inside:{}},{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{}}],atom:{pattern:/(^|[^:]):\w+/,lookbehind:!0,alias:"symbol"},module:{pattern:/\b[A-Z]\w*\b/,alias:"class-name"},"attr-name":/\b\w+\??:(?!:)/,argument:{pattern:/(^|[^&])&\d+/,lookbehind:!0,alias:"variable"},attribute:{pattern:/@\w+/,alias:"variable"},function:/\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d))/,number:/\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,keyword:/\b(?:after|alias|and|case|catch|cond|def(?:callback|delegate|exception|impl|macro|module|n|np|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|quote|raise|require|rescue|try|unless|unquote|use|when)\b/,boolean:/\b(?:false|nil|true)\b/,operator:[/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,{pattern:/([^<])<(?!<)/,lookbehind:!0},{pattern:/([^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,%\[\]{}()]/},Prism.languages.elixir.string.forEach((function(e){e.inside={interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:Prism.languages.elixir}}}}))},2503:function(){!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,r={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[r,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:r.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:r.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":r,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:r.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:r.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},7345:function(){!function(e){var t=/\b(?:bool|bytes|double|s?fixed(?:32|64)|float|[su]?int(?:32|64)|string)\b/;e.languages.protobuf=e.languages.extend("clike",{"class-name":[{pattern:/(\b(?:enum|extend|message|service)\s+)[A-Za-z_]\w*(?=\s*\{)/,lookbehind:!0},{pattern:/(\b(?:rpc\s+\w+|returns)\s*\(\s*(?:stream\s+)?)\.?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?=\s*\))/,lookbehind:!0}],keyword:/\b(?:enum|extend|extensions|import|message|oneof|option|optional|package|public|repeated|required|reserved|returns|rpc(?=\s+\w)|service|stream|syntax|to)\b(?!\s*=\s*\d)/,function:/\b[a-z_]\w*(?=\s*\()/i}),e.languages.insertBefore("protobuf","operator",{map:{pattern:/\bmap<\s*[\w.]+\s*,\s*[\w.]+\s*>(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/[<>.,]/,builtin:t}},builtin:t,"positional-class-name":{pattern:/(?:\b|\B\.)[a-z_]\w*(?:\.[a-z_]\w*)*(?=\s+[a-z_]\w*\s*[=;])/i,alias:"class-name",inside:{punctuation:/\./}},annotation:{pattern:/(\[\s*)[a-z_]\w*(?=\s*=)/i,lookbehind:!0}})}(Prism)},1247:function(e,t,n){var r={"./prism-elixir":8805,"./prism-java":2503,"./prism-protobuf":7345};function o(e){var t=a(e);return n(t)}function a(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}o.keys=function(){return Object.keys(r)},o.resolve=a,e.exports=o,o.id=1247},2703:function(e,t,n){"use strict";var r=n(414);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},5697:function(e,t,n){e.exports=n(2703)()},414:function(e){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:function(e,t,n){"use strict";var r=n(7294),o=n(7418),a=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n