From 2eed520b95c9f44872e3041b7904aeec9951477e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 11:21:56 +0000 Subject: [PATCH] deploy: 4786479b68a78a1043b694165fe33a0930ee2cb1 --- 404.html | 10 ++++----- ...tyles.c128e35b.css => styles.7ac51c41.css} | 2 +- ...ntent-0ab721e980fb07462f0ea875e004ac60.png | Bin 0 -> 35514 bytes assets/js/14eb3368.716e9ec1.js | 1 + assets/js/14eb3368.a5d80bcb.js | 1 - assets/js/15555c3b.70906890.js | 1 + assets/js/16179cba.3a7346cc.js | 1 + ...72f0d.aa79666e.js => 1ba72f0d.da232385.js} | 2 +- assets/js/26bc6599.3b7fe1d7.js | 1 - assets/js/29451ac5.30e26a3b.js | 1 + assets/js/402d2e48.4e83c139.js | 1 - ...0d055.4e4684a7.js => 40b0d055.60ffe9ac.js} | 2 +- assets/js/47986192.13f6acda.js | 1 + assets/js/4899252d.b3e32514.js | 1 - assets/js/4c455ca7.946c6245.js | 1 - assets/js/5a7456e0.970b6829.js | 1 + assets/js/5a7456e0.a5334c36.js | 1 - assets/js/65d05370.47c9eac8.js | 1 + assets/js/65f6152f.850d0fdd.js | 1 + assets/js/661cef18.3a10670b.js | 1 + assets/js/6a6251fe.ed7cf9fb.js | 1 - ...66871.508587da.js => 70066871.f40ee112.js} | 2 +- ...76495.cd08c5dc.js => 74876495.09b764ba.js} | 2 +- assets/js/8101ff7e.a7fd7485.js | 1 + assets/js/8777f386.1463edb8.js | 1 - assets/js/935f2afb.9e7c9e9d.js | 1 + assets/js/935f2afb.caa8fb63.js | 1 - assets/js/9501552e.874dbf69.js | 1 + assets/js/ac75af2e.f73fc938.js | 1 - assets/js/d03241c9.4c55d6e8.js | 1 + ...686ac.c9777f1c.js => d3d686ac.26d4bc4a.js} | 2 +- assets/js/d72ac48e.28c67a5d.js | 1 + assets/js/d72ac48e.cd787f6d.js | 1 - assets/js/e11471c7.3a30b136.js | 1 + assets/js/e677b25a.4140a2d3.js | 1 - assets/js/e950844d.858a3214.js | 1 + ...8dad4.ce7e3bd0.js => eb58dad4.f93dfa8b.js} | 2 +- assets/js/main.20867153.js | 2 ++ ...CENSE.txt => main.20867153.js.LICENSE.txt} | 0 assets/js/main.80f47174.js | 2 -- assets/js/runtime~main.740579b8.js | 1 + assets/js/runtime~main.9ba3dced.js | 1 - blog.html | 10 ++++----- blog/archive.html | 10 ++++----- blog/first-blog-post.html | 10 ++++----- blog/long-blog-post.html | 10 ++++----- blog/mdx-blog-post.html | 10 ++++----- blog/tags.html | 10 ++++----- blog/tags/docusaurus.html | 10 ++++----- blog/tags/facebook.html | 10 ++++----- blog/tags/hello.html | 10 ++++----- blog/tags/hola.html | 10 ++++----- blog/welcome.html | 10 ++++----- docs/category/dt-definition.html | 17 ++++++++++++++++ docs/category/examples.html | 12 +++++------ docs/category/fmi-simulation.html | 12 +++++------ docs/category/guides.html | 17 ---------------- docs/category/installation.html | 12 +++++------ docs/category/overview.html | 12 +++++------ docs/category/raspberry-pi.html | 12 +++++------ docs/category/unity-visualization.html | 12 +++++------ docs/examples/ball-example.html | 12 +++++------ docs/examples/raspberry-example.html | 12 +++++------ .../raspberry-example/sending-data.html | 12 +++++------ docs/examples/string-example.html | 12 +++++------ docs/fmi/concepts.html | 17 ---------------- docs/fmi/installation.html | 17 ---------------- docs/guides.html | 17 ++++++++++++++++ .../{ => definition}/dt-schema-creation.html | 18 ++++++++--------- .../{ => definition}/type-creation.html | 18 ++++++++--------- docs/{ => guides}/fmi/API.html | 18 ++++++++--------- docs/guides/fmi/concepts.html | 17 ++++++++++++++++ docs/guides/unity/creating-unity-build.html | 12 +++++------ docs/guides/unity/using-grafana-plugin.html | 12 +++++------ docs/installation/manual.html | 14 ++++++------- docs/installation/manual/composition.html | 19 ++++++++++++++++++ docs/installation/manual/essential.html | 17 ++++++++++++++++ .../installation/manual/machine-learning.html | 17 ++++++++++++++++ docs/installation/manual/simulations.html | 17 ++++++++++++++++ docs/installation/manual/unity.html | 17 ++++++++++++++++ docs/installation/requirements.html | 17 ---------------- docs/installation/using-helm.html | 14 ++++++------- docs/overview/architecture.html | 12 +++++------ docs/overview/concepts.html | 12 +++++------ docs/overview/purpose.html | 12 +++++------ docs/quickstart.html | 14 ++++++------- index.html | 10 ++++----- markdown-page.html | 10 ++++----- sitemap.xml | 2 +- 89 files changed, 373 insertions(+), 299 deletions(-) rename assets/css/{styles.c128e35b.css => styles.7ac51c41.css} (58%) create mode 100644 assets/images/opentwins-plugin-content-0ab721e980fb07462f0ea875e004ac60.png create mode 100644 assets/js/14eb3368.716e9ec1.js delete mode 100644 assets/js/14eb3368.a5d80bcb.js create mode 100644 assets/js/15555c3b.70906890.js create mode 100644 assets/js/16179cba.3a7346cc.js rename assets/js/{1ba72f0d.aa79666e.js => 1ba72f0d.da232385.js} (79%) delete mode 100644 assets/js/26bc6599.3b7fe1d7.js create mode 100644 assets/js/29451ac5.30e26a3b.js delete mode 100644 assets/js/402d2e48.4e83c139.js rename assets/js/{40b0d055.4e4684a7.js => 40b0d055.60ffe9ac.js} (88%) create mode 100644 assets/js/47986192.13f6acda.js delete mode 100644 assets/js/4899252d.b3e32514.js delete mode 100644 assets/js/4c455ca7.946c6245.js create mode 100644 assets/js/5a7456e0.970b6829.js delete mode 100644 assets/js/5a7456e0.a5334c36.js create mode 100644 assets/js/65d05370.47c9eac8.js create mode 100644 assets/js/65f6152f.850d0fdd.js create mode 100644 assets/js/661cef18.3a10670b.js delete mode 100644 assets/js/6a6251fe.ed7cf9fb.js rename assets/js/{70066871.508587da.js => 70066871.f40ee112.js} (54%) rename assets/js/{74876495.cd08c5dc.js => 74876495.09b764ba.js} (95%) create mode 100644 assets/js/8101ff7e.a7fd7485.js delete mode 100644 assets/js/8777f386.1463edb8.js create mode 100644 assets/js/935f2afb.9e7c9e9d.js delete mode 100644 assets/js/935f2afb.caa8fb63.js create mode 100644 assets/js/9501552e.874dbf69.js delete mode 100644 assets/js/ac75af2e.f73fc938.js create mode 100644 assets/js/d03241c9.4c55d6e8.js rename assets/js/{d3d686ac.c9777f1c.js => d3d686ac.26d4bc4a.js} (60%) create mode 100644 assets/js/d72ac48e.28c67a5d.js delete mode 100644 assets/js/d72ac48e.cd787f6d.js create mode 100644 assets/js/e11471c7.3a30b136.js delete mode 100644 assets/js/e677b25a.4140a2d3.js create mode 100644 assets/js/e950844d.858a3214.js rename assets/js/{eb58dad4.ce7e3bd0.js => eb58dad4.f93dfa8b.js} (90%) create mode 100644 assets/js/main.20867153.js rename assets/js/{main.80f47174.js.LICENSE.txt => main.20867153.js.LICENSE.txt} (100%) delete mode 100644 assets/js/main.80f47174.js create mode 100644 assets/js/runtime~main.740579b8.js delete mode 100644 assets/js/runtime~main.9ba3dced.js create mode 100644 docs/category/dt-definition.html delete mode 100644 docs/category/guides.html delete mode 100644 docs/fmi/concepts.html delete mode 100644 docs/fmi/installation.html create mode 100644 docs/guides.html rename docs/guides/{ => definition}/dt-schema-creation.html (57%) rename docs/guides/{ => definition}/type-creation.html (69%) rename docs/{ => guides}/fmi/API.html (92%) create mode 100644 docs/guides/fmi/concepts.html create mode 100644 docs/installation/manual/composition.html create mode 100644 docs/installation/manual/essential.html create mode 100644 docs/installation/manual/machine-learning.html create mode 100644 docs/installation/manual/simulations.html create mode 100644 docs/installation/manual/unity.html delete mode 100644 docs/installation/requirements.html diff --git a/404.html b/404.html index 2b37839..3cc2251 100644 --- a/404.html +++ b/404.html @@ -4,14 +4,14 @@ Page Not Found | OpenTwins - - - + + +
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/css/styles.c128e35b.css b/assets/css/styles.7ac51c41.css similarity index 58% rename from assets/css/styles.c128e35b.css rename to assets/css/styles.7ac51c41.css index 7f5fe1b..becef59 100644 --- a/assets/css/styles.c128e35b.css +++ b/assets/css/styles.7ac51c41.css @@ -1 +1 @@ -.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.button,.dropdown__link,.text--truncate,.typing-demo{white-space:nowrap}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#40407a;--ifm-color-primary-dark:#3a3a6e;--ifm-color-primary-darker:#363668;--ifm-color-primary-darkest:#2d2d55;--ifm-color-primary-light:#464686;--ifm-color-primary-lighter:#4a4a8c;--ifm-color-primary-lightest:#53539f;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.list_eTzJ article:last-child,.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.mainTitle,.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area.breadcrumbs__link[href]:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.sidebar_re4s,.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.cardContainer_fWXF :last-child,.collapsibleContent_i85q>:last-child,.footer__items,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_f1Hy{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.docsWrapper_BCFX,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-duration:.25s;transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-duration:.1s;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover,.sidebarItemLink_mo7H:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#33d9b2;--ifm-color-primary-dark:#26cba4;--ifm-color-primary-darker:#24c09b;--ifm-color-primary-darkest:#23b996;--ifm-color-primary-light:#4addbb;--ifm-color-primary-lighter:#55dfbf;--ifm-color-primary-lightest:#77e6cc;--docusaurus-highlighted-code-line-bg:#0000004d}@font-face{font-family:DMMono;src:url(/opentwins/assets/fonts/DMMono-Regular-15edd89a6460acfb1a86017399e47a1f.ttf)}@font-face{font-family:DMMono;font-weight:700;src:url(/opentwins/assets/fonts/DMMono-Medium-50d7af0bb966bc0570a212128d7ab24d.ttf)}@font-face{font-family:DMMono;font-weight:lighter;src:url(/opentwins/assets/fonts/DMMono-Light-2cf6d0b2de012ff294ce86eecb4263e5.ttf)}.round-border{border-radius:0 20px 20px 0;-webkit-border-radius:0 20px 20px 0;-moz-border-radius:0 20px 20px 0}.center-content{display:flex;justify-content:center}.myNavbar{background-color:#fff}[data-theme=dark] .myNavbar{background-color:#1b1b1d}[data-theme=dark] .mainTitle{color:var(--ifm-color-primary-dark)}.wrapper{display:grid;margin-top:0;padding-top:0;place-items:center}.typing-demo{animation:2s steps(9) a,.5s step-end infinite alternate b;border-right:3px solid;font-family:DMMono;font-size:5em;font-weight:400;overflow:hidden;width:9ch}@keyframes a{0%{width:0}}@keyframes b{50%{border-color:#0000}}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.collapseSidebarButton_PEFL,.docSidebarContainer_b6E3,.sidebarLogo_isFc,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{flex:1 0 auto}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.sidebar_re4s{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.sidebarItemTitle_pO2u{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_mt6G,.sidebarItemList_Yudw{font-size:.9rem}.sidebarItem__DBe{margin-top:.7rem}.sidebarItemLink_mo7H{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_I1ZP{color:var(--ifm-color-primary)!important}.cardContainer_fWXF{--ifm-link-color:var(--ifm-color-emphasis-800);--ifm-link-hover-color:var(--ifm-color-emphasis-700);--ifm-link-hover-decoration:none;border:1px solid var(--ifm-color-emphasis-200);box-shadow:0 1.5px 3px 0 #00000026;transition:all var(--ifm-transition-fast) ease;transition-property:border,box-shadow}.cardContainer_fWXF:hover{border-color:var(--ifm-color-primary);box-shadow:0 3px 6px 0 #0003}.cardTitle_rnsV{font-size:1.2rem}.cardDescription_PWke{font-size:.8rem}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.heroBanner_qdFl{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_AeoN{align-items:center;display:flex;justify-content:center}.authorCol_Hf19{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_pa_O{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_G86a{margin-left:.3rem;margin-right:.3rem}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity .2s ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_Nnez{display:inline-block;margin:.5rem .5rem 0 1rem}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:.15s;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.blogPostFooterDetailsFull_mRVl{flex-direction:column}.tableOfContents_bqdL{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.breadcrumbHomeIcon_OVgt{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.title_kItE{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-leading)*1.25)}.mdxPageWrapper_j9I6{justify-content:center}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg);position:sticky}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;max-height:100vh;padding-top:var(--ifm-navbar-height);position:sticky;top:0;transition:opacity 50ms;width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{height:0;opacity:0;overflow:hidden;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;max-height:100vh;top:0;transition:background-color var(--ifm-transition-fast) ease}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn,.generatedIndexPage_vN6x{max-width:75%!important}.list_eTzJ article:nth-last-child(-n+2){margin-bottom:0!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.sidebar_re4s,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_f1Hy{font-size:2rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.button,.dropdown__link,.text--truncate,.typing-demo{white-space:nowrap}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#40407a;--ifm-color-primary-dark:#3a3a6e;--ifm-color-primary-darker:#363668;--ifm-color-primary-darkest:#2d2d55;--ifm-color-primary-light:#464686;--ifm-color-primary-lighter:#4a4a8c;--ifm-color-primary-lightest:#53539f;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.list_eTzJ article:last-child,.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.mainTitle,.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area.breadcrumbs__link[href]:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.sidebar_re4s,.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.DocCardList--no-description .card h2,.admonitionContent_S0QG>:last-child,.cardContainer_fWXF :last-child,.collapsibleContent_i85q>:last-child,.footer__items,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_f1Hy{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.docsWrapper_BCFX,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-duration:.25s;transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-duration:.1s;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover,.sidebarItemLink_mo7H:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#33d9b2;--ifm-color-primary-dark:#26cba4;--ifm-color-primary-darker:#24c09b;--ifm-color-primary-darkest:#23b996;--ifm-color-primary-light:#4addbb;--ifm-color-primary-lighter:#55dfbf;--ifm-color-primary-lightest:#77e6cc;--docusaurus-highlighted-code-line-bg:#0000004d}@font-face{font-family:DMMono;src:url(/opentwins/assets/fonts/DMMono-Regular-15edd89a6460acfb1a86017399e47a1f.ttf)}@font-face{font-family:DMMono;font-weight:700;src:url(/opentwins/assets/fonts/DMMono-Medium-50d7af0bb966bc0570a212128d7ab24d.ttf)}@font-face{font-family:DMMono;font-weight:lighter;src:url(/opentwins/assets/fonts/DMMono-Light-2cf6d0b2de012ff294ce86eecb4263e5.ttf)}.round-border{border-radius:0 20px 20px 0;-webkit-border-radius:0 20px 20px 0;-moz-border-radius:0 20px 20px 0}.center-content{display:flex;justify-content:center}.myNavbar{background-color:#fff}[data-theme=dark] .myNavbar{background-color:#1b1b1d}[data-theme=dark] .mainTitle{color:var(--ifm-color-primary-dark)}.wrapper{display:grid;margin-top:0;padding-top:0;place-items:center}.typing-demo{animation:2s steps(9) a,.5s step-end infinite alternate b;border-right:3px solid;font-family:DMMono;font-size:5em;font-weight:400;overflow:hidden;width:9ch}@keyframes a{0%{width:0}}@keyframes b{50%{border-color:#0000}}#docusaurus-base-url-issue-banner-container,.DocCardList--no-description .card p,.collapseSidebarButton_PEFL,.docSidebarContainer_b6E3,.sidebarLogo_isFc,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{flex:1 0 auto}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.sidebar_re4s{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.sidebarItemTitle_pO2u{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_mt6G,.sidebarItemList_Yudw{font-size:.9rem}.sidebarItem__DBe{margin-top:.7rem}.sidebarItemLink_mo7H{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_I1ZP{color:var(--ifm-color-primary)!important}.cardContainer_fWXF{--ifm-link-color:var(--ifm-color-emphasis-800);--ifm-link-hover-color:var(--ifm-color-emphasis-700);--ifm-link-hover-decoration:none;border:1px solid var(--ifm-color-emphasis-200);box-shadow:0 1.5px 3px 0 #00000026;transition:all var(--ifm-transition-fast) ease;transition-property:border,box-shadow}.cardContainer_fWXF:hover{border-color:var(--ifm-color-primary);box-shadow:0 3px 6px 0 #0003}.cardTitle_rnsV{font-size:1.2rem}.cardDescription_PWke{font-size:.8rem}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.heroBanner_qdFl{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_AeoN{align-items:center;display:flex;justify-content:center}.authorCol_Hf19{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_pa_O{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_G86a{margin-left:.3rem;margin-right:.3rem}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity .2s ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_Nnez{display:inline-block;margin:.5rem .5rem 0 1rem}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:.15s;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.blogPostFooterDetailsFull_mRVl{flex-direction:column}.tableOfContents_bqdL{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.breadcrumbHomeIcon_OVgt{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.title_kItE{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-leading)*1.25)}.mdxPageWrapper_j9I6{justify-content:center}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg);position:sticky}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;max-height:100vh;padding-top:var(--ifm-navbar-height);position:sticky;top:0;transition:opacity 50ms;width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{height:0;opacity:0;overflow:hidden;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;max-height:100vh;top:0;transition:background-color var(--ifm-transition-fast) ease}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn,.generatedIndexPage_vN6x{max-width:75%!important}.list_eTzJ article:nth-last-child(-n+2){margin-bottom:0!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.sidebar_re4s,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_f1Hy{font-size:2rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/images/opentwins-plugin-content-0ab721e980fb07462f0ea875e004ac60.png b/assets/images/opentwins-plugin-content-0ab721e980fb07462f0ea875e004ac60.png new file mode 100644 index 0000000000000000000000000000000000000000..8c3e4f439bff4aa6a5cb2375b4d91c26fe863667 GIT binary patch literal 35514 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 R#w);=!c!I5(kEu`{ufq+hc*BJ literal 0 HcmV?d00001 diff --git a/assets/js/14eb3368.716e9ec1.js b/assets/js/14eb3368.716e9ec1.js new file mode 100644 index 0000000..1474f33 --- /dev/null +++ b/assets/js/14eb3368.716e9ec1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9817],{1986:(e,t,a)=>{a.d(t,{Z:()=>p});var n=a(7462),r=a(7294),i=a(6010),l=a(5281),s=a(3438),c=a(8596),o=a(9960),m=a(4996),d=a(5999);function u(e){return r.createElement("svg",(0,n.Z)({viewBox:"0 0 24 24"},e),r.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const h={breadcrumbsContainer:"breadcrumbsContainer_Z_bl",breadcrumbHomeIcon:"breadcrumbHomeIcon_OVgt"};function b(e){let{children:t,href:a,isLast:n}=e;const i="breadcrumbs__link";return n?r.createElement("span",{className:i,itemProp:"name"},t):a?r.createElement(o.Z,{className:i,href:a,itemProp:"item"},r.createElement("span",{itemProp:"name"},t)):r.createElement("span",{className:i},t)}function v(e){let{children:t,active:a,index:l,addMicrodata:s}=e;return r.createElement("li",(0,n.Z)({},s&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,i.Z)("breadcrumbs__item",{"breadcrumbs__item--active":a})}),t,r.createElement("meta",{itemProp:"position",content:String(l+1)}))}function g(){const e=(0,m.Z)("/");return r.createElement("li",{className:"breadcrumbs__item"},r.createElement(o.Z,{"aria-label":(0,d.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:(0,i.Z)("breadcrumbs__link",h.breadcrumbsItemLink),href:e},r.createElement(u,{className:h.breadcrumbHomeIcon})))}function p(){const e=(0,s.s1)(),t=(0,c.Ns)();return e?r.createElement("nav",{className:(0,i.Z)(l.k.docs.docBreadcrumbs,h.breadcrumbsContainer),"aria-label":(0,d.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},r.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&r.createElement(g,null),e.map(((t,a)=>{const n=a===e.length-1;return r.createElement(v,{key:a,active:n,index:a,addMicrodata:!!t.href},r.createElement(b,{href:t.href,isLast:n},t.label))})))):null}},2991:(e,t,a)=>{a.d(t,{Z:()=>g});var n=a(7294),r=a(6010),i=a(3438),l=a(9960),s=a(3919),c=a(5999);const o={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};function m(e){let{href:t,children:a}=e;return n.createElement(l.Z,{href:t,className:(0,r.Z)("card padding--lg",o.cardContainer)},a)}function d(e){let{href:t,icon:a,title:i,description:l}=e;return n.createElement(m,{href:t},n.createElement("h2",{className:(0,r.Z)("text--truncate",o.cardTitle),title:i},a," ",i),l&&n.createElement("p",{className:(0,r.Z)("text--truncate",o.cardDescription),title:l},l))}function u(e){let{item:t}=e;const a=(0,i.Wl)(t);return a?n.createElement(d,{href:a,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:(0,c.I)({message:"{count} items",id:"theme.docs.DocCard.categoryDescription",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t.items.length})}):null}function h(e){let{item:t}=e;const a=(0,s.Z)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,i.xz)(t.docId??void 0);return n.createElement(d,{href:t.href,icon:a,title:t.label,description:r?.description})}function b(e){let{item:t}=e;switch(t.type){case"link":return n.createElement(h,{item:t});case"category":return n.createElement(u,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function v(e){let{className:t}=e;const a=(0,i.jA)();return n.createElement(g,{items:a.items,className:t})}function g(e){const{items:t,className:a}=e;if(!t)return n.createElement(v,e);const l=(0,i.MN)(t);return n.createElement("section",{className:(0,r.Z)("row",a)},l.map(((e,t)=>n.createElement("article",{key:t,className:"col col--6 margin-bottom--lg"},n.createElement(b,{item:e})))))}},5541:(e,t,a)=>{a.r(t),a.d(t,{default:()=>g});var n=a(7294),r=a(1944),i=a(3438),l=a(4996),s=a(2991),c=a(49),o=a(3120),m=a(4364),d=a(1986),u=a(2503);const h={generatedIndexPage:"generatedIndexPage_vN6x",list:"list_eTzJ",title:"title_kItE"};function b(e){let{categoryGeneratedIndex:t}=e;return n.createElement(r.d,{title:t.title,description:t.description,keywords:t.keywords,image:(0,l.Z)(t.image)})}function v(e){let{categoryGeneratedIndex:t}=e;const a=(0,i.jA)();return n.createElement("div",{className:h.generatedIndexPage},n.createElement(o.Z,null),n.createElement(d.Z,null),n.createElement(m.Z,null),n.createElement("header",null,n.createElement(u.Z,{as:"h1",className:h.title},t.title),t.description&&n.createElement("p",null,t.description)),n.createElement("article",{className:"margin-top--lg"},n.createElement(s.Z,{items:a.items,className:h.list})),n.createElement("footer",{className:"margin-top--lg"},n.createElement(c.Z,{previous:t.navigation.previous,next:t.navigation.next})))}function g(e){return n.createElement(n.Fragment,null,n.createElement(b,e),n.createElement(v,e))}},49:(e,t,a)=>{a.d(t,{Z:()=>s});var n=a(7462),r=a(7294),i=a(5999),l=a(2244);function s(e){const{previous:t,next:a}=e;return r.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,i.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&r.createElement(l.Z,(0,n.Z)({},t,{subLabel:r.createElement(i.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),a&&r.createElement(l.Z,(0,n.Z)({},a,{subLabel:r.createElement(i.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}},4364:(e,t,a)=>{a.d(t,{Z:()=>c});var n=a(7294),r=a(6010),i=a(5999),l=a(5281),s=a(4477);function c(e){let{className:t}=e;const a=(0,s.E)();return a.badge?n.createElement("span",{className:(0,r.Z)(t,l.k.docs.docVersionBadge,"badge badge--secondary")},n.createElement(i.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:a.label}},"Version: {versionLabel}")):null}},3120:(e,t,a)=>{a.d(t,{Z:()=>g});var n=a(7294),r=a(6010),i=a(2263),l=a(9960),s=a(5999),c=a(143),o=a(5281),m=a(373),d=a(4477);const u={unreleased:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(s.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:n.createElement("b",null,a.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(s.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:n.createElement("b",null,a.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function h(e){const t=u[e.versionMetadata.banner];return n.createElement(t,e)}function b(e){let{versionLabel:t,to:a,onClick:r}=e;return n.createElement(s.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:n.createElement("b",null,n.createElement(l.Z,{to:a,onClick:r},n.createElement(s.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function v(e){let{className:t,versionMetadata:a}=e;const{siteConfig:{title:l}}=(0,i.Z)(),{pluginId:s}=(0,c.gA)({failfast:!0}),{savePreferredVersionName:d}=(0,m.J)(s),{latestDocSuggestion:u,latestVersionSuggestion:v}=(0,c.Jo)(s),g=u??(p=v).docs.find((e=>e.id===p.mainDocId));var p;return n.createElement("div",{className:(0,r.Z)(t,o.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},n.createElement("div",null,n.createElement(h,{siteTitle:l,versionMetadata:a})),n.createElement("div",{className:"margin-top--md"},n.createElement(b,{versionLabel:v.label,to:g.path,onClick:()=>d(v.name)})))}function g(e){let{className:t}=e;const a=(0,d.E)();return a.banner?n.createElement(v,{className:t,versionMetadata:a}):null}},2503:(e,t,a)=>{a.d(t,{Z:()=>o});var n=a(7462),r=a(7294),i=a(6010),l=a(5999),s=a(6668);const c={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function o(e){let{as:t,id:a,...o}=e;const{navbar:{hideOnScroll:m}}=(0,s.L)();return"h1"!==t&&a?r.createElement(t,(0,n.Z)({},o,{className:(0,i.Z)("anchor",m?c.anchorWithHideOnScrollNavbar:c.anchorWithStickyNavbar),id:a}),o.children,r.createElement("a",{className:"hash-link",href:`#${a}`,title:(0,l.I)({id:"theme.common.headingLinkTitle",message:"Direct link to heading",description:"Title for link to heading"})},"\u200b")):r.createElement(t,(0,n.Z)({},o,{id:void 0}))}},2244:(e,t,a)=>{a.d(t,{Z:()=>l});var n=a(7294),r=a(6010),i=a(9960);function l(e){const{permalink:t,title:a,subLabel:l,isNext:s}=e;return n.createElement(i.Z,{className:(0,r.Z)("pagination-nav__link",s?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},l&&n.createElement("div",{className:"pagination-nav__sublabel"},l),n.createElement("div",{className:"pagination-nav__label"},a))}}}]); \ No newline at end of file diff --git a/assets/js/14eb3368.a5d80bcb.js b/assets/js/14eb3368.a5d80bcb.js deleted file mode 100644 index d14738d..0000000 --- a/assets/js/14eb3368.a5d80bcb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9817],{1986:(e,t,a)=>{a.d(t,{Z:()=>p});var n=a(7462),r=a(7294),i=a(6010),l=a(5281),s=a(3438),c=a(8596),o=a(9960),m=a(4996),d=a(5999);function u(e){return r.createElement("svg",(0,n.Z)({viewBox:"0 0 24 24"},e),r.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const h={breadcrumbsContainer:"breadcrumbsContainer_Z_bl",breadcrumbHomeIcon:"breadcrumbHomeIcon_OVgt"};function b(e){let{children:t,href:a,isLast:n}=e;const i="breadcrumbs__link";return n?r.createElement("span",{className:i,itemProp:"name"},t):a?r.createElement(o.Z,{className:i,href:a,itemProp:"item"},r.createElement("span",{itemProp:"name"},t)):r.createElement("span",{className:i},t)}function v(e){let{children:t,active:a,index:l,addMicrodata:s}=e;return r.createElement("li",(0,n.Z)({},s&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,i.Z)("breadcrumbs__item",{"breadcrumbs__item--active":a})}),t,r.createElement("meta",{itemProp:"position",content:String(l+1)}))}function g(){const e=(0,m.Z)("/");return r.createElement("li",{className:"breadcrumbs__item"},r.createElement(o.Z,{"aria-label":(0,d.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:(0,i.Z)("breadcrumbs__link",h.breadcrumbsItemLink),href:e},r.createElement(u,{className:h.breadcrumbHomeIcon})))}function p(){const e=(0,s.s1)(),t=(0,c.Ns)();return e?r.createElement("nav",{className:(0,i.Z)(l.k.docs.docBreadcrumbs,h.breadcrumbsContainer),"aria-label":(0,d.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},r.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&r.createElement(g,null),e.map(((t,a)=>{const n=a===e.length-1;return r.createElement(v,{key:a,active:n,index:a,addMicrodata:!!t.href},r.createElement(b,{href:t.href,isLast:n},t.label))})))):null}},4228:(e,t,a)=>{a.r(t),a.d(t,{default:()=>I});var n=a(7294),r=a(1944),i=a(3438),l=a(4996),s=a(6010),c=a(9960),o=a(3919),m=a(5999);const d={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};function u(e){let{href:t,children:a}=e;return n.createElement(c.Z,{href:t,className:(0,s.Z)("card padding--lg",d.cardContainer)},a)}function h(e){let{href:t,icon:a,title:r,description:i}=e;return n.createElement(u,{href:t},n.createElement("h2",{className:(0,s.Z)("text--truncate",d.cardTitle),title:r},a," ",r),i&&n.createElement("p",{className:(0,s.Z)("text--truncate",d.cardDescription),title:i},i))}function b(e){let{item:t}=e;const a=(0,i.Wl)(t);return a?n.createElement(h,{href:a,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:(0,m.I)({message:"{count} items",id:"theme.docs.DocCard.categoryDescription",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t.items.length})}):null}function v(e){let{item:t}=e;const a=(0,o.Z)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,i.xz)(t.docId??void 0);return n.createElement(h,{href:t.href,icon:a,title:t.label,description:r?.description})}function g(e){let{item:t}=e;switch(t.type){case"link":return n.createElement(v,{item:t});case"category":return n.createElement(b,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function p(e){let{className:t}=e;const a=(0,i.jA)();return n.createElement(E,{items:a.items,className:t})}function E(e){const{items:t,className:a}=e;if(!t)return n.createElement(p,e);const r=(0,i.MN)(t);return n.createElement("section",{className:(0,s.Z)("row",a)},r.map(((e,t)=>n.createElement("article",{key:t,className:"col col--6 margin-bottom--lg"},n.createElement(g,{item:e})))))}var f=a(49),N=a(3120),Z=a(4364),k=a(1986),L=a(2503);const _={generatedIndexPage:"generatedIndexPage_vN6x",list:"list_eTzJ",title:"title_kItE"};function T(e){let{categoryGeneratedIndex:t}=e;return n.createElement(r.d,{title:t.title,description:t.description,keywords:t.keywords,image:(0,l.Z)(t.image)})}function x(e){let{categoryGeneratedIndex:t}=e;const a=(0,i.jA)();return n.createElement("div",{className:_.generatedIndexPage},n.createElement(N.Z,null),n.createElement(k.Z,null),n.createElement(Z.Z,null),n.createElement("header",null,n.createElement(L.Z,{as:"h1",className:_.title},t.title),t.description&&n.createElement("p",null,t.description)),n.createElement("article",{className:"margin-top--lg"},n.createElement(E,{items:a.items,className:_.list})),n.createElement("footer",{className:"margin-top--lg"},n.createElement(f.Z,{previous:t.navigation.previous,next:t.navigation.next})))}function I(e){return n.createElement(n.Fragment,null,n.createElement(T,e),n.createElement(x,e))}},49:(e,t,a)=>{a.d(t,{Z:()=>s});var n=a(7462),r=a(7294),i=a(5999),l=a(2244);function s(e){const{previous:t,next:a}=e;return r.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,i.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&r.createElement(l.Z,(0,n.Z)({},t,{subLabel:r.createElement(i.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),a&&r.createElement(l.Z,(0,n.Z)({},a,{subLabel:r.createElement(i.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}},4364:(e,t,a)=>{a.d(t,{Z:()=>c});var n=a(7294),r=a(6010),i=a(5999),l=a(5281),s=a(4477);function c(e){let{className:t}=e;const a=(0,s.E)();return a.badge?n.createElement("span",{className:(0,r.Z)(t,l.k.docs.docVersionBadge,"badge badge--secondary")},n.createElement(i.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:a.label}},"Version: {versionLabel}")):null}},3120:(e,t,a)=>{a.d(t,{Z:()=>g});var n=a(7294),r=a(6010),i=a(2263),l=a(9960),s=a(5999),c=a(143),o=a(5281),m=a(373),d=a(4477);const u={unreleased:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(s.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:n.createElement("b",null,a.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(s.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:n.createElement("b",null,a.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function h(e){const t=u[e.versionMetadata.banner];return n.createElement(t,e)}function b(e){let{versionLabel:t,to:a,onClick:r}=e;return n.createElement(s.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:n.createElement("b",null,n.createElement(l.Z,{to:a,onClick:r},n.createElement(s.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function v(e){let{className:t,versionMetadata:a}=e;const{siteConfig:{title:l}}=(0,i.Z)(),{pluginId:s}=(0,c.gA)({failfast:!0}),{savePreferredVersionName:d}=(0,m.J)(s),{latestDocSuggestion:u,latestVersionSuggestion:v}=(0,c.Jo)(s),g=u??(p=v).docs.find((e=>e.id===p.mainDocId));var p;return n.createElement("div",{className:(0,r.Z)(t,o.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},n.createElement("div",null,n.createElement(h,{siteTitle:l,versionMetadata:a})),n.createElement("div",{className:"margin-top--md"},n.createElement(b,{versionLabel:v.label,to:g.path,onClick:()=>d(v.name)})))}function g(e){let{className:t}=e;const a=(0,d.E)();return a.banner?n.createElement(v,{className:t,versionMetadata:a}):null}},2503:(e,t,a)=>{a.d(t,{Z:()=>o});var n=a(7462),r=a(7294),i=a(6010),l=a(5999),s=a(6668);const c={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function o(e){let{as:t,id:a,...o}=e;const{navbar:{hideOnScroll:m}}=(0,s.L)();return"h1"!==t&&a?r.createElement(t,(0,n.Z)({},o,{className:(0,i.Z)("anchor",m?c.anchorWithHideOnScrollNavbar:c.anchorWithStickyNavbar),id:a}),o.children,r.createElement("a",{className:"hash-link",href:`#${a}`,title:(0,l.I)({id:"theme.common.headingLinkTitle",message:"Direct link to heading",description:"Title for link to heading"})},"\u200b")):r.createElement(t,(0,n.Z)({},o,{id:void 0}))}},2244:(e,t,a)=>{a.d(t,{Z:()=>l});var n=a(7294),r=a(6010),i=a(9960);function l(e){const{permalink:t,title:a,subLabel:l,isNext:s}=e;return n.createElement(i.Z,{className:(0,r.Z)("pagination-nav__link",s?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},l&&n.createElement("div",{className:"pagination-nav__sublabel"},l),n.createElement("div",{className:"pagination-nav__label"},a))}}}]); \ No newline at end of file diff --git a/assets/js/15555c3b.70906890.js b/assets/js/15555c3b.70906890.js new file mode 100644 index 0000000..a7562e5 --- /dev/null +++ b/assets/js/15555c3b.70906890.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4298],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>y});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=a.createContext({}),u=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},m=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,m=r(e,["components","mdxType","originalType","parentName"]),p=u(t),d=i,y=p["".concat(s,".").concat(d)]||p[d]||c[d]||l;return t?a.createElement(y,o(o({ref:n},m),{},{components:t})):a.createElement(y,o({ref:n},m))}));function y(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var l=t.length,o=new Array(l);o[0]=d;var r={};for(var s in n)hasOwnProperty.call(n,s)&&(r[s]=n[s]);r.originalType=e,r[p]="string"==typeof e?e:i,o[1]=r;for(var u=2;u{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>r,toc:()=>u});var a=t(7462),i=(t(7294),t(3905));const l={sidebar_position:4},o="Simulations",r={unversionedId:"installation/manual/simulations",id:"installation/manual/simulations",title:"Simulations",description:"FMI simulations",source:"@site/docs/installation/manual/simulations.md",sourceDirName:"installation/manual",slug:"/installation/manual/simulations",permalink:"/opentwins/docs/installation/manual/simulations",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual/simulations.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"Machine Learning",permalink:"/opentwins/docs/installation/manual/machine-learning"},next:{title:"3D visualization",permalink:"/opentwins/docs/installation/manual/unity"}},s={},u=[{value:"FMI simulations",id:"fmi-simulations",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Deploy",id:"deploy",level:3},{value:"Connect",id:"connect",level:3},{value:"Custom simulations",id:"custom-simulations",level:2},{value:"Prerequisites",id:"prerequisites-1",level:3},{value:"Deploy",id:"deploy-1",level:3},{value:"Connect",id:"connect-1",level:3}],m={toc:u},p="wrapper";function c(e){let{components:n,...t}=e;return(0,i.kt)(p,(0,a.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"simulations"},"Simulations"),(0,i.kt)("h2",{id:"fmi-simulations"},"FMI simulations"),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"The FMI simulation service is currently being tested. Please be patient, as soon as it is properly tested, the public image will be available on Docker Hub.")),(0,i.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("p",null,"Before you begin, ensure you have the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Access to a Kubernetes cluster"),(0,i.kt)("li",{parentName:"ul"},"OpenTwins with the components of the essential functionality (monitoring) already installed by Helm or manually"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"kubectl")," installed and configured")),(0,i.kt)("h3",{id:"deploy"},"Deploy"),(0,i.kt)("p",null,"You can manually deploy the component by creating a Kubernetes deployment resource and service."),(0,i.kt)("p",null,"Create a YAML file for the deployment with this content:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="deployment.yaml"',title:'"deployment.yaml"'},"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n labels:\n name: opentwins-fmi-api\n name: opentwins-fmi-api\nspec:\n replicas: 1\n selector:\n matchLabels:\n name: pod-opentwins-fmi-api\n template:\n metadata:\n labels:\n name: pod-opentwins-fmi-api\n name: opentwins-fmi-api\n spec:\n serviceAccountName: ot-agents\n automountServiceAccountToken: true\n containers:\n - image: ertis/opentwins-fmi-simulator-api-v2:latest\n name: opentwins-fmi-api\n env:\n - name: KUBE_NAMESPACE\n value: \n - name: INSIDE_CLUSTER\n value: \n - name: INFLUXDB_HOST\n value: \n - name: INFLUXDB_TOKEN\n value: \n - name: INFLUXDB_DB\n value: \n - name: MINIO_TOKEN\n value: \n - name: MINIO_URL\n value: \n - name: MINIO_A_KEY\n value: \n - name: MINIO_S_KEY\n value: \n - name: POSTGRE_HOST\n value: \n - name: POSTGRE_PORT\n value: \n - name: POSTGRE_DB\n value: \n - name: POSTGRE_USER\n value: \n - name: POSTGRE_PASSWORD\n value: \n - name: BROKER_TYPE\n value: \n - name: BROKER_IP\n value: \n - name: BROKER_PORT\n value: \n - name: BROKER_TOPIC\n value: \n - name: BROKER_USERNAME\n value: \n - name: BROKER_PASSWORD\n value: \n ports:\n - containerPort: 8001\n imagePullPolicy: Always\n")),(0,i.kt)("p",null,"Next, create a YAML file for the service with this content:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="service.yaml"',title:'"service.yaml"'},'apiVersion: v1\nkind: Service\nmetadata:\n name: opentwins-fmi-api\nspec:\n selector:\n name: pod-opentwins-fmi-api\n type: NodePort\n ports:\n - protocol: "TCP"\n port: 8000\n nodePort: \n targetPort: 8000\n\n')),(0,i.kt)("p",null,"Apply the deployment and service using the following commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl apply -f deployment.yaml -n opentwins\nkubectl apply -f service.yaml -n opentwins\n")),(0,i.kt)("p",null,"To ",(0,i.kt)("strong",{parentName:"p"},"verify that everything is working correctly"),", use the following command to check if the new components are running and ready to use."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl get all -n opentwins\n")),(0,i.kt)("h3",{id:"connect"},"Connect"),(0,i.kt)("h2",{id:"custom-simulations"},"Custom simulations"),(0,i.kt)("h3",{id:"prerequisites-1"},"Prerequisites"),(0,i.kt)("h3",{id:"deploy-1"},"Deploy"),(0,i.kt)("h3",{id:"connect-1"},"Connect"))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/16179cba.3a7346cc.js b/assets/js/16179cba.3a7346cc.js new file mode 100644 index 0000000..0991cd7 --- /dev/null +++ b/assets/js/16179cba.3a7346cc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8465],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});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 c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),p=a,f=m["".concat(c,".").concat(p)]||m[p]||d[p]||i;return n?r.createElement(f,o(o({ref:t},u),{},{components:n})):r.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=p;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[m]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{n.d(t,{Z:()=>y});var r=n(7294),a=n(6010),i=n(3438),o=n(9960),l=n(3919),c=n(5999);const s={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};function u(e){let{href:t,children:n}=e;return r.createElement(o.Z,{href:t,className:(0,a.Z)("card padding--lg",s.cardContainer)},n)}function m(e){let{href:t,icon:n,title:i,description:o}=e;return r.createElement(u,{href:t},r.createElement("h2",{className:(0,a.Z)("text--truncate",s.cardTitle),title:i},n," ",i),o&&r.createElement("p",{className:(0,a.Z)("text--truncate",s.cardDescription),title:o},o))}function d(e){let{item:t}=e;const n=(0,i.Wl)(t);return n?r.createElement(m,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:(0,c.I)({message:"{count} items",id:"theme.docs.DocCard.categoryDescription",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t.items.length})}):null}function p(e){let{item:t}=e;const n=(0,l.Z)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",a=(0,i.xz)(t.docId??void 0);return r.createElement(m,{href:t.href,icon:n,title:t.label,description:a?.description})}function f(e){let{item:t}=e;switch(t.type){case"link":return r.createElement(p,{item:t});case"category":return r.createElement(d,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function h(e){let{className:t}=e;const n=(0,i.jA)();return r.createElement(y,{items:n.items,className:t})}function y(e){const{items:t,className:n}=e;if(!t)return r.createElement(h,e);const o=(0,i.MN)(t);return r.createElement("section",{className:(0,a.Z)("row",n)},o.map(((e,t)=>r.createElement("article",{key:t,className:"col col--6 margin-bottom--lg"},r.createElement(f,{item:e})))))}},4252:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>p,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var r=n(7462),a=(n(7294),n(3905)),i=n(2991);const o={sidebar_position:2},l="Manual",c={unversionedId:"installation/manual/index",id:"installation/manual/index",title:"Manual",description:"The documentation of this method is being written right now. We recommend using helm installation.",source:"@site/docs/installation/manual/index.md",sourceDirName:"installation/manual",slug:"/installation/manual/",permalink:"/opentwins/docs/installation/manual/",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual/index.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Helm",permalink:"/opentwins/docs/installation/using-helm"},next:{title:"DT definition and monitoring (required)",permalink:"/opentwins/docs/installation/manual/essential"}},s={},u=[],m={toc:u},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"manual"},"Manual"),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"The documentation of this method is being written right now. We recommend using ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/using-helm"},"helm installation"),".")),(0,a.kt)("p",null,"This section will explain how to deploy the platform manually. Basically, you will have to deploy or install the different components and then connect them. The procedure explained below is the one followed to deploy them in ",(0,a.kt)("strong",{parentName:"p"},"Kubernetes")," using in most cases the ",(0,a.kt)("strong",{parentName:"p"},"Helm")," option, but any other installation in which all the components are correctly installed and there is some kind of network between them to be able to communicate can be used. "),(0,a.kt)("p",null,"It is not necessary to deploy all components if not all functionalities are to be used. Check the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture"},"architecture")," section to find out which ones are essential and what functionality is covered by each of them."),(0,a.kt)("p",null,"Follow the instructions for the features you want to include in OpenTwins:"),(0,a.kt)(i.Z,{className:"DocCardList--no-description",mdxType:"DocCardList"}))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1ba72f0d.aa79666e.js b/assets/js/1ba72f0d.da232385.js similarity index 79% rename from assets/js/1ba72f0d.aa79666e.js rename to assets/js/1ba72f0d.da232385.js index 279783d..fe1839a 100644 --- a/assets/js/1ba72f0d.aa79666e.js +++ b/assets/js/1ba72f0d.da232385.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8906],{531:e=>{e.exports=JSON.parse('{"title":"Installation","description":"There are two ways of installation, you can use helm, the easiest way of deployment or you can install every single component manually.","slug":"/category/installation","permalink":"/opentwins/docs/category/installation","navigation":{"previous":{"title":"Architecture","permalink":"/opentwins/docs/overview/architecture"},"next":{"title":"Requirements","permalink":"/opentwins/docs/installation/requirements"}}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8906],{531:e=>{e.exports=JSON.parse('{"title":"Installation","description":"There are two ways of installation, you can use helm, the easiest way of deployment or you can install every single component manually.","slug":"/category/installation","permalink":"/opentwins/docs/category/installation","navigation":{"previous":{"title":"Architecture","permalink":"/opentwins/docs/overview/architecture"},"next":{"title":"Helm","permalink":"/opentwins/docs/installation/using-helm"}}}')}}]); \ No newline at end of file diff --git a/assets/js/26bc6599.3b7fe1d7.js b/assets/js/26bc6599.3b7fe1d7.js deleted file mode 100644 index 1e4f2b9..0000000 --- a/assets/js/26bc6599.3b7fe1d7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1683],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>h});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),c=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(a),m=i,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||r;return a?n.createElement(h,o(o({ref:t},u),{},{components:a})):n.createElement(h,o({ref:t},u))}));function h(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{a.d(t,{Z:()=>o});var n=a(7294),i=a(6010);const r={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:a,className:o}=e;return n.createElement("div",{role:"tabpanel",className:(0,i.Z)(r.tabItem,o),hidden:a},t)}},5488:(e,t,a)=>{a.d(t,{Z:()=>d});var n=a(7462),i=a(7294),r=a(6010),o=a(2389),l=a(7392),s=a(7094),c=a(2466);const u={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function p(e){const{lazy:t,block:a,defaultValue:o,values:p,groupId:d,className:m}=e,h=i.Children.map(e.children,(e=>{if((0,i.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),b=p??h.map((e=>{let{props:{value:t,label:a,attributes:n}}=e;return{value:t,label:a,attributes:n}})),f=(0,l.l)(b,((e,t)=>e.value===t.value));if(f.length>0)throw new Error(`Docusaurus error: Duplicate values "${f.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const y=null===o?o:o??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==y&&!b.some((e=>e.value===y)))throw new Error(`Docusaurus error: The has a defaultValue "${y}" but none of its children has the corresponding value. Available values are: ${b.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:g,setTabGroupChoices:w}=(0,s.U)(),[k,v]=(0,i.useState)(y),T=[],{blockElementScrollPositionUntilNextRender:A}=(0,c.o5)();if(null!=d){const e=g[d];null!=e&&e!==k&&b.some((t=>t.value===e))&&v(e)}const D=e=>{const t=e.currentTarget,a=T.indexOf(t),n=b[a].value;n!==k&&(A(t),v(n),null!=d&&w(d,String(n)))},E=e=>{let t=null;switch(e.key){case"Enter":D(e);break;case"ArrowRight":{const a=T.indexOf(e.currentTarget)+1;t=T[a]??T[0];break}case"ArrowLeft":{const a=T.indexOf(e.currentTarget)-1;t=T[a]??T[T.length-1];break}}t?.focus()};return i.createElement("div",{className:(0,r.Z)("tabs-container",u.tabList)},i.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.Z)("tabs",{"tabs--block":a},m)},b.map((e=>{let{value:t,label:a,attributes:o}=e;return i.createElement("li",(0,n.Z)({role:"tab",tabIndex:k===t?0:-1,"aria-selected":k===t,key:t,ref:e=>T.push(e),onKeyDown:E,onClick:D},o,{className:(0,r.Z)("tabs__item",u.tabItem,o?.className,{"tabs__item--active":k===t})}),a??t)}))),t?(0,i.cloneElement)(h.filter((e=>e.props.value===k))[0],{className:"margin-top--md"}):i.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,i.cloneElement)(e,{key:t,hidden:e.props.value!==k})))))}function d(e){const t=(0,o.Z)();return i.createElement(p,(0,n.Z)({key:String(t)},e))}},8151:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>c,toc:()=>p});var n=a(7462),i=(a(7294),a(3905)),r=a(5488),o=a(5162);const l={sidebar_position:1},s="Create a type",c={unversionedId:"guides/type-creation",id:"guides/type-creation",title:"Create a type",description:"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.",source:"@site/docs/guides/type-creation.mdx",sourceDirName:"guides",slug:"/guides/type-creation",permalink:"/opentwins/docs/guides/type-creation",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/type-creation.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Guides",permalink:"/opentwins/docs/category/guides"},next:{title:"Create a digital twin",permalink:"/opentwins/docs/guides/dt-schema-creation"}},u={},p=[],d={toc:p},m="wrapper";function h(e){let{components:t,...l}=e;return(0,i.kt)(m,(0,n.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"create-a-type"},"Create a type"),(0,i.kt)("p",null,"The way to interact with ",(0,i.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/index.html"},"Eclipse Ditto")," and therefore create not only digital twins, but connections, etc. is through http requests and methods.\nAlthough the graphical interface of OpenTwins makes it unnecessary to go so low level, the option to communicate directly with Eclipse Ditto is still available."),(0,i.kt)(r.Z,{className:"unique-tabs",defaultValue:"ui",values:[{label:"Using Grafana interface",value:"ui"},{label:"Using http methods",value:"http"}],mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"ui",mdxType:"TabItem"},(0,i.kt)("p",null,"As explained in TWINS WIP, OpenTwins has two types of DT schemas. One for creating a single DT and other for creating a type to create multiple instances of a DT."),(0,i.kt)("p",null,'To create a new DT type using OpenTwins plugin in Grafana, just select "Create new type in" button in "Types" tab.\n',(0,i.kt)("img",{alt:"CreateType",src:a(9877).Z,width:"180",height:"44"})),(0,i.kt)("p",null,"A new window with a form that will define the DT and a viewer of the produced JSON schema will have appeared."),(0,i.kt)("p",null,"The first required information is the identification of the twin. There are two required field."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Namespace: Is the name of the context to which the type belongs."),(0,i.kt)("li",{parentName:"ul"},"ID: This must be unique within the scope of the type. The name of the type will precede it automatically.")),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Identification",src:a(7615).Z,width:"945",height:"248"})),(0,i.kt)("p",null,"Next is type information. This basic static information about the type for description. There are several fields, but just one is required:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Policy* : We must select a policy."),(0,i.kt)("li",{parentName:"ul"},"Name."),(0,i.kt)("li",{parentName:"ul"},"Description."),(0,i.kt)("li",{parentName:"ul"},"Image: You can paste a image url to show in the type information.")),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Information",src:a(1753).Z,width:"949",height:"369"})),(0,i.kt)("p",null,'In addition to the above information, new custom attributes can be defined, normally used as static information. By simply filling in the attribute name and its value, click on the "add" button to add a new attribute.'),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Attributes",src:a(2632).Z,width:"913",height:"271"})),(0,i.kt)("p",null,'Finally, the features section is used to create the variables to be collected by the DT. Simply type the name and click on the "add" button. This will add a new variable to the twin schema.'),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Features",src:a(5322).Z,width:"819",height:"176"})),(0,i.kt)("p",null,"An example of a schema of a DT of an abstract vehicle can be seen in the following JSON:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-JSON"},'{\n "thingId": "benchmark:vehicle",\n "policyId": "default:basic_policy",\n "attributes": {\n "name": "Vehicle",\n "description": "Vehicle type for generating new vehicles.",\n "image": "ImageLink",\n "Brand": "EMPTY",\n "Subtype": "EMPTY"\n },\n "features": {\n "wheels": {\n "properties": {\n "value": null\n }\n },\n "power": {\n "properties": {\n "value": null\n }\n },\n "capacity": {\n "properties": {\n "value": null\n }\n }\n }\n}\n\n'))),(0,i.kt)(o.Z,{value:"http",mdxType:"TabItem"},(0,i.kt)("h1",{id:"creation-using-http-requests"},"Creation using HTTP requests"))))}h.isMDXComponent=!0},2632:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/attributes-688b657151e36d377dc0d544f3595183.png"},9877:(e,t,a)=>{a.d(t,{Z:()=>n});const n="data:image/png;base64,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"},5322:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/typefeatures-2a5e13e806e5325654279e12fdb308f1.png"},7615:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/typeidentification-5f59909ac0a9fbb0943ecd69cea3eb57.png"},1753:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/typeinformation-eeeec38f1c25299e252141768dac756a.png"}}]); \ No newline at end of file diff --git a/assets/js/29451ac5.30e26a3b.js b/assets/js/29451ac5.30e26a3b.js new file mode 100644 index 0000000..e71b557 --- /dev/null +++ b/assets/js/29451ac5.30e26a3b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8040],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});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 r(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 o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=i,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||r;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{n.d(t,{Z:()=>o});var a=n(7294),i=n(6010);const r={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:n,className:o}=e;return a.createElement("div",{role:"tabpanel",className:(0,i.Z)(r.tabItem,o),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>d});var a=n(7462),i=n(7294),r=n(6010),o=n(2389),l=n(7392),s=n(7094),c=n(2466);const u={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function p(e){const{lazy:t,block:n,defaultValue:o,values:p,groupId:d,className:m}=e,h=i.Children.map(e.children,(e=>{if((0,i.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=p??h.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),b=(0,l.l)(f,((e,t)=>e.value===t.value));if(b.length>0)throw new Error(`Docusaurus error: Duplicate values "${b.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const y=null===o?o:o??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==y&&!f.some((e=>e.value===y)))throw new Error(`Docusaurus error: The has a defaultValue "${y}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:g,setTabGroupChoices:w}=(0,s.U)(),[k,v]=(0,i.useState)(y),T=[],{blockElementScrollPositionUntilNextRender:A}=(0,c.o5)();if(null!=d){const e=g[d];null!=e&&e!==k&&f.some((t=>t.value===e))&&v(e)}const D=e=>{const t=e.currentTarget,n=T.indexOf(t),a=f[n].value;a!==k&&(A(t),v(a),null!=d&&w(d,String(a)))},E=e=>{let t=null;switch(e.key){case"Enter":D(e);break;case"ArrowRight":{const n=T.indexOf(e.currentTarget)+1;t=T[n]??T[0];break}case"ArrowLeft":{const n=T.indexOf(e.currentTarget)-1;t=T[n]??T[T.length-1];break}}t?.focus()};return i.createElement("div",{className:(0,r.Z)("tabs-container",u.tabList)},i.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:o}=e;return i.createElement("li",(0,a.Z)({role:"tab",tabIndex:k===t?0:-1,"aria-selected":k===t,key:t,ref:e=>T.push(e),onKeyDown:E,onClick:D},o,{className:(0,r.Z)("tabs__item",u.tabItem,o?.className,{"tabs__item--active":k===t})}),n??t)}))),t?(0,i.cloneElement)(h.filter((e=>e.props.value===k))[0],{className:"margin-top--md"}):i.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,i.cloneElement)(e,{key:t,hidden:e.props.value!==k})))))}function d(e){const t=(0,o.Z)();return i.createElement(p,(0,a.Z)({key:String(t)},e))}},8747:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>c,toc:()=>p});var a=n(7462),i=(n(7294),n(3905)),r=n(5488),o=n(5162);const l={sidebar_position:1},s="Create a type",c={unversionedId:"guides/definition/type-creation",id:"guides/definition/type-creation",title:"Create a type",description:"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.",source:"@site/docs/guides/definition/type-creation.mdx",sourceDirName:"guides/definition",slug:"/guides/definition/type-creation",permalink:"/opentwins/docs/guides/definition/type-creation",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/definition/type-creation.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"DT definition",permalink:"/opentwins/docs/category/dt-definition"},next:{title:"Create a digital twin",permalink:"/opentwins/docs/guides/definition/dt-schema-creation"}},u={},p=[],d={toc:p},m="wrapper";function h(e){let{components:t,...l}=e;return(0,i.kt)(m,(0,a.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"create-a-type"},"Create a type"),(0,i.kt)("p",null,"The way to interact with ",(0,i.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/index.html"},"Eclipse Ditto")," and therefore create not only digital twins, but connections, etc. is through http requests and methods.\nAlthough the graphical interface of OpenTwins makes it unnecessary to go so low level, the option to communicate directly with Eclipse Ditto is still available."),(0,i.kt)(r.Z,{className:"unique-tabs",defaultValue:"ui",values:[{label:"Using Grafana interface",value:"ui"},{label:"Using http methods",value:"http"}],mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"ui",mdxType:"TabItem"},(0,i.kt)("p",null,"As explained in TWINS WIP, OpenTwins has two types of DT schemas. One for creating a single DT and other for creating a type to create multiple instances of a DT."),(0,i.kt)("p",null,'To create a new DT type using OpenTwins plugin in Grafana, just select "Create new type in" button in "Types" tab.\n',(0,i.kt)("img",{alt:"CreateType",src:n(9861).Z,width:"180",height:"44"})),(0,i.kt)("p",null,"A new window with a form that will define the DT and a viewer of the produced JSON schema will have appeared."),(0,i.kt)("p",null,"The first required information is the identification of the twin. There are two required field."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Namespace: Is the name of the context to which the type belongs."),(0,i.kt)("li",{parentName:"ul"},"ID: This must be unique within the scope of the type. The name of the type will precede it automatically.")),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Identification",src:n(8282).Z,width:"945",height:"248"})),(0,i.kt)("p",null,"Next is type information. This basic static information about the type for description. There are several fields, but just one is required:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Policy* : We must select a policy."),(0,i.kt)("li",{parentName:"ul"},"Name."),(0,i.kt)("li",{parentName:"ul"},"Description."),(0,i.kt)("li",{parentName:"ul"},"Image: You can paste a image url to show in the type information.")),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Information",src:n(9869).Z,width:"949",height:"369"})),(0,i.kt)("p",null,'In addition to the above information, new custom attributes can be defined, normally used as static information. By simply filling in the attribute name and its value, click on the "add" button to add a new attribute.'),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Attributes",src:n(3995).Z,width:"913",height:"271"})),(0,i.kt)("p",null,'Finally, the features section is used to create the variables to be collected by the DT. Simply type the name and click on the "add" button. This will add a new variable to the twin schema.'),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Features",src:n(1553).Z,width:"819",height:"176"})),(0,i.kt)("p",null,"An example of a schema of a DT of an abstract vehicle can be seen in the following JSON:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-JSON"},'{\n "thingId": "benchmark:vehicle",\n "policyId": "default:basic_policy",\n "attributes": {\n "name": "Vehicle",\n "description": "Vehicle type for generating new vehicles.",\n "image": "ImageLink",\n "Brand": "EMPTY",\n "Subtype": "EMPTY"\n },\n "features": {\n "wheels": {\n "properties": {\n "value": null\n }\n },\n "power": {\n "properties": {\n "value": null\n }\n },\n "capacity": {\n "properties": {\n "value": null\n }\n }\n }\n}\n\n'))),(0,i.kt)(o.Z,{value:"http",mdxType:"TabItem"},(0,i.kt)("h1",{id:"creation-using-http-requests"},"Creation using HTTP requests"))))}h.isMDXComponent=!0},3995:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/attributes-688b657151e36d377dc0d544f3595183.png"},9861:(e,t,n)=>{n.d(t,{Z:()=>a});const a="data:image/png;base64,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"},1553:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/typefeatures-2a5e13e806e5325654279e12fdb308f1.png"},8282:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/typeidentification-5f59909ac0a9fbb0943ecd69cea3eb57.png"},9869:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/typeinformation-eeeec38f1c25299e252141768dac756a.png"}}]); \ No newline at end of file diff --git a/assets/js/402d2e48.4e83c139.js b/assets/js/402d2e48.4e83c139.js deleted file mode 100644 index 885ffb8..0000000 --- a/assets/js/402d2e48.4e83c139.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5176],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});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 r(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 l(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=p(n),c=i,k=u["".concat(s,".").concat(c)]||u[c]||m[c]||r;return n?a.createElement(k,l(l({ref:t},d),{},{components:n})):a.createElement(k,l({ref:t},d))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:i,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:3},l="API Documentation",o={unversionedId:"fmi/API",id:"fmi/API",title:"API Documentation",description:"Welcome to the Example API documentation. This API allows developers to interact with our services easily and efficiently.",source:"@site/docs/fmi/API.md",sourceDirName:"fmi",slug:"/fmi/API",permalink:"/opentwins/docs/fmi/API",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/fmi/API.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"FMI Simulation concepts",permalink:"/opentwins/docs/fmi/concepts"}},s={},p=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"Introduction",id:"introduction",level:2},{value:"Endpoints",id:"endpoints",level:2},{value:"FMU endpoints",id:"fmu-endpoints",level:3},{value:"1. GET /{context}",id:"1-get-context",level:4},{value:"Description",id:"description",level:5},{value:"Request",id:"request",level:5},{value:"Response",id:"response",level:5},{value:"2. POST /{context}",id:"2-post-context",level:4},{value:"Description",id:"description-1",level:5},{value:"Request",id:"request-1",level:5},{value:"Response",id:"response-1",level:5},{value:"3. GET /{context}/{fmuName}",id:"3-get-contextfmuname",level:4},{value:"Description",id:"description-2",level:5},{value:"Request",id:"request-2",level:5},{value:"Response",id:"response-2",level:5},{value:"4. DELETE /{context}/{fmuName}",id:"4-delete-contextfmuname",level:4},{value:"Description",id:"description-3",level:5},{value:"Request",id:"request-3",level:5},{value:"Response",id:"response-3",level:5},{value:"Schema endpoints",id:"schema-endpoints",level:3},{value:"1. GET /{context}",id:"1-get-context-1",level:4},{value:"Description",id:"description-4",level:5},{value:"Request",id:"request-4",level:5},{value:"Response",id:"response-4",level:5},{value:"2. POST /{context}",id:"2-post-context-1",level:4},{value:"Description",id:"description-5",level:5},{value:"Request",id:"request-5",level:5},{value:"Response",id:"response-5",level:5},{value:"3. GET /{context}/{schema_id}",id:"3-get-contextschema_id",level:4},{value:"Description",id:"description-6",level:5},{value:"Request",id:"request-6",level:5},{value:"Response",id:"response-6",level:5},{value:"4. DELETE /{context}/{schema_id}",id:"4-delete-contextschema_id",level:4},{value:"Description",id:"description-7",level:5},{value:"Request",id:"request-7",level:5},{value:"Response",id:"response-7",level:5},{value:"Simulation endpoints",id:"simulation-endpoints",level:3},{value:"1. GET /{context}",id:"1-get-context-2",level:4},{value:"Description",id:"description-8",level:5},{value:"Request",id:"request-8",level:5},{value:"Response",id:"response-8",level:5},{value:"2. POST /{context}",id:"2-post-context-2",level:4},{value:"Description",id:"description-9",level:5},{value:"Request",id:"request-9",level:5},{value:"Response",id:"response-9",level:5},{value:"3. GET /{context}/{simulation_id}",id:"3-get-contextsimulation_id",level:4},{value:"Description",id:"description-10",level:5},{value:"Request",id:"request-10",level:5},{value:"Response",id:"response-10",level:5},{value:"4. DELETE /{context}/{simulation_id}",id:"4-delete-contextsimulation_id",level:4},{value:"Description",id:"description-11",level:5},{value:"Request",id:"request-11",level:5},{value:"Response",id:"response-11",level:5},{value:"5. POST /{context}/{simulation_id}/resume",id:"5-post-contextsimulation_idresume",level:4},{value:"Description",id:"description-12",level:5},{value:"Request",id:"request-12",level:5},{value:"Response",id:"response-12",level:5},{value:"6. POST /{context}/{simulation_id}/pause",id:"6-post-contextsimulation_idpause",level:4},{value:"Description",id:"description-13",level:5},{value:"Request",id:"request-13",level:5},{value:"Response",id:"response-13",level:5}],d={toc:p},u="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"api-documentation"},"API Documentation"),(0,i.kt)("p",null,"Welcome to the Example API documentation. This API allows developers to interact with our services easily and efficiently."),(0,i.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#endpoints"},"Endpoints"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#fmu-endpoints"},"FMU endpoints")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#schema-endpoints"},"Schema endpoints")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#simulation-endpoints"},"Simulation endpoints"))))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"This API provides access to FMU data and allows for the creation and management of simulation schemas and simulations. It is based on REST and returns responses in JSON format."),(0,i.kt)("h2",{id:"endpoints"},"Endpoints"),(0,i.kt)("h3",{id:"fmu-endpoints"},"FMU endpoints"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Endpoint /fmi/fmus"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#1-get-context"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a list of FMUs")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#2-post-context"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Upload a new FMU")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#3-get-contextfmuname"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{fmuName}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve FMU information within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#4-delete-contextfmuname"},"DELETE")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{fmuName}"),(0,i.kt)("td",{parentName:"tr",align:null},"Delete a FMU within a context")))),(0,i.kt)("h4",{id:"1-get-context"},"1. GET /{context}"),(0,i.kt)("h5",{id:"description"},"Description"),(0,i.kt)("p",null,"Get a list of FMUs in a specific context."),(0,i.kt)("h5",{id:"request"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of FMUs with information about their variables."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": "bouncingBallCS2",\n "inputs": [],\n "outputs": [],\n "other_variables": [\n {\n "name": "h",\n "type": "Real",\n "default": {\n "start": "1"\n },\n "description": "height, used as state"\n },\n {\n "name": "v",\n "type": "Real",\n "default": {\n "start": "0",\n "reinit": "true"\n },\n "description": "velocity of ball, used as state"\n },\n {\n "name": "g",\n "type": "Real",\n "default": {\n "start": "9.81"\n },\n "description": "acceleration of gravity"\n },\n {\n "name": "e",\n "type": "Real",\n "default": {\n "start": "0.7",\n "min": "0.5",\n "max": "1"\n },\n "description": "dimensionless parameter"\n }\n ]\n }\n]\n')),(0,i.kt)("h4",{id:"2-post-context"},"2. POST /{context}"),(0,i.kt)("h5",{id:"description-1"},"Description"),(0,i.kt)("p",null,"Upload a new FMU to the sistem into a specific context."),(0,i.kt)("h5",{id:"request-1"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-1"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"FMU uploaded succesfully"\n')),(0,i.kt)("h4",{id:"3-get-contextfmuname"},"3. GET /{context}/{fmuName}"),(0,i.kt)("h5",{id:"description-2"},"Description"),(0,i.kt)("p",null,"Get the XML file of a specific FMU."),(0,i.kt)("h5",{id:"request-2"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{fmuName}")),(0,i.kt)("h5",{id:"response-2"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-xml"},'\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n')),(0,i.kt)("h4",{id:"4-delete-contextfmuname"},"4. DELETE /{context}/{fmuName}"),(0,i.kt)("h5",{id:"description-3"},"Description"),(0,i.kt)("p",null,"Delete a FMU from the sistem in a specific context."),(0,i.kt)("h5",{id:"request-3"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DELETE"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{fmuName}")),(0,i.kt)("h5",{id:"response-3"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"FMU deleted succesfully"\n')),(0,i.kt)("hr",null),(0,i.kt)("h3",{id:"schema-endpoints"},"Schema endpoints"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Endpoint /fmi/schemas"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#1-get-context-1"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a list of schemas")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#2-post-context-1"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Upload a new schema")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#3-get-contextschema_id"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{schema_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a schema within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#4-delete-contextschema_id"},"DELETE")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{schema_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Delete a schema within a context")))),(0,i.kt)("h4",{id:"1-get-context-1"},"1. GET /{context}"),(0,i.kt)("h5",{id:"description-4"},"Description"),(0,i.kt)("p",null,"Get all simulation schemas in a specific context."),(0,i.kt)("h5",{id:"request-4"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-4"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of name and id of every single simulation schemas."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": "schema1",\n "name": "Schema 1"\n }\n]\n')),(0,i.kt)("h4",{id:"2-post-context-1"},"2. POST /{context}"),(0,i.kt)("h5",{id:"description-5"},"Description"),(0,i.kt)("p",null,"Create a new schema in a specific context."),(0,i.kt)("h5",{id:"request-5"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-5"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of name and id of every single simulation schemas."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"Schema created succesfully"\n')),(0,i.kt)("h4",{id:"3-get-contextschema_id"},"3. GET /{context}/{schema_id}"),(0,i.kt)("h5",{id:"description-6"},"Description"),(0,i.kt)("p",null,"Get a schema in a specific context."),(0,i.kt)("h5",{id:"request-6"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{schema_id}")),(0,i.kt)("h5",{id:"response-6"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": "schema2",\n "fmus": [\n {\n "id": "Controller",\n "inputs": [\n {\n "id": "u_s"\n },\n {\n "id": "u_m"\n }\n ],\n "outputs": [\n {\n "id": "y"\n }\n ]\n },\n {\n "id": "Drivetrain",\n "inputs": [\n {\n "id": "tau"\n }\n ],\n "outputs": [\n {\n "id": "w"\n }\n ]\n }\n ],\n "name": "Schema 2",\n "schema": [\n {\n "to": {\n "id": "Controller",\n "var": "u_s"\n },\n "from": {\n "var": "w_ref"\n }\n },\n {\n "to": {\n "id": "Controller",\n "var": "u_m"\n },\n "from": {\n "id": "Drivetrain",\n "var": "w"\n }\n },\n {\n "to": {\n "id": "Drivetrain",\n "var": "tau"\n },\n "from": {\n "id": "Controller",\n "var": "y"\n }\n },\n {\n "to": {\n "var": "w"\n },\n "from": {\n "id": "Drivetrain",\n "var": "w"\n }\n }\n ],\n "description": "Testing schema",\n "relatedTwins": [\n "Twin1"\n ]\n }\n]\n')),(0,i.kt)("h4",{id:"4-delete-contextschema_id"},"4. DELETE /{context}/{schema_id}"),(0,i.kt)("h5",{id:"description-7"},"Description"),(0,i.kt)("p",null,"Delete a schema in a specific context."),(0,i.kt)("h5",{id:"request-7"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DELETE"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{schema_id}")),(0,i.kt)("h5",{id:"response-7"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"Schema deleted succesfully"\n')),(0,i.kt)("hr",null),(0,i.kt)("h3",{id:"simulation-endpoints"},"Simulation endpoints"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Endpoint /fmi/simulations"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#1-get-context-2"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a list of running simulations")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#2-post-context-2"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Deploy simulation")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#3-get-contextsimulation_id"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve simulation info within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#4-delete-contextsimulation_id"},"DELETE")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Delete a simulation within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#5-post-contextsimulation_idresume"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}/resume"),(0,i.kt)("td",{parentName:"tr",align:null},"Resume a specific simulation")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#6-post-contextsimulation_idpause"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}/pause"),(0,i.kt)("td",{parentName:"tr",align:null},"Stops a specific simulation")))),(0,i.kt)("h4",{id:"1-get-context-2"},"1. GET /{context}"),(0,i.kt)("h5",{id:"description-8"},"Description"),(0,i.kt)("p",null,"Get all running simulations in a specific context."),(0,i.kt)("h5",{id:"request-8"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-8"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of information of every single running simulations."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'\n[\n {\n "schema-id": "schema1",\n "simulation-id": "pruebabouncingball",\n "namespace": "opentwins",\n "type": "one-time",\n "status": "Active",\n "pods": [\n {\n "simulation-id": "pruebabouncingball",\n "phase": "Running",\n "status": false,\n "creation_timestamp": "2024/09/26, 03:06:06+0000"\n }\n ]\n }\n]\n\n')),(0,i.kt)("h4",{id:"2-post-context-2"},"2. POST /{context}"),(0,i.kt)("h5",{id:"description-9"},"Description"),(0,i.kt)("p",null,"Create a new simulation using a existing schema in a specific context."),(0,i.kt)("h5",{id:"request-9"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-9"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"true"\n')),(0,i.kt)("h4",{id:"3-get-contextsimulation_id"},"3. GET /{context}/{simulation_id}"),(0,i.kt)("h5",{id:"description-10"},"Description"),(0,i.kt)("p",null,"Get all information about a specific simulation in a specific context."),(0,i.kt)("h5",{id:"request-10"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}")),(0,i.kt)("h5",{id:"response-10"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "api_version": "batch/v1",\n "kind": "Job",\n "metadata": {\n "annotations": null,\n "creation_timestamp": "2024-09-26 03:06:06+00:00",\n "deletion_grace_period_seconds": null,\n "deletion_timestamp": null,\n .\n .\n .\n }\n}\n')),(0,i.kt)("h4",{id:"4-delete-contextsimulation_id"},"4. DELETE /{context}/{simulation_id}"),(0,i.kt)("h5",{id:"description-11"},"Description"),(0,i.kt)("p",null,"Delete specific simulation in a specific context."),(0,i.kt)("h5",{id:"request-11"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DELETE"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}")),(0,i.kt)("h5",{id:"response-11"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"Schema deleted succesfully"\n')),(0,i.kt)("h4",{id:"5-post-contextsimulation_idresume"},"5. POST /{context}/{simulation_id}/resume"),(0,i.kt)("h5",{id:"description-12"},"Description"),(0,i.kt)("p",null,"Resume paused simulation in a specific context."),(0,i.kt)("h5",{id:"request-12"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}/resume")),(0,i.kt)("h5",{id:"response-12"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK")," "),(0,i.kt)("h4",{id:"6-post-contextsimulation_idpause"},"6. POST /{context}/{simulation_id}/pause"),(0,i.kt)("h5",{id:"description-13"},"Description"),(0,i.kt)("p",null,"Pause simulation in a specific context."),(0,i.kt)("h5",{id:"request-13"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}/pause")),(0,i.kt)("h5",{id:"response-13"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/40b0d055.4e4684a7.js b/assets/js/40b0d055.60ffe9ac.js similarity index 88% rename from assets/js/40b0d055.4e4684a7.js rename to assets/js/40b0d055.60ffe9ac.js index 97e759b..5d57255 100644 --- a/assets/js/40b0d055.4e4684a7.js +++ b/assets/js/40b0d055.60ffe9ac.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1144],{4282:e=>{e.exports=JSON.parse('{"title":"Overview","description":"Here you will find detailed information about the purpose of the platform, the key concepts that are important to understand and how it works internally.","slug":"/category/overview","permalink":"/opentwins/docs/category/overview","navigation":{"previous":{"title":"Quickstart","permalink":"/opentwins/docs/quickstart"},"next":{"title":"Purpose","permalink":"/opentwins/docs/overview/purpose"}}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1144],{8151:e=>{e.exports=JSON.parse('{"title":"Overview","description":"Here you will find detailed information about the purpose of the platform, the key concepts that are important to understand and how it works internally.","slug":"/category/overview","permalink":"/opentwins/docs/category/overview","navigation":{"previous":{"title":"Quickstart","permalink":"/opentwins/docs/quickstart"},"next":{"title":"Purpose","permalink":"/opentwins/docs/overview/purpose"}}}')}}]); \ No newline at end of file diff --git a/assets/js/47986192.13f6acda.js b/assets/js/47986192.13f6acda.js new file mode 100644 index 0000000..777a948 --- /dev/null +++ b/assets/js/47986192.13f6acda.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[301],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>f});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=r.createContext({}),s=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=s(e.components);return r.createElement(c.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(t),d=a,f=p["".concat(c,".").concat(d)]||p[d]||m[d]||i;return t?r.createElement(f,o(o({ref:n},u),{},{components:t})):r.createElement(f,o({ref:n},u))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=d;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[p]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=t(7462),a=(t(7294),t(3905));const i={sidebar_position:3},o="Machine Learning",l={unversionedId:"installation/manual/machine-learning",id:"installation/manual/machine-learning",title:"Machine Learning",description:"Prerequisites",source:"@site/docs/installation/manual/machine-learning.md",sourceDirName:"installation/manual",slug:"/installation/manual/machine-learning",permalink:"/opentwins/docs/installation/manual/machine-learning",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual/machine-learning.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Composition (recommended)",permalink:"/opentwins/docs/installation/manual/composition"},next:{title:"Simulations",permalink:"/opentwins/docs/installation/manual/simulations"}},c={},s=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Deploy",id:"deploy",level:2},{value:"Connect",id:"connect",level:2}],u={toc:s},p="wrapper";function m(e){let{components:n,...t}=e;return(0,a.kt)(p,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"machine-learning"},"Machine Learning"),(0,a.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("h2",{id:"deploy"},"Deploy"),(0,a.kt)("h2",{id:"connect"},"Connect"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4899252d.b3e32514.js b/assets/js/4899252d.b3e32514.js deleted file mode 100644 index 07b120c..0000000 --- a/assets/js/4899252d.b3e32514.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1368],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function o(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 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||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=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=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=o,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||i;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var c=2;c{n.d(t,{Z:()=>r});var a=n(7294),o=n(6010);const i={tabItem:"tabItem_Ymn6"};function r(e){let{children:t,hidden:n,className:r}=e;return a.createElement("div",{role:"tabpanel",className:(0,o.Z)(i.tabItem,r),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>u});var a=n(7462),o=n(7294),i=n(6010),r=n(2389),s=n(7392),l=n(7094),c=n(2466);const p={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function d(e){const{lazy:t,block:n,defaultValue:r,values:d,groupId:u,className:m}=e,h=o.Children.map(e.children,(e=>{if((0,o.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=d??h.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),g=(0,s.l)(f,((e,t)=>e.value===t.value));if(g.length>0)throw new Error(`Docusaurus error: Duplicate values "${g.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const k=null===r?r:r??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==k&&!f.some((e=>e.value===k)))throw new Error(`Docusaurus error: The has a defaultValue "${k}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:v,setTabGroupChoices:b}=(0,l.U)(),[y,N]=(0,o.useState)(k),w=[],{blockElementScrollPositionUntilNextRender:_}=(0,c.o5)();if(null!=u){const e=v[u];null!=e&&e!==y&&f.some((t=>t.value===e))&&N(e)}const T=e=>{const t=e.currentTarget,n=w.indexOf(t),a=f[n].value;a!==y&&(_(t),N(a),null!=u&&b(u,String(a)))},E=e=>{let t=null;switch(e.key){case"Enter":T(e);break;case"ArrowRight":{const n=w.indexOf(e.currentTarget)+1;t=w[n]??w[0];break}case"ArrowLeft":{const n=w.indexOf(e.currentTarget)-1;t=w[n]??w[w.length-1];break}}t?.focus()};return o.createElement("div",{className:(0,i.Z)("tabs-container",p.tabList)},o.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:r}=e;return o.createElement("li",(0,a.Z)({role:"tab",tabIndex:y===t?0:-1,"aria-selected":y===t,key:t,ref:e=>w.push(e),onKeyDown:E,onClick:T},r,{className:(0,i.Z)("tabs__item",p.tabItem,r?.className,{"tabs__item--active":y===t})}),n??t)}))),t?(0,o.cloneElement)(h.filter((e=>e.props.value===y))[0],{className:"margin-top--md"}):o.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,o.cloneElement)(e,{key:t,hidden:e.props.value!==y})))))}function u(e){const t=(0,r.Z)();return o.createElement(d,(0,a.Z)({key:String(t)},e))}},637:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>c,toc:()=>d});var a=n(7462),o=(n(7294),n(3905)),i=n(5488),r=n(5162);const s={sidebar_position:3},l="Manual",c={unversionedId:"installation/manual",id:"installation/manual",title:"Manual",description:"The documentation of this method is being written right now. We recommend using helm installation.",source:"@site/docs/installation/manual.md",sourceDirName:"installation",slug:"/installation/manual",permalink:"/opentwins/docs/installation/manual",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Helm",permalink:"/opentwins/docs/installation/using-helm"},next:{title:"Guides",permalink:"/opentwins/docs/category/guides"}},p={},d=[{value:"Essential functionality",id:"essential-functionality",level:2},{value:"Deploy",id:"deploy",level:3},{value:"MongoDB v6.0",id:"mongodb-v60",level:4},{value:"Eclipse Ditto v3.3",id:"eclipse-ditto-v33",level:4},{value:"InfluxDB v2",id:"influxdb-v2",level:4},{value:"Mosquitto v2.0",id:"mosquitto-v20",level:4},{value:"Apache Kafka v3.4",id:"apache-kafka-v34",level:4},{value:"Grafana v9.5",id:"grafana-v95",level:4},{value:"Eclipse Hono v2.4",id:"eclipse-hono-v24",level:4},{value:"Connect",id:"connect",level:3},{value:"Eclipse Ditto and InfluxDB",id:"eclipse-ditto-and-influxdb",level:4},{value:"InfluxDB and Grafana",id:"influxdb-and-grafana",level:4},{value:"Eclipse Ditto and Eclipse Hono",id:"eclipse-ditto-and-eclipse-hono",level:4},{value:"Compositional support",id:"compositional-support",level:2},{value:"Data prediction with machine learning",id:"data-prediction-with-machine-learning",level:2},{value:"3D representation",id:"3d-representation",level:2}],u={toc:d},m="wrapper";function h(e){let{components:t,...s}=e;return(0,o.kt)(m,(0,a.Z)({},u,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"manual"},"Manual"),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"The documentation of this method is being written right now. We recommend using ",(0,o.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/using-helm"},"helm installation"),".")),(0,o.kt)("p",null,"This section will explain how to deploy the platform manually. Basically, you will have to deploy or install the different components and then connect them. The procedure explained below is the one followed to deploy them in ",(0,o.kt)("strong",{parentName:"p"},"Kubernetes")," using in most cases the ",(0,o.kt)("strong",{parentName:"p"},"Helm")," option, but any other installation in which all the components are correctly installed and there is some kind of network between them to be able to communicate can be used. "),(0,o.kt)("p",null,"It is not necessary to deploy all components if not all functionalities are to be used. Check the ",(0,o.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture"},"architecture")," section to find out which ones are essential and what functionality is covered by each of them."),(0,o.kt)("h2",{id:"essential-functionality"},"Essential functionality"),(0,o.kt)("h3",{id:"deploy"},"Deploy"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Note that the values files have the variables that we recommend for the installation of each Helm Chart, but they ",(0,o.kt)("strong",{parentName:"p"},"can be extended or modified according to your needs")," (please consult the Helm Chart documentation for each component).")),(0,o.kt)("p",null,"We recommend installing all components in the same Kubernetes namespace to make it easier to identify and control them all. In our case the namespace will be ",(0,o.kt)("em",{parentName:"p"},"opentwins"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create namespace opentwins\n")),(0,o.kt)("p",null,"We installed all the components with their Helm versions and kept most of the values in their default configuration, except for those that are important for the interconnection of the components. In addition, we configure the services as NodePort to facilitate external access and set a specific port for each one. "),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"Depending on how you have persistence configured in your cluster, you may need to deploy ",(0,o.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/"},"persistent volumes")," for MongoDB, InfluxDB and Grafana. The values for MongoDB are shown below, but they all follow the same template."),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre",className:"language-yaml"},"apiVersion: v1\nkind: PersistentVolume\nmetadata:\n name: pv-opentwins-mongodb\nspec:\n accessModes:\n - ReadWriteOnce\n capacity:\n storage: 8Gi\n hostPath:\n path: /mnt/opentwins/mongodb\n type: DirectoryOrCreate\n"))),(0,o.kt)("p",null,"Listed below are the essential components of the ",(0,o.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture"},"architecture")," along with their versions used, their Helm values and a link to the repository explaining their installation."),(0,o.kt)("h4",{id:"mongodb-v60"},"MongoDB v6.0"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://www.mongodb.com/docs/v6.0/introduction/"},"App v6.0 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/bitnami/charts/tree/main/bitnami/mongodb"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm install mongodb -n opentwins oci://registry-1.docker.io/bitnamicharts/mongodb --version 13.8.3 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"service:\n type: NodePort\n nodePorts:\n mongodb: 30717\npersistence:\n enabled: true\nvolumePermissions:\n enabled: true\nauth:\n enabled: false\n")),(0,o.kt)("h4",{id:"eclipse-ditto-v33"},"Eclipse Ditto v3.3"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://eclipse.dev/ditto/3.3/intro-overview.html"},"App v3.3 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/eclipse-ditto/ditto/tree/master/deployment/helm/ditto"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm install --dependency-update -n opentwins ditto oci://registry-1.docker.io/eclipse/ditto --version 3.3.7 --wait -f values.yaml\n")),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("ul",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ul"},"We advise not to modify any authentication configuration due to a bug in Eclipse Ditto that may cause access errors."),(0,o.kt)("li",{parentName:"ul"},"In the following values you have to replace ",(0,o.kt)("em",{parentName:"li"},"mongodb-service-name")," by the MongoDB service name"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"global:\n hashedBasicAuthUsers: false\n basicAuthUsers:\n ditto:\n user: ditto\n password: ditto\n devops:\n user: devops\n password: foobar\nnginx:\n service:\n type: NodePort\n nodePort: 30525\nswaggerui:\n enabled: false\ndittoui:\n enabled: false\nmongodb:\n enabled: false\ndbconfig:\n policies:\n uri: 'mongodb://:27017/ditto'\n things:\n uri: 'mongodb://:27017/ditto'\n connectivity:\n uri: 'mongodb://:27017/ditto'\n thingsSearch:\n uri: 'mongodb://:27017/ditto'\ngateway:\n config:\n authentication:\n enablePreAuthentication: true\n devops:\n devopsPassword: foobar\n statusPassword: foobar\n")),(0,o.kt)("h4",{id:"influxdb-v2"},"InfluxDB v2"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.influxdata.com/influxdb/v2/"},"App v2 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/influxdata/helm-charts/tree/master/charts/influxdb2"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add influxdata https://helm.influxdata.com/\nhelm repo update\nhelm install -n opentwins influxdb influxdata/influxdb2 --version 2.1.1 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"persistence:\n enabled: true\nservice:\n type: NodePort\n nodePort: 30716\nimage:\n pullPolicy: Always\n")),(0,o.kt)("h4",{id:"mosquitto-v20"},"Mosquitto v2.0"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"OpenTwins supports the use of Mosquitto and Kafka as intermediaries, but ",(0,o.kt)("strong",{parentName:"p"},"we recommend using Mosquitto")," due to its simpler configuration. Since there is no official Helm chart for Mosquitto, we have created one of our own that works fine, although there is no documentation yet. However, you can install Mosquitto in any of the ",(0,o.kt)("a",{parentName:"p",href:"https://mosquitto.org/download/"},"available ways"),".")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://mosquitto.org/documentation/"},"App documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/ertis-research/Helm-charts/blob/main/mosquitto/values.yaml"},"Helm values file"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\nhelm repo update\nhelm install mosquitto ertis/mosquitto -n opentwins --wait --dependency-update -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"service:\n type: NodePort\n nodePort: 30511\nconfiguration:\n authentication:\n enabled: false\n")),(0,o.kt)("h4",{id:"apache-kafka-v34"},"Apache Kafka v3.4"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://kafka.apache.org/34/documentation.html"},"App v3.4 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/bitnami/charts/tree/main/bitnami/kafka"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm install kafka oci://registry-1.docker.io/bitnamicharts/kafka --version 22.0.0 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"autoCreateTopicsEnable: true\n")),(0,o.kt)("h4",{id:"grafana-v95"},"Grafana v9.5"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://grafana.com/docs/grafana/v9.5/"},"App v9.5.1 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/grafana/helm-charts/tree/main/charts/grafana"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add grafana https://grafana.github.io/helm-charts\nhelm repo update\nhelm install grafana grafana/grafana -n opentwins --version 6.56.1 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"persistence:\n enabled: true\nservice:\n type: NodePort\n nodePort: 30718\ngrafana.ini:\n plugins:\n plugin_admin_enabled: true\n allow_loading_unsigned_plugins: 'ertis-opentwins,ertis-unity-panel'\nextraInitContainers:\n- name: install-opentwins-plugins\n image: busybox\n command:\n - /bin/sh\n - -c\n - |\n #!/bin/sh\n set -euo pipefail\n mkdir -p /grafana-storage/plugins\n cd /grafana-storage/plugins\n wget --no-check-certificate -O ertis-opentwins.zip https://github.com/ertis-research/opentwins-in-grafana/releases/download/latest/ertis-opentwins.zip\n unzip -o ertis-opentwins.zip\n rm ertis-opentwins.zip\n wget --no-check-certificate -O ertis-unity-panel.zip https://github.com/ertis-research/grafana-panel-unity/releases/download/latest/ertis-unity-panel.zip\n unzip -o ertis-unity-panel.zip\n rm ertis-unity-panel.zip\n volumeMounts:\n - name: storage\n mountPath: /grafana-storage\n")),(0,o.kt)("h4",{id:"eclipse-hono-v24"},"Eclipse Hono v2.4"),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"This component is completely optional. We maintain support for its connection to OpenTwins, but ",(0,o.kt)("strong",{parentName:"p"},"we do not recommend its use"),". For a large number of devices or messages it increases considerably the latency of the platform.")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://eclipse.dev/hono/docs/2.4/"},"App v2.4 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/eclipse/packages/tree/master/charts/hono"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add eclipse-iot https://eclipse.org/packages/charts\nhelm repo update\nhelm install hono eclipse-iot/hono -n opentwins -f values.yaml --version=2.5.5\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"prometheus:\n createInstance: false\ngrafana:\n enabled: false\nuseLoadBalancer: false\nprobes:\n livenessProbe:\n initialDelaySeconds: 900\n readinessProbe:\n initialDelaySeconds: 45\nmessagingNetworkTypes:\n - amqp\nkafkaMessagingClusterExample:\n enabled: false\namqpMessagingNetworkExample:\n enabled: true\ndeviceRegistryExample:\n type: mongodb\n addExampleData: false\n mongoDBBasedDeviceRegistry:\n mongodb:\n host: '{{ .Release.Name }}-mongodb'\n port: 27017\n dbName: hono\n hono:\n registry:\n http:\n insecurePortEnabled: true\nadapters:\n mqtt:\n hono:\n mqtt:\n insecurePortEnabled: true\n http:\n hono:\n http:\n insecurePortEnabled: true\n amqp:\n hono:\n amqp:\n insecurePortEnabled: true\n\n")),(0,o.kt)("h3",{id:"connect"},"Connect"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Check ",(0,o.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture"},"architecture")," to see which connections you need to set up")),(0,o.kt)("h4",{id:"eclipse-ditto-and-influxdb"},"Eclipse Ditto and InfluxDB"),(0,o.kt)("p",null,"The process to connect Eclipse Ditto and InfluxDB will depend on Mosquitto or Apache Kafka. Choose the option you have selected in each step."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"You have to add an output connection in Eclipse Ditto that publishes the events of the twins in the intermediary. This is done with a ",(0,o.kt)("inlineCode",{parentName:"p"},"POST")," request to the URL ",(0,o.kt)("inlineCode",{parentName:"p"},"http://DITTO_NGINX_URL/api/2/connections")," with the following body and the basic credentials: user ",(0,o.kt)("em",{parentName:"p"},'"devops"')," and password ",(0,o.kt)("em",{parentName:"p"},'"foobar"'),". Remember to replace ",(0,o.kt)("strong",{parentName:"p"},"DITTO_NGINX_URL")," by a URL that allows access to the Eclipse Ditto Nginx service, you can check how to do it ",(0,o.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/access-application-cluster/service-access-application-cluster/"},"here"),"."),(0,o.kt)("p",{parentName:"li"},"You can check if the connection is working properly by reading the ",(0,o.kt)("em",{parentName:"p"},"opentwins")," topic in the selected broker with some tool or script and sending updates to some twin in ",(0,o.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/protocol-overview.html"},"Ditto Protocol")," format. To create the twin check ",(0,o.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/http-api-doc.html#/Things/put_api_2_things__thingId_"},"here")," and to see an example of an update message check ",(0,o.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/protocol-examples-modifyfeatures.html#modifyfeatures"},"here"),"."))),(0,o.kt)(i.Z,{groupId:"intermediary",mdxType:"Tabs"},(0,o.kt)(r.Z,{value:"mosquitto",label:"Mosquitto",default:!0,mdxType:"TabItem"},(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"Change ",(0,o.kt)("strong",{parentName:"p"},"MOSQUITTO_SERVICE_NAME")," to the name of the Mosquitto service. You can check it with ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get services"),".")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="PUT http://DITTO_NGINX_URL/api/2/connections"',title:'"PUT','http://DITTO_NGINX_URL/api/2/connections"':!0},'{\n "name": "mosquitto-target-connection",\n "connectionType": "mqtt-5",\n "connectionStatus": "open",\n "uri": "tcp://MOSQUITTO_SERVICE_NAME:1883",\n "clientCount": 1,\n "failoverEnabled": true,\n "sources": [],\n "targets": [\n {\n "address": "opentwins/{{ topic:channel }}/{{ topic:criterion }}/{{ thing:namespace }}/{{ thing:name }}",\n "topics": [\n "_/_/things/twin/events?extraFields=thingId,attributes/_parents,features/idSimulationRun/properties/value",\n "_/_/things/live/messages",\n "_/_/things/live/commands"\n ],\n "qos": 1,\n "authorizationContext": [\n "nginx:ditto"\n ]\n }\n ]\n}\n'))),(0,o.kt)(r.Z,{value:"kafka",label:"Apache Kafka",mdxType:"TabItem"},(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"Change ",(0,o.kt)("strong",{parentName:"p"},"KAFKA_SERVICE_NAME")," to the name of the Apache Kafka service. You can check it with ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get services"),".")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="PUT http://DITTO_NGINX_URL/api/2/connections"',title:'"PUT','http://DITTO_NGINX_URL/api/2/connections"':!0},'{\n "name": "kafka-target-connection",\n "connectionType": "kafka",\n "connectionStatus": "open",\n "uri": "tcp://KAFKA_SERVICE_NAME:9092",\n "specificConfig": {\n "bootstrapServers": "KAFKA_SERVICE_NAME:9092",\n "saslMechanism": "plain"\n },\n "failoverEnabled": true,\n "sources": [],\n "targets": [\n {\n "address": "opentwins",\n "topics": [\n "_/_/things/twin/events?extraFields=thingId,attributes/_parents,features/idSimulationRun/properties/value",\n "_/_/things/live/messages",\n "_/_/things/live/commands"\n ],\n "authorizationContext": [\n "nginx:ditto"\n ]\n }\n ]\n}\n')))),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Now we will need to obtain a token in InfluxDB with write permissions. We will then access from a browser to the InfluxDB interface and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/influxdb/v2/admin/organizations/create-org/"},"create an ",(0,o.kt)("em",{parentName:"a"},"opentwins")," organization"),". Then, follow the instructions in their documentation to ",(0,o.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/influxdb/v2/admin/tokens/create-token/"},"create an API token")," in the organization. Save this token because we will use it next.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"An instance of Telegraf must be deployed to read the events written in the intermediary broker and write them to the database. For this we will use the Telegraf Helm and add the necessary configuration in its values. You can check to Telegraf v1 documentation for both the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/telegraf/v1/"},"application")," and ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/influxdata/helm-charts/tree/master/charts/telegraf"},"Helm")," for more information."),(0,o.kt)("p",{parentName:"li"},"The commands to deploy it are the following, using the necessary values file in each case."))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add influxdata https://helm.influxdata.com/\nhelm repo update\nhelm install -n opentwins telegraf influxdata/telegraf -f values.yaml --version=1.8.27 --set tplVersion=2\n")),(0,o.kt)(i.Z,{groupId:"intermediary",mdxType:"Tabs"},(0,o.kt)(r.Z,{value:"mosquitto",label:"Mosquitto",default:!0,mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},'service:\n enabled: false\nconfig:\n agent:\n debug: true\n processors:\n - rename:\n replace:\n - tag: "extra_attributes__parents"\n dest: "parent" \n - tag: "headers_ditto-originator"\n dest: "originator"\n - tag: "extra_features_idSimulationRun_properties_value"\n dest: "idSimulationRun"\n - tag: "extra_thingId"\n dest: "thingId"\n outputs:\n - influxdb_v2:\n urls:\n - "http://INFLUX_SERVICE_NAME:INFLUX_PORT"\n token: "INFLUXDB_TOKEN"\n organization: "opentwins"\n bucket: "default"\n inputs:\n - mqtt_consumer:\n servers:\n - "tcp://MOSQUITTO_SERVICE_NAME:1883"\n topics:\n - "opentwins/#"\n qos: 1\n tag_keys:\n - "extra_attributes__parents"\n - "extra_thingId"\n - "headers_ditto-originator"\n - "extra_features_idSimulationRun_properties_value"\n - "value_time_properties_value" \n data_format: "json"\nmetrics:\n internal:\n enabled: false\n'))),(0,o.kt)(r.Z,{value:"kafka",label:"Apache Kafka",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},'service:\n enabled: false\nconfig:\n agent:\n debug: true\n processors:\n - rename:\n replace:\n - tag: "extra_attributes__parents"\n dest: "parent" \n - tag: "headers_ditto-originator"\n dest: "originator"\n - tag: "extra_features_idSimulationRun_properties_value"\n dest: "idSimulationRun"\n - tag: "extra_thingId"\n dest: "thingId"\n outputs:\n - influxdb_v2:\n urls:\n - "http://INFLUX_SERVICE_NAME:INFLUX_PORT"\n token: "INFLUXDB_TOKEN"\n organization: "opentwins"\n bucket: "default"\n inputs:\n - kafka_consumer:\n brokers:\n - "KAFKA_SERVICE_NAME:9092"\n topics:\n - "opentwins"\n tag_keys:\n - "extra_attributes__parents"\n - "extra_thingId"\n - "headers_ditto-originator"\n - "extra_features_idSimulationRun_properties_value"\n - "value_time_properties_value" \n data_format: "json"\nmetrics:\n internal:\n enabled: false\n')))),(0,o.kt)("p",null,"With this Eclipse Ditto and InfluxDB should be connected. You can check this by sending update messages to Eclipse Ditto and verifying if they are correctly written to the InfluxDB bucket. If not, check if the messages are arriving correctly to the intermediate broker and, if so, check the logs of the Telegraf pod to see if there is any error in the configuration (usually connection problems)."),(0,o.kt)("h4",{id:"influxdb-and-grafana"},"InfluxDB and Grafana"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Obtain a ",(0,o.kt)("a",{parentName:"li",href:"https://docs.influxdata.com/influxdb/v2/admin/tokens/create-token/"},"read access token in InfluxDB")," for Grafana."),(0,o.kt)("li",{parentName:"ol"},"Access ",(0,o.kt)("inlineCode",{parentName:"li"},"Configuration > Data sources")," on the Grafana interface and click on ",(0,o.kt)("em",{parentName:"li"},"Add data source"),"."),(0,o.kt)("li",{parentName:"ol"},"Select ",(0,o.kt)("em",{parentName:"li"},"InfluxDB")," from the list. In the setup form it is very important to select ",(0,o.kt)("em",{parentName:"li"},"Flux")," as query language. It will be necessary to fill in the URL section with the one that corresponds to InfluxDB service. You will also have to activate ",(0,o.kt)("em",{parentName:"li"},"Auth Basic")," and fill in the fields (in our case we have set the default admin of InfluxDB, but you can create a new user and fill in these fields). In the InfluxDB details you should indicate the organization, the bucket (default is ",(0,o.kt)("em",{parentName:"li"},"default"),") and the token you have generated. "),(0,o.kt)("li",{parentName:"ol"},"When saving and testing, it should come out that at least one bucket has been found, indicating that they are already connected.")),(0,o.kt)("h4",{id:"eclipse-ditto-and-eclipse-hono"},"Eclipse Ditto and Eclipse Hono"),(0,o.kt)("p",null,"In the following diagram you can see how Eclipse Hono and Eclipse Ditto are related in OpenTwins. "),(0,o.kt)("center",null,(0,o.kt)("img",{src:n(9193).Z,alt:"Ditto and Hono relationship",style:{width:500}})),(0,o.kt)("p",null,"Basically, you will need to ",(0,o.kt)("strong",{parentName:"p"},"create a connection between both for each Eclipse Hono tenant you want to use"),". ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/hono/docs/concepts/tenancy/"},"Tenants")," basically act as device containers, so you could simply create a single tenant connected to Eclipse Ditto and store all the devices you need there. In this case we will do it this way, but you could create as many tenants and connections as your needs require."),(0,o.kt)("p",null,"The first thing to do is to check the IPs and ports to use with ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get services -n $NS"),". At this point we are interested in the ",(0,o.kt)("em",{parentName:"p"},"dt-service-device-registry-ext")," and ",(0,o.kt)("em",{parentName:"p"},"dt-ditto-nginx")," services, which correspond to Eclipse Hono and Eclipse Ditto respectively (if you have followed these instructions and services are NodePort, you will have to use port 3XXXX). "),(0,o.kt)("p",null,"We will then create a Hono tenant called, for example, ditto (you must override the variable ",(0,o.kt)("strong",{parentName:"p"},"HONO_TENANT")," if you have chosen another name)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"HONO_TENANT=ditto\ncurl -i -X POST http://$HONO_IP:$HONO_PORT/v1/tenants/$HONO_TENANT\n")),(0,o.kt)("p",null,"Now we will create the connection from Eclipse Ditto, which will act as a consumer of the AMQP endpoint of that tenant. To do this you will need to know the Eclipse Ditto devops password with the following command (the variable ",(0,o.kt)("strong",{parentName:"p"},"RELEASE")," is the name we gave to the Helm release when installing cloud2edge, if you have followed these instructions it should be dt)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'RELEASE=dt\nDITTO_DEVOPS_PWD=$(kubectl --namespace ${NS} get secret ${RELEASE}-ditto-gateway-secret -o jsonpath="{.data.devops-password}" | base64 --decode)\n')),(0,o.kt)("p",null,"Now we ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/connectivity-manage-connections.html#create-connection"},"create the connection from Eclipse Ditto")," with the following command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'curl -i -X POST -u devops:${DITTO_DEVOPS_PWD} -H \'Content-Type: application/json\' --data \'{\n "targetActorSelection": "/system/sharding/connection",\n "headers": {\n "aggregate": false\n },\n "piggybackCommand": {\n "type": "connectivity.commands:createConnection",\n "connection": {\n "id": "hono-connection-for-\'"${HONO_TENANT}"\'",\n "connectionType": "amqp-10",\n "connectionStatus": "open",\n "uri": "amqp://consumer%40HONO:verysecret@\'"${RELEASE}"\'-dispatch-router-ext:15672",\n "failoverEnabled": true,\n "sources": [\n {\n "addresses": [\n "telemetry/\'"${HONO_TENANT}"\'",\n "event/\'"${HONO_TENANT}"\'"\n ],\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "enforcement": {\n "input": "{{ header:device_id }}",\n "filters": [\n "{{ entity:id }}"\n ]\n },\n "headerMapping": {\n "hono-device-id": "{{ header:device_id }}",\n "content-type": "{{ header:content-type }}"\n },\n "replyTarget": {\n "enabled": true,\n "address": "{{ header:reply-to }}",\n "headerMapping": {\n "to": "command/\'"${HONO_TENANT}"\'/{{ header:hono-device-id }}",\n "subject": "{{ header:subject | fn:default(topic:action-subject) | fn:default(topic:criterion) }}-response",\n "correlation-id": "{{ header:correlation-id }}",\n "content-type": "{{ header:content-type | fn:default(\'"\'"\'application/vnd.eclipse.ditto+json\'"\'"\') }}"\n },\n "expectedResponseTypes": [\n "response",\n "error"\n ]\n },\n "acknowledgementRequests": {\n "includes": [],\n "filter": "fn:filter(header:qos,\'"\'"\'ne\'"\'"\',\'"\'"\'0\'"\'"\')"\n }\n },\n {\n "addresses": [\n "command_response/\'"${HONO_TENANT}"\'/replies"\n ],\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "headerMapping": {\n "content-type": "{{ header:content-type }}",\n "correlation-id": "{{ header:correlation-id }}",\n "status": "{{ header:status }}"\n },\n "replyTarget": {\n "enabled": false,\n "expectedResponseTypes": [\n "response",\n "error"\n ]\n }\n }\n ],\n "targets": [\n {\n "address": "command/\'"${HONO_TENANT}"\'",\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "topics": [\n "_/_/things/live/commands",\n "_/_/things/live/messages"\n ],\n "headerMapping": {\n "to": "command/\'"${HONO_TENANT}"\'/{{ thing:id }}",\n "subject": "{{ header:subject | fn:default(topic:action-subject) }}",\n "content-type": "{{ header:content-type | fn:default(\'"\'"\'application/vnd.eclipse.ditto+json\'"\'"\') }}",\n "correlation-id": "{{ header:correlation-id }}",\n "reply-to": "{{ fn:default(\'"\'"\'command_response/\'"${HONO_TENANT}"\'/replies\'"\'"\') | fn:filter(header:response-required,\'"\'"\'ne\'"\'"\',\'"\'"\'false\'"\'"\') }}"\n }\n },\n {\n "address": "command/\'"${HONO_TENANT}"\'",\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "topics": [\n "_/_/things/twin/events",\n "_/_/things/live/events"\n ],\n "headerMapping": {\n "to": "command/\'"${HONO_TENANT}"\'/{{ thing:id }}",\n "subject": "{{ header:subject | fn:default(topic:action-subject) }}",\n "content-type": "{{ header:content-type | fn:default(\'"\'"\'application/vnd.eclipse.ditto+json\'"\'"\') }}",\n "correlation-id": "{{ header:correlation-id }}"\n }\n }\n ]\n }\n }\n}\' http://$DITTO_IP:$DITTO_PORT/devops/piggyback/connectivity\n')),(0,o.kt)("p",null,"This connection is configured so that if an ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/hono/docs/concepts/device-identity/"},"Eclipse Hono device")," has the ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/basic-thing.html#thing-id"},"ThingId")," of an Eclipse Ditto twin as its identifier, its messages will be redirected to that twin directly (explained in more detail in the ",(0,o.kt)("a",{parentName:"p",href:"#usage"},"usage")," section)."),(0,o.kt)("h2",{id:"compositional-support"},"Compositional support"),(0,o.kt)("h2",{id:"data-prediction-with-machine-learning"},"Data prediction with machine learning"),(0,o.kt)("h2",{id:"3d-representation"},"3D representation"))}h.isMDXComponent=!0},9193:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/ditto-hono-relationship-05edfdb26b9df807a0860fad82192684.jpg"}}]); \ No newline at end of file diff --git a/assets/js/4c455ca7.946c6245.js b/assets/js/4c455ca7.946c6245.js deleted file mode 100644 index c3c8a81..0000000 --- a/assets/js/4c455ca7.946c6245.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6933],{9191:e=>{e.exports=JSON.parse('{"title":"Guides","slug":"/category/guides","permalink":"/opentwins/docs/category/guides","navigation":{"previous":{"title":"Manual","permalink":"/opentwins/docs/installation/manual"},"next":{"title":"Create a type","permalink":"/opentwins/docs/guides/type-creation"}}}')}}]); \ No newline at end of file diff --git a/assets/js/5a7456e0.970b6829.js b/assets/js/5a7456e0.970b6829.js new file mode 100644 index 0000000..7ae8102 --- /dev/null +++ b/assets/js/5a7456e0.970b6829.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1826],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function r(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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=u(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||i;return n?a.createElement(h,l(l({ref:t},p),{},{components:n})):a.createElement(h,l({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:r,l[1]=o;for(var u=2;u{n.d(t,{Z:()=>l});var a=n(7294),r=n(6010);const i={tabItem:"tabItem_Ymn6"};function l(e){let{children:t,hidden:n,className:l}=e;return a.createElement("div",{role:"tabpanel",className:(0,r.Z)(i.tabItem,l),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>c});var a=n(7462),r=n(7294),i=n(6010),l=n(2389),o=n(7392),s=n(7094),u=n(2466);const p={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function d(e){const{lazy:t,block:n,defaultValue:l,values:d,groupId:c,className:m}=e,h=r.Children.map(e.children,(e=>{if((0,r.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=d??h.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),k=(0,o.l)(f,((e,t)=>e.value===t.value));if(k.length>0)throw new Error(`Docusaurus error: Duplicate values "${k.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const g=null===l?l:l??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==g&&!f.some((e=>e.value===g)))throw new Error(`Docusaurus error: The has a defaultValue "${g}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:b,setTabGroupChoices:v}=(0,s.U)(),[w,y]=(0,r.useState)(g),N=[],{blockElementScrollPositionUntilNextRender:O}=(0,u.o5)();if(null!=c){const e=b[c];null!=e&&e!==w&&f.some((t=>t.value===e))&&y(e)}const T=e=>{const t=e.currentTarget,n=N.indexOf(t),a=f[n].value;a!==w&&(O(t),y(a),null!=c&&v(c,String(a)))},E=e=>{let t=null;switch(e.key){case"Enter":T(e);break;case"ArrowRight":{const n=N.indexOf(e.currentTarget)+1;t=N[n]??N[0];break}case"ArrowLeft":{const n=N.indexOf(e.currentTarget)-1;t=N[n]??N[N.length-1];break}}t?.focus()};return r.createElement("div",{className:(0,i.Z)("tabs-container",p.tabList)},r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:l}=e;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:w===t?0:-1,"aria-selected":w===t,key:t,ref:e=>N.push(e),onKeyDown:E,onClick:T},l,{className:(0,i.Z)("tabs__item",p.tabItem,l?.className,{"tabs__item--active":w===t})}),n??t)}))),t?(0,r.cloneElement)(h.filter((e=>e.props.value===w))[0],{className:"margin-top--md"}):r.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==w})))))}function c(e){const t=(0,l.Z)();return r.createElement(d,(0,a.Z)({key:String(t)},e))}},6029:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var a=n(7462),r=(n(7294),n(3905));n(5488),n(5162);const i={sidebar_position:1},l="Helm",o={unversionedId:"installation/using-helm",id:"installation/using-helm",title:"Helm",description:"Standard version",source:"@site/docs/installation/using-helm.mdx",sourceDirName:"installation",slug:"/installation/using-helm",permalink:"/opentwins/docs/installation/using-helm",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/using-helm.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Installation",permalink:"/opentwins/docs/category/installation"},next:{title:"Manual",permalink:"/opentwins/docs/installation/manual/"}},s={},u=[{value:"Standard version",id:"standard-version",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Hardware",id:"hardware",level:4},{value:"Software",id:"software",level:4},{value:"Installation",id:"installation",level:3},{value:"Configuration",id:"configuration",level:3},{value:"Obtain external URLs for Eclipse Ditto, Ditto Extended API and Grafana.",id:"obtain-external-urls-for-eclipse-ditto-ditto-extended-api-and-grafana",level:4},{value:"Add URLs to OpenTwins plugin configuration",id:"add-urls-to-opentwins-plugin-configuration",level:4},{value:"Lightweight version",id:"lightweight-version",level:2},{value:"Prerequisites",id:"prerequisites-1",level:3},{value:"Hardware",id:"hardware-1",level:4},{value:"Software",id:"software-1",level:4},{value:"Installation",id:"installation-1",level:3}],p={toc:u},d="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(d,(0,a.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"helm"},"Helm"),(0,r.kt)("h2",{id:"standard-version"},"Standard version"),(0,r.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("h4",{id:"hardware"},"Hardware"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"2 CPU cores"),(0,r.kt)("li",{parentName:"ul"},"8 GB of RAM")),(0,r.kt)("h4",{id:"software"},"Software"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Container manager: Currently tested on ",(0,r.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")," and ",(0,r.kt)("a",{parentName:"li",href:"https://containerd.io/"},"ContainerD"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")," (recommended) or ",(0,r.kt)("a",{parentName:"li",href:"https://k3s.io/"},"K3s"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," version 16.14 or above.")),(0,r.kt)("h3",{id:"installation"},"Installation"),(0,r.kt)("p",null,"First of all, you have to add ERTIS Research group helm repository to your helm repository list:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\n")),(0,r.kt)("p",null,"Once done, the next step is installing the chart by executing this line on your terminal (in our case, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"opentwins")," as release name and ",(0,r.kt)("inlineCode",{parentName:"p"},"opentwins")," as namespace, but you can choose the one that you prefeer). To customize the installation, please refer to ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/Helm-charts/blob/main/OpenTwins/values.yaml"},"Helm's values")," file."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"We recommend to modify the ",(0,r.kt)("strong",{parentName:"p"},"default passwords and tokens")," for Grafana and InfluxDB before deploying the platform. Currently, to avoid potential problems, we do not recommend changing Eclipse Ditto's username and password.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade --install opentwins ertis/OpenTwins --wait --dependency-update --debug\n")),(0,r.kt)("p",null,"After waiting some time, the installation will be ready for use."),(0,r.kt)("h3",{id:"configuration"},"Configuration"),(0,r.kt)("p",null,"If you have kept the default values of the Helm chart, you will only need to ",(0,r.kt)("strong",{parentName:"p"},"configure the OpenTwins interface plugin for Grafana"),"."),(0,r.kt)("h4",{id:"obtain-external-urls-for-eclipse-ditto-ditto-extended-api-and-grafana"},"Obtain external URLs for Eclipse Ditto, Ditto Extended API and Grafana."),(0,r.kt)("p",null,"Get the name of the services with ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl get services"),". The result will look something similar to the following image. If you have changed the name of the release, the names will not be preceded by ",(0,r.kt)("em",{parentName:"p"},"opentwins"),", but by the name you have assigned. We are interested in the services ",(0,r.kt)("em",{parentName:"p"},"opentwins-grafana"),", ",(0,r.kt)("em",{parentName:"p"},"opentwins-ditto-nginx")," and ",(0,r.kt)("em",{parentName:"p"},"opentwins-ditto-extended-api"),"."),(0,r.kt)("center",null,(0,r.kt)("img",{src:n(8831).Z,alt:"Kubectl get services",style:{width:700}})),(0,r.kt)("p",null,"The method to obtain the URL may vary depending on the configuration of your cluster. Generally, the URL for each service will match the cluster IP and the NodePort (the number after the colon). For example, if our cluster IP is ",(0,r.kt)("inlineCode",{parentName:"p"},"192.168.32.25"),", the URL for Grafana would be ",(0,r.kt)("inlineCode",{parentName:"p"},"192.168.32.25:30718"),"."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Are you using ",(0,r.kt)("b",null,"Minikube")," to deploy OpenTwins?"),(0,r.kt)("div",null,(0,r.kt)("p",null,"As Minikube is a local cluster, you ",(0,r.kt)("strong",{parentName:"p"},"cannot directly use the IP of the cluster"),". Therefore, you will have to ",(0,r.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/handbook/accessing/"},"expose the services")," that you want to use externally with a command."),(0,r.kt)("p",null,"Open three terminals, one for each service, and run the following command on each terminal with a different service name. These will return a URL of your localhost with a port that will forward all traffic to the specified service. ",(0,r.kt)("strong",{parentName:"p"},"These are the URLs you should use.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"minikube service --url\n")))),(0,r.kt)("h4",{id:"add-urls-to-opentwins-plugin-configuration"},"Add URLs to OpenTwins plugin configuration"),(0,r.kt)("p",null,"Access Grafana in any browser with the URL you have obtained. The credentials must match those indicated in the Helm values, which by default are user ",(0,r.kt)("em",{parentName:"p"},"admin")," and password ",(0,r.kt)("em",{parentName:"p"},"admin"),". "),(0,r.kt)("p",null,"Access the left drop-down menu and select ",(0,r.kt)("inlineCode",{parentName:"p"},"Administration > Plugins"),". Once there, find the ",(0,r.kt)("em",{parentName:"p"},"OpenTwins")," plugin and activate it by clicking ",(0,r.kt)("em",{parentName:"p"},"Enable"),". Then, go to the ",(0,r.kt)("em",{parentName:"p"},"Configuration")," tab where you will need to enter the Eclipse Ditto and Extended API URLs in the corresponding fields. Use ",(0,r.kt)("em",{parentName:"p"},"ditto")," for both the Eclipse Ditto username and password if you have not changed the credentials. Then click on ",(0,r.kt)("em",{parentName:"p"},"Save settings")," to complete the plugin configuration."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Screenshots"),(0,r.kt)("div",null,(0,r.kt)("center",null,(0,r.kt)("img",{src:n(6482).Z,alt:"Plugin",style:{width:600}})),(0,r.kt)("center",null,(0,r.kt)("img",{src:n(3508).Z,alt:"Configuration",style:{width:600}})),(0,r.kt)("center",null,(0,r.kt)("img",{src:n(8407).Z,alt:"Configuration",style:{width:400}})))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"If you are using the latest version of the interface, you may find two fields intended for an agent service. This functionality is currently under development and is not yet available, so leave them empty and disregard them for now.")),(0,r.kt)("p",null,"Find the available application in the ",(0,r.kt)("inlineCode",{parentName:"p"},"App > OpenTwins")," section of the left drop-down menu. "),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"You can now start using OpenTwins"),". "),(0,r.kt)("h2",{id:"lightweight-version"},"Lightweight version"),(0,r.kt)("h3",{id:"prerequisites-1"},"Prerequisites"),(0,r.kt)("h4",{id:"hardware-1"},"Hardware"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Raspberry Pi 4")),(0,r.kt)("h4",{id:"software-1"},"Software"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Container manager: Currently tested on ",(0,r.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")," and ",(0,r.kt)("a",{parentName:"li",href:"https://containerd.io/"},"ContainerD"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")," (recommended) or ",(0,r.kt)("a",{parentName:"li",href:"https://k3s.io/"},"K3s"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," version 16.14 or above.")),(0,r.kt)("h3",{id:"installation-1"},"Installation"),(0,r.kt)("p",null,"OpenTwins has it's own lightweight version that aims to run on IoT devices such as Raspberry Pi devices.\nTo install this versi\xf3n, you have to follow the first step in order to add ERTIS repository to your repository list and then install the platform using the command bellow:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm install ot ertis/OpenTwins-Lightweight -n opentwins\n")),(0,r.kt)("p",null,"In this case connections still need to be made for the platform to work properly. Check the manual documentation to learn how to do it."))}c.isMDXComponent=!0},3508:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/configuration-interfaz-c20eaffea1d3bec206f55464ba19679a.png"},6482:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/enable-plugin-0aa4a65c98ecbff05f27d2b540455e1b.png"},8831:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/kubectlgetsvc-f4edab151d7278aa24b49da8b2bcc0e3.png"},8407:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/opentwins-access-2eb74b7ab18c9e4a88906e0a9a5a13fd.png"}}]); \ No newline at end of file diff --git a/assets/js/5a7456e0.a5334c36.js b/assets/js/5a7456e0.a5334c36.js deleted file mode 100644 index a72e929..0000000 --- a/assets/js/5a7456e0.a5334c36.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1826],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function r(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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),m=r,h=c["".concat(s,".").concat(m)]||c[m]||d[m]||i;return n?a.createElement(h,o(o({ref:t},p),{},{components:n})):a.createElement(h,o({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var u=2;u{n.d(t,{Z:()=>o});var a=n(7294),r=n(6010);const i={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:n,className:o}=e;return a.createElement("div",{role:"tabpanel",className:(0,r.Z)(i.tabItem,o),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>d});var a=n(7462),r=n(7294),i=n(6010),o=n(2389),l=n(7392),s=n(7094),u=n(2466);const p={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function c(e){const{lazy:t,block:n,defaultValue:o,values:c,groupId:d,className:m}=e,h=r.Children.map(e.children,(e=>{if((0,r.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=c??h.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),g=(0,l.l)(f,((e,t)=>e.value===t.value));if(g.length>0)throw new Error(`Docusaurus error: Duplicate values "${g.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const b=null===o?o:o??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==b&&!f.some((e=>e.value===b)))throw new Error(`Docusaurus error: The has a defaultValue "${b}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:v,setTabGroupChoices:k}=(0,s.U)(),[y,w]=(0,r.useState)(b),N=[],{blockElementScrollPositionUntilNextRender:O}=(0,u.o5)();if(null!=d){const e=v[d];null!=e&&e!==y&&f.some((t=>t.value===e))&&w(e)}const T=e=>{const t=e.currentTarget,n=N.indexOf(t),a=f[n].value;a!==y&&(O(t),w(a),null!=d&&k(d,String(a)))},x=e=>{let t=null;switch(e.key){case"Enter":T(e);break;case"ArrowRight":{const n=N.indexOf(e.currentTarget)+1;t=N[n]??N[0];break}case"ArrowLeft":{const n=N.indexOf(e.currentTarget)-1;t=N[n]??N[N.length-1];break}}t?.focus()};return r.createElement("div",{className:(0,i.Z)("tabs-container",p.tabList)},r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:o}=e;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:y===t?0:-1,"aria-selected":y===t,key:t,ref:e=>N.push(e),onKeyDown:x,onClick:T},o,{className:(0,i.Z)("tabs__item",p.tabItem,o?.className,{"tabs__item--active":y===t})}),n??t)}))),t?(0,r.cloneElement)(h.filter((e=>e.props.value===y))[0],{className:"margin-top--md"}):r.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==y})))))}function d(e){const t=(0,o.Z)();return r.createElement(c,(0,a.Z)({key:String(t)},e))}},6029:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(7462),r=(n(7294),n(3905));n(5488),n(5162);const i={sidebar_position:2},o="Helm",l={unversionedId:"installation/using-helm",id:"installation/using-helm",title:"Helm",description:"Standard version",source:"@site/docs/installation/using-helm.mdx",sourceDirName:"installation",slug:"/installation/using-helm",permalink:"/opentwins/docs/installation/using-helm",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/using-helm.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Requirements",permalink:"/opentwins/docs/installation/requirements"},next:{title:"Manual",permalink:"/opentwins/docs/installation/manual"}},s={},u=[{value:"Standard version",id:"standard-version",level:2},{value:"Installation",id:"installation",level:3},{value:"Configuration",id:"configuration",level:3},{value:"Obtain external URLs for Eclipse Ditto, Ditto extended API and Grafana.",id:"obtain-external-urls-for-eclipse-ditto-ditto-extended-api-and-grafana",level:4},{value:"Add URLs to OpenTwins plugin configuration",id:"add-urls-to-opentwins-plugin-configuration",level:4},{value:"Lightweight version",id:"lightweight-version",level:2}],p={toc:u},c="wrapper";function d(e){let{components:t,...i}=e;return(0,r.kt)(c,(0,a.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"helm"},"Helm"),(0,r.kt)("h2",{id:"standard-version"},"Standard version"),(0,r.kt)("h3",{id:"installation"},"Installation"),(0,r.kt)("p",null,"First of all, you have to add ERTIS Research group helm repository to your helm repository list:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\n")),(0,r.kt)("p",null,"Once done, the next step is installing the chart by executing this line on your terminal (in our case, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"opentwins")," as release name and ",(0,r.kt)("inlineCode",{parentName:"p"},"opentwins")," as namespace, but you can choose the one that you prefeer). To customize the installation, please refer to ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/Helm-charts/blob/main/OpenTwins/values.yaml"},"Helm's values")," file."),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"We recommend to modify the ",(0,r.kt)("strong",{parentName:"p"},"default passwords and tokens")," for Grafana and InfluxDB before deploying the platform. Currently, to avoid potential problems, we do not recommend changing Eclipse Ditto's username and password.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade --install opentwins ertis/OpenTwins --wait --dependency-update --debug\n")),(0,r.kt)("p",null,"After waiting some time, the installation will be ready for use."),(0,r.kt)("h3",{id:"configuration"},"Configuration"),(0,r.kt)("p",null,"If you have kept the default values of the Helm chart, you will only need to ",(0,r.kt)("strong",{parentName:"p"},"configure the OpenTwins interface plugin for Grafana"),"."),(0,r.kt)("h4",{id:"obtain-external-urls-for-eclipse-ditto-ditto-extended-api-and-grafana"},"Obtain external URLs for Eclipse Ditto, Ditto extended API and Grafana."),(0,r.kt)("p",null,"Get the name of the services with ",(0,r.kt)("inlineCode",{parentName:"p"},"kubectl get services"),". The result will look something similar to the following image. If you have changed the name of the release, the names will not be preceded by ",(0,r.kt)("em",{parentName:"p"},"opentwins"),", but by the name you have assigned. We are interested in the services ",(0,r.kt)("em",{parentName:"p"},"opentwins-grafana"),", ",(0,r.kt)("em",{parentName:"p"},"opentwins-ditto-nginx")," and ",(0,r.kt)("em",{parentName:"p"},"opentwins-ditto-extended-api"),"."),(0,r.kt)("center",null,(0,r.kt)("img",{src:n(8831).Z,alt:"Kubectl get services",style:{width:700}})),(0,r.kt)("p",null,"The method to obtain the URL may vary depending on the configuration of your cluster. Generally, the URL for each service will match the cluster IP and the NodePort (the number after the colon). For example, if our cluster IP is ",(0,r.kt)("inlineCode",{parentName:"p"},"192.168.32.25"),", the URL for Grafana would be ",(0,r.kt)("inlineCode",{parentName:"p"},"192.168.32.25:30718"),"."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Are you using ",(0,r.kt)("b",null,"Minikube")," to deploy OpenTwins?"),(0,r.kt)("div",null,(0,r.kt)("p",null,"As Minikube is a local cluster, you ",(0,r.kt)("strong",{parentName:"p"},"cannot directly use the IP of the cluster"),". Therefore, you will have to ",(0,r.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/handbook/accessing/"},"expose the services")," that you want to use externally with a command."),(0,r.kt)("p",null,"Open three terminals, one for each service, and run the following command on each terminal with a different service name. These will return a URL of your localhost with a port that will forward all traffic to the specified service. ",(0,r.kt)("strong",{parentName:"p"},"These are the URLs you should use.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"minikube service --url\n")))),(0,r.kt)("h4",{id:"add-urls-to-opentwins-plugin-configuration"},"Add URLs to OpenTwins plugin configuration"),(0,r.kt)("p",null,"Access Grafana in any browser with the URL you have obtained. The credentials must match those indicated in the Helm values, which by default are user ",(0,r.kt)("em",{parentName:"p"},"admin")," and password ",(0,r.kt)("em",{parentName:"p"},"admin"),". "),(0,r.kt)("p",null,"Access the left drop-down menu and select ",(0,r.kt)("inlineCode",{parentName:"p"},"Administration > Plugins"),". Once there, find the ",(0,r.kt)("em",{parentName:"p"},"OpenTwins")," plugin and activate it by clicking ",(0,r.kt)("em",{parentName:"p"},"Enable"),". Then, go to the ",(0,r.kt)("em",{parentName:"p"},"Configuration")," tab where you will need to enter the Eclipse Ditto and Extended API URLs in the corresponding fields. Use ",(0,r.kt)("em",{parentName:"p"},"ditto")," for both the Eclipse Ditto username and password for the moment. Then click on ",(0,r.kt)("em",{parentName:"p"},"Save settings")," to complete the plugin configuration."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"If you are using the latest version of the interface, you may find two fields intended for an agent service. This functionality is currently under development and is not yet available, so leave them empty and disregard them for now.")),(0,r.kt)("p",null,"Find the available application in the ",(0,r.kt)("inlineCode",{parentName:"p"},"App > OpenTwins")," section of the left drop-down menu. "),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"You can now start using OpenTwins"),". "),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Screenshots"),(0,r.kt)("div",null,(0,r.kt)("center",null,(0,r.kt)("img",{src:n(6482).Z,alt:"Plugin",style:{width:600}})),(0,r.kt)("center",null,(0,r.kt)("img",{src:n(3508).Z,alt:"Configuration",style:{width:600}})),(0,r.kt)("center",null,(0,r.kt)("img",{src:n(8407).Z,alt:"Configuration",style:{width:400}})))),(0,r.kt)("h2",{id:"lightweight-version"},"Lightweight version"),(0,r.kt)("p",null,"OpenTwins has it's own lightweight version that aims to run on IoT devices such as Raspberry Pi devices.\nTo install this versi\xf3n, you have to follow the first step in order to add ERTIS repository to your repository list and then install the platform using the command bellow:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"helm install ot ertis/OpenTwins-Lightweight -n opentwins\n")),(0,r.kt)("p",null,"In this case connections still need to be made for the platform to work properly."))}d.isMDXComponent=!0},3508:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/configuration-interfaz-c20eaffea1d3bec206f55464ba19679a.png"},6482:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/enable-plugin-0aa4a65c98ecbff05f27d2b540455e1b.png"},8831:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/kubectlgetsvc-f4edab151d7278aa24b49da8b2bcc0e3.png"},8407:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/opentwins-access-2eb74b7ab18c9e4a88906e0a9a5a13fd.png"}}]); \ No newline at end of file diff --git a/assets/js/65d05370.47c9eac8.js b/assets/js/65d05370.47c9eac8.js new file mode 100644 index 0000000..79459d8 --- /dev/null +++ b/assets/js/65d05370.47c9eac8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6045],{7634:e=>{e.exports=JSON.parse('{"title":"DT definition","slug":"/category/dt-definition","permalink":"/opentwins/docs/category/dt-definition","navigation":{"previous":{"title":"Guides","permalink":"/opentwins/docs/guides/"},"next":{"title":"Create a type","permalink":"/opentwins/docs/guides/definition/type-creation"}}}')}}]); \ No newline at end of file diff --git a/assets/js/65f6152f.850d0fdd.js b/assets/js/65f6152f.850d0fdd.js new file mode 100644 index 0000000..f3c4d0c --- /dev/null +++ b/assets/js/65f6152f.850d0fdd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9601],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>f});var r=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=r.createContext({}),c=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return r.createElement(l.Provider,{value:n},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=c(t),d=i,f=m["".concat(l,".").concat(d)]||m[d]||p[d]||a;return t?r.createElement(f,o(o({ref:n},u),{},{components:t})):r.createElement(f,o({ref:n},u))}));function f(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=d;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[m]="string"==typeof e?e:i,o[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var r=t(7462),i=(t(7294),t(3905));t(4996),t(941);const a={sidebar_position:1,sidebar_label:"Concepts"},o="FMI Simulation concepts",s={unversionedId:"guides/fmi/concepts",id:"guides/fmi/concepts",title:"FMI Simulation concepts",description:"The FMI simulation service is currently being tested.",source:"@site/docs/guides/fmi/concepts.mdx",sourceDirName:"guides/fmi",slug:"/guides/fmi/concepts",permalink:"/opentwins/docs/guides/fmi/concepts",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/fmi/concepts.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"Concepts"},sidebar:"tutorialSidebar",previous:{title:"FMI Simulation",permalink:"/opentwins/docs/category/fmi-simulation"},next:{title:"API Documentation",permalink:"/opentwins/docs/guides/fmi/API"}},l={},c=[{value:"Simulation schema",id:"simulation-schema",level:2},{value:"Simulation running schema",id:"simulation-running-schema",level:2}],u={toc:c},m="wrapper";function p(e){let{components:n,...t}=e;return(0,i.kt)(m,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"fmi-simulation-concepts"},"FMI Simulation concepts"),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"The FMI simulation service is currently being tested.")),(0,i.kt)("h2",{id:"simulation-schema"},"Simulation schema"),(0,i.kt)("p",null,"The schema is used to create simulation blueprints to store and create several simulation instances."),(0,i.kt)("p",null,"The schema can be create for a single FMU or several FMUs. The schema for a single FMU is:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id":"schema1",\n "name":"Schema 1",\n "description":"Sample schema",\n "relatedTwins":[\n "Twin1"\n ],\n "fmus":[\n {\n "id": "Controller",\n "inputs": [\n {"id": "u_s"},\n {"id": "u_m"}\n ],\n "outputs": [\n {"id": "y"}\n ]\n }\n ]\n}\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,(0,i.kt)("b",null,"Schema for several FMUs")),(0,i.kt)("p",null,"The following schema is designed to be used with multiple FMUs:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-tsx"},'{\n "id":"schema1",\n "name":"Schema 1",\n "description":"Sample schema",\n "relatedTwins":[\n "Twin1"\n ],\n "fmus":[\n {\n "id": "Controller",\n "inputs": [\n {"id": "u_s"},\n {"id": "u_m"}\n ],\n "outputs": [\n {"id": "y"}\n ]\n },\n {\n "id": "Drivetrain",\n "inputs": [\n {"id": "tau"}\n ],\n "outputs": [\n {"id": "w"}\n ]\n }\n ],\n "schema":[\n {\n "from": {"var": "w_ref"},\n "to": {"id": "controller", "var": "u_s"}\n },\n {\n "from": {"id": "drivetrain", "var": "w"},\n "to": {"id": "controller", "var": "u_m"}\n },\n {\n "from": {"id": "controller", "var": "y"},\n "to": {"id": "drivetrain", "var": "tau"}\n },\n {\n "from": {"id": "drivetrain", "var": "w"},\n "to": {"var": "w"}\n }\n ]\n}\n')),(0,i.kt)("p",null,"This will work properly, although hovering over",(0,i.kt)("inlineCode",{parentName:"p"},"ApparentGreetProps"),"may be a little intimidating. You can reduce this boilerplate with the",(0,i.kt)("inlineCode",{parentName:"p"},"ComponentProps")," utility detailed below.")),(0,i.kt)("h2",{id:"simulation-running-schema"},"Simulation running schema"),(0,i.kt)("p",null,"Once you have a schema stored in the system, you can create a simulation instance using that schema:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id":"Simulation1",\n "name":"Simulation1",\n "schemaId": "schema1",\n "targetConnection":{\n "BROKER_TYPE" : "mqtt",\n "BROKER_IP" : "",\n "BROKER_PORT" : "",\n "BROKER_TOPIC" : "",\n "BROKER_USERNAME" : "",\n "BROKER_PASSWORD" : ""\n },\n "configuration":{\n "SIMULATION_START_TIME":1,\n "SIMULATION_END_TIME":7,\n "SIMULATION_STEP_SIZE":1,\n "SIMULATION_DELAY_WARNING": 1,\n "SIMULATION_LAST_VALUE": true,\n "SIMULATION_TYPESCHEDULE": "one-time"\n },\n "inputs":[],\n "outputs": []\n}\n\n')),(0,i.kt)("p",null,"This schema is not different for one or several FMUs execution. It only contains information about execution."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/661cef18.3a10670b.js b/assets/js/661cef18.3a10670b.js new file mode 100644 index 0000000..dff965c --- /dev/null +++ b/assets/js/661cef18.3a10670b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9106],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});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 l(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 l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=p(n),c=i,k=u["".concat(s,".").concat(c)]||u[c]||m[c]||l;return n?a.createElement(k,r(r({ref:t},d),{},{components:n})):a.createElement(k,r({ref:t},d))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:i,r[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const l={sidebar_position:2},r="API Documentation",o={unversionedId:"guides/fmi/API",id:"guides/fmi/API",title:"API Documentation",description:"Welcome to the Example API documentation. This API allows developers to interact with our services easily and efficiently.",source:"@site/docs/guides/fmi/API.md",sourceDirName:"guides/fmi",slug:"/guides/fmi/API",permalink:"/opentwins/docs/guides/fmi/API",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/fmi/API.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Concepts",permalink:"/opentwins/docs/guides/fmi/concepts"},next:{title:"Unity visualization",permalink:"/opentwins/docs/category/unity-visualization"}},s={},p=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"Introduction",id:"introduction",level:2},{value:"Endpoints",id:"endpoints",level:2},{value:"FMU endpoints",id:"fmu-endpoints",level:3},{value:"1. GET /{context}",id:"1-get-context",level:4},{value:"Description",id:"description",level:5},{value:"Request",id:"request",level:5},{value:"Response",id:"response",level:5},{value:"2. POST /{context}",id:"2-post-context",level:4},{value:"Description",id:"description-1",level:5},{value:"Request",id:"request-1",level:5},{value:"Response",id:"response-1",level:5},{value:"3. GET /{context}/{fmuName}",id:"3-get-contextfmuname",level:4},{value:"Description",id:"description-2",level:5},{value:"Request",id:"request-2",level:5},{value:"Response",id:"response-2",level:5},{value:"4. DELETE /{context}/{fmuName}",id:"4-delete-contextfmuname",level:4},{value:"Description",id:"description-3",level:5},{value:"Request",id:"request-3",level:5},{value:"Response",id:"response-3",level:5},{value:"Schema endpoints",id:"schema-endpoints",level:3},{value:"1. GET /{context}",id:"1-get-context-1",level:4},{value:"Description",id:"description-4",level:5},{value:"Request",id:"request-4",level:5},{value:"Response",id:"response-4",level:5},{value:"2. POST /{context}",id:"2-post-context-1",level:4},{value:"Description",id:"description-5",level:5},{value:"Request",id:"request-5",level:5},{value:"Response",id:"response-5",level:5},{value:"3. GET /{context}/{schema_id}",id:"3-get-contextschema_id",level:4},{value:"Description",id:"description-6",level:5},{value:"Request",id:"request-6",level:5},{value:"Response",id:"response-6",level:5},{value:"4. DELETE /{context}/{schema_id}",id:"4-delete-contextschema_id",level:4},{value:"Description",id:"description-7",level:5},{value:"Request",id:"request-7",level:5},{value:"Response",id:"response-7",level:5},{value:"Simulation endpoints",id:"simulation-endpoints",level:3},{value:"1. GET /{context}",id:"1-get-context-2",level:4},{value:"Description",id:"description-8",level:5},{value:"Request",id:"request-8",level:5},{value:"Response",id:"response-8",level:5},{value:"2. POST /{context}",id:"2-post-context-2",level:4},{value:"Description",id:"description-9",level:5},{value:"Request",id:"request-9",level:5},{value:"Response",id:"response-9",level:5},{value:"3. GET /{context}/{simulation_id}",id:"3-get-contextsimulation_id",level:4},{value:"Description",id:"description-10",level:5},{value:"Request",id:"request-10",level:5},{value:"Response",id:"response-10",level:5},{value:"4. DELETE /{context}/{simulation_id}",id:"4-delete-contextsimulation_id",level:4},{value:"Description",id:"description-11",level:5},{value:"Request",id:"request-11",level:5},{value:"Response",id:"response-11",level:5},{value:"5. POST /{context}/{simulation_id}/resume",id:"5-post-contextsimulation_idresume",level:4},{value:"Description",id:"description-12",level:5},{value:"Request",id:"request-12",level:5},{value:"Response",id:"response-12",level:5},{value:"6. POST /{context}/{simulation_id}/pause",id:"6-post-contextsimulation_idpause",level:4},{value:"Description",id:"description-13",level:5},{value:"Request",id:"request-13",level:5},{value:"Response",id:"response-13",level:5}],d={toc:p},u="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"api-documentation"},"API Documentation"),(0,i.kt)("p",null,"Welcome to the Example API documentation. This API allows developers to interact with our services easily and efficiently."),(0,i.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#endpoints"},"Endpoints"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#fmu-endpoints"},"FMU endpoints")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#schema-endpoints"},"Schema endpoints")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#simulation-endpoints"},"Simulation endpoints"))))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"This API provides access to FMU data and allows for the creation and management of simulation schemas and simulations. It is based on REST and returns responses in JSON format."),(0,i.kt)("h2",{id:"endpoints"},"Endpoints"),(0,i.kt)("h3",{id:"fmu-endpoints"},"FMU endpoints"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Endpoint /fmi/fmus"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#1-get-context"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a list of FMUs")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#2-post-context"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Upload a new FMU")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#3-get-contextfmuname"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{fmuName}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve FMU information within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#4-delete-contextfmuname"},"DELETE")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{fmuName}"),(0,i.kt)("td",{parentName:"tr",align:null},"Delete a FMU within a context")))),(0,i.kt)("h4",{id:"1-get-context"},"1. GET /{context}"),(0,i.kt)("h5",{id:"description"},"Description"),(0,i.kt)("p",null,"Get a list of FMUs in a specific context."),(0,i.kt)("h5",{id:"request"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of FMUs with information about their variables."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": "bouncingBallCS2",\n "inputs": [],\n "outputs": [],\n "other_variables": [\n {\n "name": "h",\n "type": "Real",\n "default": {\n "start": "1"\n },\n "description": "height, used as state"\n },\n {\n "name": "v",\n "type": "Real",\n "default": {\n "start": "0",\n "reinit": "true"\n },\n "description": "velocity of ball, used as state"\n },\n {\n "name": "g",\n "type": "Real",\n "default": {\n "start": "9.81"\n },\n "description": "acceleration of gravity"\n },\n {\n "name": "e",\n "type": "Real",\n "default": {\n "start": "0.7",\n "min": "0.5",\n "max": "1"\n },\n "description": "dimensionless parameter"\n }\n ]\n }\n]\n')),(0,i.kt)("h4",{id:"2-post-context"},"2. POST /{context}"),(0,i.kt)("h5",{id:"description-1"},"Description"),(0,i.kt)("p",null,"Upload a new FMU to the sistem into a specific context."),(0,i.kt)("h5",{id:"request-1"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-1"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"FMU uploaded succesfully"\n')),(0,i.kt)("h4",{id:"3-get-contextfmuname"},"3. GET /{context}/{fmuName}"),(0,i.kt)("h5",{id:"description-2"},"Description"),(0,i.kt)("p",null,"Get the XML file of a specific FMU."),(0,i.kt)("h5",{id:"request-2"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{fmuName}")),(0,i.kt)("h5",{id:"response-2"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-xml"},'\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n')),(0,i.kt)("h4",{id:"4-delete-contextfmuname"},"4. DELETE /{context}/{fmuName}"),(0,i.kt)("h5",{id:"description-3"},"Description"),(0,i.kt)("p",null,"Delete a FMU from the sistem in a specific context."),(0,i.kt)("h5",{id:"request-3"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DELETE"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{fmuName}")),(0,i.kt)("h5",{id:"response-3"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"FMU deleted succesfully"\n')),(0,i.kt)("hr",null),(0,i.kt)("h3",{id:"schema-endpoints"},"Schema endpoints"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Endpoint /fmi/schemas"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#1-get-context-1"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a list of schemas")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#2-post-context-1"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Upload a new schema")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#3-get-contextschema_id"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{schema_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a schema within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#4-delete-contextschema_id"},"DELETE")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{schema_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Delete a schema within a context")))),(0,i.kt)("h4",{id:"1-get-context-1"},"1. GET /{context}"),(0,i.kt)("h5",{id:"description-4"},"Description"),(0,i.kt)("p",null,"Get all simulation schemas in a specific context."),(0,i.kt)("h5",{id:"request-4"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-4"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of name and id of every single simulation schemas."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": "schema1",\n "name": "Schema 1"\n }\n]\n')),(0,i.kt)("h4",{id:"2-post-context-1"},"2. POST /{context}"),(0,i.kt)("h5",{id:"description-5"},"Description"),(0,i.kt)("p",null,"Create a new schema in a specific context."),(0,i.kt)("h5",{id:"request-5"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-5"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of name and id of every single simulation schemas."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"Schema created succesfully"\n')),(0,i.kt)("h4",{id:"3-get-contextschema_id"},"3. GET /{context}/{schema_id}"),(0,i.kt)("h5",{id:"description-6"},"Description"),(0,i.kt)("p",null,"Get a schema in a specific context."),(0,i.kt)("h5",{id:"request-6"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{schema_id}")),(0,i.kt)("h5",{id:"response-6"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": "schema2",\n "fmus": [\n {\n "id": "Controller",\n "inputs": [\n {\n "id": "u_s"\n },\n {\n "id": "u_m"\n }\n ],\n "outputs": [\n {\n "id": "y"\n }\n ]\n },\n {\n "id": "Drivetrain",\n "inputs": [\n {\n "id": "tau"\n }\n ],\n "outputs": [\n {\n "id": "w"\n }\n ]\n }\n ],\n "name": "Schema 2",\n "schema": [\n {\n "to": {\n "id": "Controller",\n "var": "u_s"\n },\n "from": {\n "var": "w_ref"\n }\n },\n {\n "to": {\n "id": "Controller",\n "var": "u_m"\n },\n "from": {\n "id": "Drivetrain",\n "var": "w"\n }\n },\n {\n "to": {\n "id": "Drivetrain",\n "var": "tau"\n },\n "from": {\n "id": "Controller",\n "var": "y"\n }\n },\n {\n "to": {\n "var": "w"\n },\n "from": {\n "id": "Drivetrain",\n "var": "w"\n }\n }\n ],\n "description": "Testing schema",\n "relatedTwins": [\n "Twin1"\n ]\n }\n]\n')),(0,i.kt)("h4",{id:"4-delete-contextschema_id"},"4. DELETE /{context}/{schema_id}"),(0,i.kt)("h5",{id:"description-7"},"Description"),(0,i.kt)("p",null,"Delete a schema in a specific context."),(0,i.kt)("h5",{id:"request-7"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DELETE"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{schema_id}")),(0,i.kt)("h5",{id:"response-7"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"Schema deleted succesfully"\n')),(0,i.kt)("hr",null),(0,i.kt)("h3",{id:"simulation-endpoints"},"Simulation endpoints"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Endpoint /fmi/simulations"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#1-get-context-2"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve a list of running simulations")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#2-post-context-2"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}"),(0,i.kt)("td",{parentName:"tr",align:null},"Deploy simulation")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#3-get-contextsimulation_id"},"GET")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Retrieve simulation info within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#4-delete-contextsimulation_id"},"DELETE")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}"),(0,i.kt)("td",{parentName:"tr",align:null},"Delete a simulation within a context")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#5-post-contextsimulation_idresume"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}/resume"),(0,i.kt)("td",{parentName:"tr",align:null},"Resume a specific simulation")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("a",{parentName:"td",href:"#6-post-contextsimulation_idpause"},"POST")),(0,i.kt)("td",{parentName:"tr",align:null},"/{context}/{simulation_id}/pause"),(0,i.kt)("td",{parentName:"tr",align:null},"Stops a specific simulation")))),(0,i.kt)("h4",{id:"1-get-context-2"},"1. GET /{context}"),(0,i.kt)("h5",{id:"description-8"},"Description"),(0,i.kt)("p",null,"Get all running simulations in a specific context."),(0,i.kt)("h5",{id:"request-8"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-8"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")," A list of information of every single running simulations."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'\n[\n {\n "schema-id": "schema1",\n "simulation-id": "pruebabouncingball",\n "namespace": "opentwins",\n "type": "one-time",\n "status": "Active",\n "pods": [\n {\n "simulation-id": "pruebabouncingball",\n "phase": "Running",\n "status": false,\n "creation_timestamp": "2024/09/26, 03:06:06+0000"\n }\n ]\n }\n]\n\n')),(0,i.kt)("h4",{id:"2-post-context-2"},"2. POST /{context}"),(0,i.kt)("h5",{id:"description-9"},"Description"),(0,i.kt)("p",null,"Create a new simulation using a existing schema in a specific context."),(0,i.kt)("h5",{id:"request-9"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}")),(0,i.kt)("h5",{id:"response-9"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"true"\n')),(0,i.kt)("h4",{id:"3-get-contextsimulation_id"},"3. GET /{context}/{simulation_id}"),(0,i.kt)("h5",{id:"description-10"},"Description"),(0,i.kt)("p",null,"Get all information about a specific simulation in a specific context."),(0,i.kt)("h5",{id:"request-10"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"GET"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}")),(0,i.kt)("h5",{id:"response-10"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "api_version": "batch/v1",\n "kind": "Job",\n "metadata": {\n "annotations": null,\n "creation_timestamp": "2024-09-26 03:06:06+00:00",\n "deletion_grace_period_seconds": null,\n "deletion_timestamp": null,\n .\n .\n .\n }\n}\n')),(0,i.kt)("h4",{id:"4-delete-contextsimulation_id"},"4. DELETE /{context}/{simulation_id}"),(0,i.kt)("h5",{id:"description-11"},"Description"),(0,i.kt)("p",null,"Delete specific simulation in a specific context."),(0,i.kt)("h5",{id:"request-11"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DELETE"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}")),(0,i.kt)("h5",{id:"response-11"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"Response Body:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"Schema deleted succesfully"\n')),(0,i.kt)("h4",{id:"5-post-contextsimulation_idresume"},"5. POST /{context}/{simulation_id}/resume"),(0,i.kt)("h5",{id:"description-12"},"Description"),(0,i.kt)("p",null,"Resume paused simulation in a specific context."),(0,i.kt)("h5",{id:"request-12"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}/resume")),(0,i.kt)("h5",{id:"response-12"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK")," "),(0,i.kt)("h4",{id:"6-post-contextsimulation_idpause"},"6. POST /{context}/{simulation_id}/pause"),(0,i.kt)("h5",{id:"description-13"},"Description"),(0,i.kt)("p",null,"Pause simulation in a specific context."),(0,i.kt)("h5",{id:"request-13"},"Request"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Method:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"POST"),(0,i.kt)("br",{parentName:"p"}),"\n",(0,i.kt)("strong",{parentName:"p"},"URL:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"/{context}/{simulation_id}/pause")),(0,i.kt)("h5",{id:"response-13"},"Response"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Status code:")," ",(0,i.kt)("inlineCode",{parentName:"p"},"200 OK")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6a6251fe.ed7cf9fb.js b/assets/js/6a6251fe.ed7cf9fb.js deleted file mode 100644 index 4474eec..0000000 --- a/assets/js/6a6251fe.ed7cf9fb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5284],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>h});var a=t(7294);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(l[t]=e[t]);return l}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var s=a.createContext({}),p=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},m=function(e){var n=p(e.components);return a.createElement(s.Provider,{value:n},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),u=p(t),d=l,h=u["".concat(s,".").concat(d)]||u[d]||c[d]||r;return t?a.createElement(h,i(i({ref:n},m),{},{components:t})):a.createElement(h,i({ref:n},m))}));function h(e,n){var t=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var r=t.length,i=new Array(r);i[0]=d;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[u]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=t(7462),l=(t(7294),t(3905));const r={sidebar_position:1},i="Installation Guide",o={unversionedId:"fmi/installation",id:"fmi/installation",title:"Installation Guide",description:"The FMI simulation service is currently being tested, so please be patient, as soon as it is properly tested, the public image will be available on Docker Hub.",source:"@site/docs/fmi/installation.md",sourceDirName:"fmi",slug:"/fmi/installation",permalink:"/opentwins/docs/fmi/installation",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/fmi/installation.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"FMI Simulation",permalink:"/opentwins/docs/category/fmi-simulation"},next:{title:"FMI Simulation concepts",permalink:"/opentwins/docs/fmi/concepts"}},s={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Method 1: Helm Installation (WIP)",id:"method-1-helm-installation-wip",level:2},{value:"Method 2: Manual Installation",id:"method-2-manual-installation",level:2},{value:"Step 1: Deploy the Kubernetes Deployment",id:"step-1-deploy-the-kubernetes-deployment",level:3},{value:"Step 2: Create a Kubernetes Service",id:"step-2-create-a-kubernetes-service",level:3},{value:"Step 3: Verify the installation",id:"step-3-verify-the-installation",level:3}],m={toc:p},u="wrapper";function c(e){let{components:n,...t}=e;return(0,l.kt)(u,(0,a.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"installation-guide"},"Installation Guide"),(0,l.kt)("admonition",{type:"warning"},(0,l.kt)("p",{parentName:"admonition"},"The FMI simulation service is currently being tested, so please be patient, as soon as it is properly tested, the public image will be available on Docker Hub.")),(0,l.kt)("p",null,"This guide explains how to install the component using two methods:"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("strong",{parentName:"li"},"Helm")," (Work in Progress)"),(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("strong",{parentName:"li"},"Manual Installation")," using Kubernetes manifests (Deployment and Service)")),(0,l.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,l.kt)("p",null,"This guide asumes that you have OpenTwins already installed."),(0,l.kt)("p",null,"Before you begin, ensure you have the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Access to a Kubernetes cluster"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"kubectl")," installed and configured"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," (for Helm installation)")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"method-1-helm-installation-wip"},"Method 1: Helm Installation (WIP)"),(0,l.kt)("admonition",{type:"warning"},(0,l.kt)("p",{parentName:"admonition"},"This method is currently a Work in Progress (WIP) and may not be fully functional yet. We recomend using manual installation.")),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("strong",{parentName:"p"},"Add the Helm repository")," (once available):"),(0,l.kt)("pre",{parentName:"li"},(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\n"))),(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("strong",{parentName:"p"},"Update Helm repositories"),":"),(0,l.kt)("pre",{parentName:"li"},(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo update\n"))),(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("strong",{parentName:"p"},"Install the component"),":"),(0,l.kt)("pre",{parentName:"li"},(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"helm install --namespace \n")))),(0,l.kt)("p",null,"For additional configuration options, refer to the ",(0,l.kt)("a",{parentName:"p",href:"https://helm.sh/docs/"},"Helm documentation"),"."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"method-2-manual-installation"},"Method 2: Manual Installation"),(0,l.kt)("p",null,"You can manually deploy the component by creating a Kubernetes Deployment resource and a Service."),(0,l.kt)("h3",{id:"step-1-deploy-the-kubernetes-deployment"},"Step 1: Deploy the Kubernetes Deployment"),(0,l.kt)("p",null,"Create a YAML file for the Deployment (e.g., ",(0,l.kt)("inlineCode",{parentName:"p"},"deployment.yaml"),"):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-yaml"},"\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n labels:\n name: opentwins-fmi-api\n name: opentwins-fmi-api\nspec:\n replicas: 1\n selector:\n matchLabels:\n name: pod-opentwins-fmi-api\n template:\n metadata:\n labels:\n name: pod-opentwins-fmi-api\n name: opentwins-fmi-api\n spec:\n serviceAccountName: ot-agents\n automountServiceAccountToken: true\n containers:\n - image: ertis/opentwins-fmi-simulator-api-v2:latest\n name: opentwins-fmi-api\n env:\n - name: KUBE_NAMESPACE\n value: \n - name: INSIDE_CLUSTER\n value: \n - name: INFLUXDB_HOST\n value: \n - name: INFLUXDB_TOKEN\n value: \n - name: INFLUXDB_DB\n value: \n - name: MINIO_TOKEN\n value: \n - name: MINIO_URL\n value: \n - name: MINIO_A_KEY\n value: \n - name: MINIO_S_KEY\n value: \n - name: POSTGRE_HOST\n value: \n - name: POSTGRE_PORT\n value: \n - name: POSTGRE_DB\n value: \n - name: POSTGRE_USER\n value: \n - name: POSTGRE_PASSWORD\n value: \n - name: BROKER_TYPE\n value: \n - name: BROKER_IP\n value: \n - name: BROKER_PORT\n value: \n - name: BROKER_TOPIC\n value: \n - name: BROKER_USERNAME\n value: \n - name: BROKER_PASSWORD\n value: \n ports:\n - containerPort: 8001\n imagePullPolicy: Always\n")),(0,l.kt)("p",null,"Apply the Deployment using the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl apply -f deployment.yaml -n \n")),(0,l.kt)("h3",{id:"step-2-create-a-kubernetes-service"},"Step 2: Create a Kubernetes Service"),(0,l.kt)("p",null,"Next, create a YAML file for the Service (e.g., ",(0,l.kt)("inlineCode",{parentName:"p"},"service.yaml"),"):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-yaml"},'apiVersion: v1\nkind: Service\nmetadata:\n name: opentwins-fmi-api\nspec:\n selector:\n name: pod-opentwins-fmi-api\n type: NodePort\n ports:\n - protocol: "TCP"\n port: 8000\n nodePort: \n targetPort: 8000\n\n')),(0,l.kt)("p",null,"Apply the Service configuration using the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl apply -f service.yaml -n \n")),(0,l.kt)("h3",{id:"step-3-verify-the-installation"},"Step 3: Verify the installation"),(0,l.kt)("p",null,"After deploying both the deployment and the service, veryfy that everything is running correctly:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl get deployments -n \nkubectl get services -n \n")),(0,l.kt)("p",null,"You should see your Deployment and Service listed, and the component should be ready for use."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/70066871.508587da.js b/assets/js/70066871.f40ee112.js similarity index 54% rename from assets/js/70066871.508587da.js rename to assets/js/70066871.f40ee112.js index a949647..d877b08 100644 --- a/assets/js/70066871.508587da.js +++ b/assets/js/70066871.f40ee112.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5466],{5470:i=>{i.exports=JSON.parse('{"title":"Unity visualization","slug":"/category/unity-visualization","permalink":"/opentwins/docs/category/unity-visualization","navigation":{"previous":{"title":"Create a digital twin","permalink":"/opentwins/docs/guides/dt-schema-creation"},"next":{"title":"Creation of Unity WebGL build","permalink":"/opentwins/docs/guides/unity/creating-unity-build"}}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5466],{5470:i=>{i.exports=JSON.parse('{"title":"Unity visualization","slug":"/category/unity-visualization","permalink":"/opentwins/docs/category/unity-visualization","navigation":{"previous":{"title":"API Documentation","permalink":"/opentwins/docs/guides/fmi/API"},"next":{"title":"Creation of Unity WebGL build","permalink":"/opentwins/docs/guides/unity/creating-unity-build"}}}')}}]); \ No newline at end of file diff --git a/assets/js/74876495.cd08c5dc.js b/assets/js/74876495.09b764ba.js similarity index 95% rename from assets/js/74876495.cd08c5dc.js rename to assets/js/74876495.09b764ba.js index 8ed9e17..ba72755 100644 --- a/assets/js/74876495.cd08c5dc.js +++ b/assets/js/74876495.09b764ba.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5049],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var i=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 o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=i.createContext({}),c=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return i.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),u=a,m=d["".concat(l,".").concat(u)]||d[u]||h[u]||o;return n?i.createElement(m,r(r({ref:t},p),{},{components:n})):i.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var i=n(7462),a=(n(7294),n(3905));n(4996),n(941);const o={sidebar_position:1},r="Quickstart",s={unversionedId:"quickstart",id:"quickstart",title:"Quickstart",description:"Welcome to OpenTwins, a flexible platform adapted to your needs! Although OpenTwins offers extensive customization options, we understand the importance of simplicity for beginners. Therefore, let's embark on a short journey together, showing you the quickest route to deploy the platform and develop a functional digital twin.",source:"@site/docs/quickstart.mdx",sourceDirName:".",slug:"/quickstart",permalink:"/opentwins/docs/quickstart",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/quickstart.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/opentwins/docs/category/overview"}},l={},c=[{value:"Installation",id:"installation",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Deploy",id:"deploy",level:3},{value:"Configuration",id:"configuration",level:3},{value:"Create your first digital twin",id:"create-your-first-digital-twin",level:2},{value:"Design",id:"design",level:3},{value:"Definition",id:"definition",level:3},{value:"Create Car type",id:"create-car-type",level:4},{value:"Create Wheel type",id:"create-wheel-type",level:4},{value:"Create the digital twins",id:"create-the-digital-twins",level:4},{value:"Connection",id:"connection",level:3},{value:"Visualization",id:"visualization",level:3}],p={toc:c},d="wrapper";function h(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,i.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"quickstart"},"Quickstart"),(0,a.kt)("p",null,"Welcome to OpenTwins, a flexible platform adapted to your needs! Although OpenTwins offers extensive customization options, we understand the importance of simplicity for beginners. Therefore, let's embark on a short journey together, showing you the quickest route to deploy the platform and develop a functional digital twin."),(0,a.kt)("h2",{id:"installation"},"Installation"),(0,a.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("p",null,"Please be sure you have the following utilities installed on your host machine:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," v3")),(0,a.kt)("p",null,"If you don't have a Kubernetes cluster, you can set one up on local using ",(0,a.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/"},"minikube"),". For a smooth deployment experience, we suggest you use the following minimum configuration values."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"minikube start --cpus 4 --disk-size 40gb --memory 8192\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config use-context minikube\n")),(0,a.kt)("h3",{id:"deploy"},"Deploy"),(0,a.kt)("p",null,"The quickest way to deploy OpenTwins is ",(0,a.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/using_helm/"},"using Helm"),"."),(0,a.kt)("p",null,"The following command adds the ERTIS repository where the OpenTwins helm chart is located."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\n")),(0,a.kt)("p",null,"To deploy the platform with recommended functionality, use the command below:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade --install opentwins ertis/OpenTwins --wait --dependency-update\n")),(0,a.kt)("p",null,"To modify the components to be deployed and connected during the installation, you can check the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/using-helm"},"installation via Helm"),"."),(0,a.kt)("h3",{id:"configuration"},"Configuration"),(0,a.kt)("p",null,"If you've correctly installed OpenTwins Helm using the default settings, all connections should be established.\nThe final step involves ",(0,a.kt)("strong",{parentName:"p"},"configuring the platform interface plugin")," by adding the addresses of the Eclipse Ditto nginx service and the Ditto Extended API component into the plugin's configuration section.\nCheck the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/using-helm#configuration"},"installation documentation")," for more details."),(0,a.kt)("h2",{id:"create-your-first-digital-twin"},"Create your first digital twin"),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(2979).Z,alt:"Create digital twins",style:{width:700,margin:40}})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"A digital twin must be at least a synchronized replica of a real system or object"),". To create it, the first step involves understanding the purpose of the digital twin, designing its structure and defining its most relevant characteristics. Next, it is necessary to define this information in OpenTwins and then connect the data sources that will feed the model. Finally, it is necessary to represent the data in a way that is understandable to any user."),(0,a.kt)("p",null,"Optionally, other useful functionalities can be added to the digital twin. In OpenTwins, we offer the integration of AI/ML models, the addition of 3D models and the execution of FMI or containerized simulations. However, this tutorial will not cover these extra functionalities, so we recommend consulting their respective guides for more information."),(0,a.kt)("p",null,"Following these steps, we will use OpenTwins to develop the ",(0,a.kt)("strong",{parentName:"p"},"digital twin of a car"),". In this case, for simplicity, we will focus only on the speed and direction of the car's four wheels. In addition, we will record the GPS location of the vehicle for tracking."),(0,a.kt)("h3",{id:"design"},"Design"),(0,a.kt)("p",null,"Taking advantage of the platform's functionalities, we will create a ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twins-composition"},"composite digital twin"),".\nFor this purpose, we will define ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twin-type"},"types"),' "car" and "wheel", which will abstract information about the car and the wheel, respectively.\nThese types will be linked by a composition relation, which means that a car comprises four wheels. Once all this is set up, instantiating the car as a digital twin will automatically generate twins for all four wheels.\nIn this way, we can independently access the data for each wheel and easily add digital twins for other cars or other contexts.'),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(4347).Z,alt:"Create digital twins",style:{width:700}})),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The creation of ",(0,a.kt)("strong",{parentName:"p"},"types is not essential")," to create a digital twin, but ",(0,a.kt)("strong",{parentName:"p"},"it is recommended")," to facilitate future work. You can create digital twins directly without defining a type, just select the ",(0,a.kt)("em",{parentName:"p"},"from scratch")," option in the twin creation form.")),(0,a.kt)("h3",{id:"definition"},"Definition"),(0,a.kt)("h4",{id:"create-car-type"},"Create Car type"),(0,a.kt)("p",null,"First, we will create the car type. To do so, we navigate to the ",(0,a.kt)("em",{parentName:"p"},"Types")," section in the interface and click on the blue ",(0,a.kt)("em",{parentName:"p"},"Create new type")," button. In this form, we must fill in the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twin-content"},"digital twin information")," that will be common for all instances. This includes the name, description and image of the twin, along with the values it will store, in this case ",(0,a.kt)("strong",{parentName:"p"},"gps"),".\nWe will define this type within a namespace and assign it a name.\nThe combination of the namespace and the name will be referred to as the ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/basic-thing.html#thing-id"},"thingId"),"."),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Screenshots of the filled form"),(0,a.kt)("div",null,(0,a.kt)("center",null,(0,a.kt)("img",{src:n(9636).Z,alt:"Create type - Identification and type information"}),(0,a.kt)("img",{src:n(2748).Z,alt:"Create type - attributes and features"})))),(0,a.kt)("p",null,"The JSON generated in ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/basic-thing.html#model-specification"},"Ditto Thing")," model is shown to the right of the form, which in this case corresponds to the following JSON:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "thingId": "example:car",\n "policyId": "default:basic_policy",\n "attributes": {\n "name": "Car",\n "description": "Digital twin example for quickstart",\n "image": "https://images.pexels.com/photos/119435/pexels-photo-119435.jpeg"\n },\n "features": {\n "gps": {\n "properties": {\n "value": null\n }\n }\n }\n}\n')),(0,a.kt)("p",null,"Click on the blue ",(0,a.kt)("em",{parentName:"p"},"Create type")," button to create the type. A message should appear indicating that the type has been successfully created. You can close this message and return to the main screen."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"If you have installed OpenTwins with Helm, you should have a basic policy. Currently, we do not take into account the restriction of access to digital twins by ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/basic-policy.html"},"policy"),", so we always use the same one. Still, using this functionality is possible with OpenTwins, although you must interact directly with Eclipse Ditto. "),(0,a.kt)("p",{parentName:"admonition"},"For more details see the ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/http-api-doc.html#/Policies"},"Eclipse Ditto documentation"),".")),(0,a.kt)("h4",{id:"create-wheel-type"},"Create Wheel type"),(0,a.kt)("p",null,"Next we will create the type for the wheels.\nIn the list of types, we will access the type of the car we have just created to see its information.\nHere we select the ",(0,a.kt)("em",{parentName:"p"},"children")," tab and click on the ",(0,a.kt)("em",{parentName:"p"},"Create new type")," button.\nThis form is almost identical to the previous one, with the difference that we can directly specify the number of instances of this new type to be created when a car type is instantiated.\nIn our example we will have to indicate a 4 in this section and fill in the rest of the form as before.\nThis type, in addition to its identification and basic information, will have as features the ",(0,a.kt)("strong",{parentName:"p"},"velocity")," and ",(0,a.kt)("strong",{parentName:"p"},"direction")," of the wheel."),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Screenshots of the filled form"),(0,a.kt)("div",null,(0,a.kt)("center",null,(0,a.kt)("img",{src:n(8775).Z,alt:"Create type - Identification and type information"}),(0,a.kt)("img",{src:n(8226).Z,alt:"Create type - attributes and features"})))),(0,a.kt)("p",null,"In this case the JSON of the generated Ditto Thing is the following:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "thingId": "example:wheel",\n "policyId": "default:basic_policy",\n "attributes": {\n "name": "Wheel",\n "description": "Digital twin example for quickstart",\n "image": "https://images.pexels.com/photos/111766/pexels-photo-111766.jpeg"\n },\n "features": {\n "velocity": {\n "properties": {\n "value": null\n }\n },\n "direction": {\n "properties": {\n "value": null\n }\n }\n }\n}\n')),(0,a.kt)("p",null,"After clicking the ",(0,a.kt)("em",{parentName:"p"},"Create type")," button, a confirmation message will appear.\nIf we now navigate to the children tab of the car type, it will show that the wheel type is one of its children and will be instantiated four times."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(7390).Z,alt:"Children of car type",style:{width:600}})),(0,a.kt)("h4",{id:"create-the-digital-twins"},"Create the digital twins"),(0,a.kt)("p",null,"All that remains is to instantiate the car type so that all the twins are created.\nTo do this, navigate to the ",(0,a.kt)("em",{parentName:"p"},"Twins")," section and click on ",(0,a.kt)("em",{parentName:"p"},"Create a new twin"),".\nIn the form, specify the identification of the twin and select the car type.\nAll data will be filled in automatically, though you can modify it if desired by activating the customization switch."),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Screenshots of the filled form"),(0,a.kt)("div",null,(0,a.kt)("center",null,(0,a.kt)("img",{src:n(9726).Z,alt:"Create twin form"})))),(0,a.kt)("p",null,"After clicking on ",(0,a.kt)("em",{parentName:"p"},"Create twin"),", the 5 digital twins will be generated automatically. A successfull message will appear when the process is finished.\nIf we check the list of twins, we will see our twin example:car.\nBy clicking on it and accessing the children tab, we will find four twins corresponding to its wheels, each with the features specified in their respective type."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(4008).Z,alt:"Children of car type"})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"The composite digital twin has already been defined.")),(0,a.kt)("h3",{id:"connection"},"Connection"),(0,a.kt)("p",null,"Once we have the digital twin defined, we need to feed it with data.\nEclipse Ditto requires data updates to be sent in ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/protocol-specification.html#dittoProtocolEnvelope"},"Ditto Protocol"),", which is a JSON format that indicates which parts of the digital twin we want to update and how to do it."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"It is also possible to connect Eclipse Ditto with messaging brokers that use other message formats.\nWe can add a ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/connectivity-mapping.html#javascript-examples"},"JavaScript mapping")," to the Eclipse Ditto connection, which will automatically transform the messages to the Ditto Protocol format.")),(0,a.kt)("p",null,"For Eclipse Ditto to collect the data, it is necessary to establish a ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/connectivity-overview.html"},"connection")," through MQTT, AMQP or Kafka, providing all the required information (address, port, credentials, etc.).\nIn this example, we will take advantage of the source connection that is automatically created with the installation of Helm (",(0,a.kt)("inlineCode",{parentName:"p"},"mosquitto-source-connection"),").\nThis connection pulls messages via MQTT from the Mosquitto deployed with the platform, using any subtopic within the telemetry topic (i.e. ",(0,a.kt)("inlineCode",{parentName:"p"},"telemetry/#"),").\nBy default, it does not include any JavaScript mapping, so we will send messages directly in Ditto Protocol.\nIf you need to use another connection, see the ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/http-api-doc.html#/Connections"},"Eclipse Ditto documentation"),". "),(0,a.kt)("p",null,"We will need to get the address of Mosquitto, which will depend on your installation."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"If you are using a cluster in your network"),", the address will be your cluster address and the port can be obtained by running ",(0,a.kt)("inlineCode",{parentName:"li"},"kubectl get services")," and looking up the ",(0,a.kt)("a",{parentName:"li",href:"https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport"},(0,a.kt)("em",{parentName:"a"},"NodePort"))," of the Mosquitto service (default should be 30511)."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"If you are using Minikube"),", you must expose the Mosquitto service in order to access it from your ",(0,a.kt)("em",{parentName:"li"},"localhost"),".\nTo do this, find the name of the service with ",(0,a.kt)("inlineCode",{parentName:"li"},"kubectl get services")," and then run ",(0,a.kt)("inlineCode",{parentName:"li"},"minikube service --url"),".\nThis will return a URL with the address and port to connect to.")),(0,a.kt)("p",null,"Since we don't have real data, we are going to create a Python script that generates random data from the car and its wheels every 5 seconds and sends it in Ditto Protocol to Mosquitto.\nTo run the script we will need to install the ",(0,a.kt)("a",{parentName:"p",href:"https://pypi.org/project/paho-mqtt/"},"Paho library for MQTT")," (typing_extensions is one of its dependencies)."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-shell"},"pip install paho-mqtt\npip install typing_extensions\n")),(0,a.kt)("p",null,"In the following script you must ",(0,a.kt)("strong",{parentName:"p"},"change the MQTT broker address and port")," to your own."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-python"},'import paho.mqtt.client as mqtt\nimport random\nimport time\nimport json\n\n# Digital twin info\nnamespace = "example"\ncar_name = "mycar"\nwheels_name = "mycar:wheel_"\n\n# MQTT info\nbroker = "localhost" # MQTT broker address\nport = 1883 # MQTT port\ntopic = "telemetry/" # Topic where data will be published\n\n# MQTT connection\ndef on_connect(client, userdata, flags, rc):\n if rc == 0:\n print("Successful connection")\n else:\n print(f"Connection failed with code {rc}")\n\nclient = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)\nclient.on_connect = on_connect\nclient.username_pw_set(username, password)\nclient.connect(broker, port, 60)\n\n# Data generator\ndef generate_wheel_data():\n velocity = random.uniform(0, 100) # Generate random velocity (between 0 and 100 km/h)\n direction = random.uniform(-45, 45) # Generate random direction (between -45 and 45 degrees)\n return velocity, direction\n\ndef generate_gps_data():\n latitude = random.uniform(-90.0, 90.0)\n longitude = random.uniform(-180.0, 180.0)\n return latitude, longitude\n\n# Ditto Protocol\ndef get_ditto_protocol_value_car(time, latitude, longitude):\n return {\n "gps" : {\n "properties": {\n "latitude": latitude,\n "longitude": longitude,\n "time": time\n }\n }\n }\n\ndef get_ditto_protocol_value_wheel(time, velocity, direction):\n return {\n "velocity" : {\n "properties": {\n "value": velocity,\n "time": time\n }\n },\n "direction": {\n "properties" : {\n "value": direction,\n "time" : time\n }\n }\n }\n\ndef get_ditto_protocol_msg(name, value):\n return {\n "topic": "{}/{}/things/twin/commands/merge".format(namespace, name),\n "headers": {\n "content-type": "application/merge-patch+json"\n },\n "path": "/features",\n "value": value\n }\n\n# Send data\ntry:\n while True:\n t = round(time.time() * 1000) # Unix ms\n \n # Car twin\n latitude, longitude = generate_gps_data()\n msg = get_ditto_protocol_msg(car_name, get_ditto_protocol_value_car(t, latitude, longitude))\n client.publish(topic + namespace + "/" + car_name, json.dumps(msg))\n print(car_name + " data published")\n \n # Wheels twins\n for i in range(1, 5):\n name = wheels_name+str(i)\n velocity, direction = generate_wheel_data()\n msg = get_ditto_protocol_msg(name, get_ditto_protocol_value_wheel(t, velocity, direction))\n client.publish(topic + namespace + "/" + name, json.dumps(msg))\n print(name + " data published")\n \n time.sleep(5)\n \nexcept KeyboardInterrupt:\n client.disconnect()\n')),(0,a.kt)("p",null,"When you ",(0,a.kt)("strong",{parentName:"p"},"run the script"),", the data should start to be stored in the digital twins.\nYou can see if messages are being received by checking the information of the twins, where the values of their features will now have data."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(8606).Z,alt:"Children of car type",style:{width:700}})),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Are the twins not being updated?"),(0,a.kt)("div",null,(0,a.kt)("p",null,"You can check if messages arrive to Mosquitto by using ",(0,a.kt)("a",{parentName:"p",href:"https://mqtt-explorer.com/"},"MQTT explorer"),".\nIf they are sending correctly, you should see something like the following image:"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"MQTT explorer",src:n(1845).Z,width:"1140",height:"628"})),(0,a.kt)("p",null,"And the messages being sent should be like these:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "topic": "example/mycar:wheel_2/things/twin/commands/merge",\n "headers": {\n "content-type": "application/merge-patch+json"\n },\n "path": "/features",\n "value": {\n "velocity": {\n "properties": {\n "value": 44.07908610511725,\n "time": 1715943644787\n }\n },\n "direction": {\n "properties": {\n "value": 37.92163063527694,\n "time": 1715943644787\n }\n }\n }\n}\n')),(0,a.kt)("p",null,"If the ",(0,a.kt)("strong",{parentName:"p"},"messages are not being received"),", debug the code to see what might be happening. Most likely you are not connecting correctly to Mosquitto (wrong address or port)."),(0,a.kt)("p",null,"If the ",(0,a.kt)("strong",{parentName:"p"},"messages are being received"),", then the problem is in the source connection to Eclipse Ditto. Check the connection logs with ",(0,a.kt)("inlineCode",{parentName:"p"},"http://:/api/2/connections/mosquitto-source-connection/logs"),".\nThe Eclipse Ditto ip and port are obtained the same as mosquitto's, but since Ditto has more than one service, you have to query/expose the ",(0,a.kt)("strong",{parentName:"p"},"nginx")," one."))),(0,a.kt)("h3",{id:"visualization"},"Visualization"),(0,a.kt)("p",null,"Finally, we need to present the data in a user-friendly and meaningful way for the users of the digital twin.\nTo achieve this, we will create a new ",(0,a.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/dashboards/"},"dashboard")," in Grafana and add ",(0,a.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/panels-visualizations/"},"panels")," to display the relevant digital twin information."),(0,a.kt)("p",null,"The digital twin data is stored in an ",(0,a.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/influxdb/v2/"},"InfluxDB2")," database, so we will have to query the information using ",(0,a.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/flux/v0/"},"Flux")," language.\nIf OpenTwins has been installed via Helm with default values, the ",(0,a.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/datasources/"},"connection")," between InfluxDB and Grafana should already be established, so it will only be necessary to select it as data source when creating a panel."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(159).Z,alt:"Children of car type",style:{width:400}})),(0,a.kt)("p",null,"In this example, we will demonstrate a basic visualization. However, ",(0,a.kt)("strong",{parentName:"p"},"you can use any of Grafana's functionalities and plugins to customize it according to your specific objectives"),".\nWe will create four panels: one displaying the most recent GPS data of the car, another showing the evolution of the GPS data, a third panel indicating the current direction of all the wheels, and a fourth comparing the velocity of each wheel.\nThe result would look something like this:"),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(589).Z,alt:"Grafana dashboard"})),(0,a.kt)("p",null,"For each of the four panels, we have selected the most convenient chart type, kept the default settings and added the related query in the Query section."),(0,a.kt)("p",null,"The panel displaying the ",(0,a.kt)("strong",{parentName:"p"},"current GPS")," data extracts the longitude and latitude information from the digital twin ",(0,a.kt)("em",{parentName:"p"},"example:mycar"),".\nIt renames the fields for proper display, retains the relevant fields, sorts the results by time, and keeps only the most recent entry."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => r["thingId"] == "example:mycar")\n |> filter(fn: (r) => r["_field"] == "value_gps_properties_latitude" or r["_field"] == "value_gps_properties_longitude")\n |> map(fn: (r) => ({ r with _field: strings.replace(v: r["_field"], t: "value_gps_properties_", u: "", i: 2) }))\n |> keep (columns: ["_value", "_field", "_time"])\n |> sort(columns: ["_time"], desc: false) \n |> last() \n')),(0,a.kt)("p",null,"The panel for show the ",(0,a.kt)("strong",{parentName:"p"},"GPS evolution")," also extracts the latitude and longitude data from the digital twin ",(0,a.kt)("em",{parentName:"p"},"example:mycar"),", but keeps all the entries instead of just the last one."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => r["thingId"] == "example:mycar")\n |> filter(fn: (r) => r["_field"] == "value_gps_properties_latitude" or r["_field"] == "value_gps_properties_longitude")\n |> map(fn: (r) => ({ r with _field: strings.replace(v: r["_field"], t: "value_gps_properties_", u: "", i: 2) }))\n |> keep (columns: ["_value", "_field", "_time"])\n')),(0,a.kt)("p",null,"The panel displaying the ",(0,a.kt)("strong",{parentName:"p"},"current direction of wheels")," extracts the direction data of the four twins corresponding to the wheels, identified by starting with ",(0,a.kt)("em",{parentName:"p"},"example:mycar:wheel_"),".\nIt modifies the identifiers of the twins for a more readable display and retains the most recent value based on time."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => strings.hasPrefix(v: r["thingId"], prefix: "example:mycar:wheel_"))\n |> filter(fn: (r) => r["_field"] == "value_direction_properties_value")\n |> map(fn: (r) => ({ r with thingId: strings.replace(v: r["thingId"], t: "example:mycar:", u: "", i: 2) }))\n |> keep (columns: ["thingId", "_value", "_time"])\n |> sort(columns: ["_time"], desc: false) \n |> last()\n')),(0,a.kt)("p",null,"Finally, the panel that makes a ",(0,a.kt)("strong",{parentName:"p"},"wheels velocity comparison")," is similar to the previous one, although extracting the velocity data from the 4 twins instead of the direction and keeping all the entries."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => strings.hasPrefix(v: r["thingId"], prefix: "example:mycar:wheel_"))\n |> filter(fn: (r) => r["_field"] == "value_velocity_properties_value")\n |> map(fn: (r) => ({ r with thingId: strings.replace(v: r["thingId"], t: "example:mycar:", u: "", i: 2) }))\n |> keep (columns: ["thingId", "_value", "_time"])\n')),(0,a.kt)("p",null,"This satisfies the basic requirements to consider a system as a digital twin.\nHowever, to take full advantage of its capabilities, we recommend including other functionalities or additional data sources.\nThis will allow you to obtain a more complete and accurate view of the real system.\nYou can check our ",(0,a.kt)("a",{parentName:"p",href:"./category/guides"},"guides")," for more information"))}h.isMDXComponent=!0},4008:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/children-car-twin-ca2cf91c075a327581d6ba641943742c.png"},7390:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/children-car-d181addcc20bcf1a9a75715cf3353c15.png"},2979:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-digital-twins-bd76130c9ab23c157cdfcd9dcb0fdc5b.png"},9726:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-twin-car-4a9968f0a40982680599c72e2f6d3b23.png"},9636:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-car-1-83399364c854df3e8b229885140649ba.png"},2748:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-car-2-c0b3b0d20c5b4291c77340e8a685d0c6.png"},8775:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-wheel-1-d71b44232fb9dfeebc601958e43d19fd.png"},8226:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-wheel-2-01daddbffbb636b06904956113d446fc.png"},589:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/grafana-dashboard-d0dbd9d8646a93fa599ba324ce583338.png"},159:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/grafana-datasource-e1e06ed3137227fd650fb894928415db.png"},4347:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/model-car-example-2b119ad662f43ec5caa875a83d9d7b7c.jpg"},8606:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/wheel-data-30d7b695d58b99fcec8f817d5d5b45e1.png"},1845:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/mqtt-explorer-ebaae1985874581cb44c024060bef150.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5049],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var i=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 o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=i.createContext({}),c=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return i.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),u=a,m=d["".concat(l,".").concat(u)]||d[u]||h[u]||o;return n?i.createElement(m,r(r({ref:t},p),{},{components:n})):i.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var i=n(7462),a=(n(7294),n(3905));n(4996),n(941);const o={sidebar_position:1},r="Quickstart",s={unversionedId:"quickstart",id:"quickstart",title:"Quickstart",description:"Welcome to OpenTwins, a flexible platform adapted to your needs! Although OpenTwins offers extensive customization options, we understand the importance of simplicity for beginners. Therefore, let's embark on a short journey together, showing you the quickest route to deploy the platform and develop a functional digital twin.",source:"@site/docs/quickstart.mdx",sourceDirName:".",slug:"/quickstart",permalink:"/opentwins/docs/quickstart",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/quickstart.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",next:{title:"Overview",permalink:"/opentwins/docs/category/overview"}},l={},c=[{value:"Installation",id:"installation",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Deploy",id:"deploy",level:3},{value:"Configuration",id:"configuration",level:3},{value:"Create your first digital twin",id:"create-your-first-digital-twin",level:2},{value:"Design",id:"design",level:3},{value:"Definition",id:"definition",level:3},{value:"Create Car type",id:"create-car-type",level:4},{value:"Create Wheel type",id:"create-wheel-type",level:4},{value:"Create the digital twins",id:"create-the-digital-twins",level:4},{value:"Connection",id:"connection",level:3},{value:"Visualization",id:"visualization",level:3}],p={toc:c},d="wrapper";function h(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,i.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"quickstart"},"Quickstart"),(0,a.kt)("p",null,"Welcome to OpenTwins, a flexible platform adapted to your needs! Although OpenTwins offers extensive customization options, we understand the importance of simplicity for beginners. Therefore, let's embark on a short journey together, showing you the quickest route to deploy the platform and develop a functional digital twin."),(0,a.kt)("h2",{id:"installation"},"Installation"),(0,a.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("p",null,"Please be sure you have the following utilities installed on your host machine:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," v3")),(0,a.kt)("p",null,"If you don't have a Kubernetes cluster, you can set one up on local using ",(0,a.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/"},"minikube"),". For a smooth deployment experience, we suggest you use the following minimum configuration values."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"minikube start --cpus 4 --disk-size 40gb --memory 8192\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl config use-context minikube\n")),(0,a.kt)("h3",{id:"deploy"},"Deploy"),(0,a.kt)("p",null,"The quickest way to deploy OpenTwins is ",(0,a.kt)("a",{parentName:"p",href:"https://helm.sh/docs/intro/using_helm/"},"using Helm"),"."),(0,a.kt)("p",null,"The following command adds the ERTIS repository where the OpenTwins helm chart is located."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\n")),(0,a.kt)("p",null,"To deploy the platform with recommended functionality, use the command below:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade --install opentwins ertis/OpenTwins --wait --dependency-update\n")),(0,a.kt)("p",null,"To modify the components to be deployed and connected during the installation, you can check the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/using-helm"},"installation via Helm"),"."),(0,a.kt)("h3",{id:"configuration"},"Configuration"),(0,a.kt)("p",null,"If you've correctly installed OpenTwins Helm using the default settings, all connections should be established.\nThe final step involves ",(0,a.kt)("strong",{parentName:"p"},"configuring the platform interface plugin")," by adding the addresses of the Eclipse Ditto nginx service and the Ditto Extended API component into the plugin's configuration section.\nCheck the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/using-helm#configuration"},"installation documentation")," for more details."),(0,a.kt)("h2",{id:"create-your-first-digital-twin"},"Create your first digital twin"),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(2979).Z,alt:"Create digital twins",style:{width:700,margin:40}})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"A digital twin must be at least a synchronized replica of a real system or object"),". To create it, the first step involves understanding the purpose of the digital twin, designing its structure and defining its most relevant characteristics. Next, it is necessary to define this information in OpenTwins and then connect the data sources that will feed the model. Finally, it is necessary to represent the data in a way that is understandable to any user."),(0,a.kt)("p",null,"Optionally, other useful functionalities can be added to the digital twin. In OpenTwins, we offer the integration of AI/ML models, the addition of 3D models and the execution of FMI or containerized simulations. However, this tutorial will not cover these extra functionalities, so we recommend consulting their respective guides for more information."),(0,a.kt)("p",null,"Following these steps, we will use OpenTwins to develop the ",(0,a.kt)("strong",{parentName:"p"},"digital twin of a car"),". In this case, for simplicity, we will focus only on the speed and direction of the car's four wheels. In addition, we will record the GPS location of the vehicle for tracking."),(0,a.kt)("h3",{id:"design"},"Design"),(0,a.kt)("p",null,"Taking advantage of the platform's functionalities, we will create a ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twins-composition"},"composite digital twin"),".\nFor this purpose, we will define ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twin-type"},"types"),' "car" and "wheel", which will abstract information about the car and the wheel, respectively.\nThese types will be linked by a composition relation, which means that a car comprises four wheels. Once all this is set up, instantiating the car as a digital twin will automatically generate twins for all four wheels.\nIn this way, we can independently access the data for each wheel and easily add digital twins for other cars or other contexts.'),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(4347).Z,alt:"Create digital twins",style:{width:700}})),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The creation of ",(0,a.kt)("strong",{parentName:"p"},"types is not essential")," to create a digital twin, but ",(0,a.kt)("strong",{parentName:"p"},"it is recommended")," to facilitate future work. You can create digital twins directly without defining a type, just select the ",(0,a.kt)("em",{parentName:"p"},"from scratch")," option in the twin creation form.")),(0,a.kt)("h3",{id:"definition"},"Definition"),(0,a.kt)("h4",{id:"create-car-type"},"Create Car type"),(0,a.kt)("p",null,"First, we will create the car type. To do so, we navigate to the ",(0,a.kt)("em",{parentName:"p"},"Types")," section in the interface and click on the blue ",(0,a.kt)("em",{parentName:"p"},"Create new type")," button. In this form, we must fill in the ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twin-content"},"digital twin information")," that will be common for all instances. This includes the name, description and image of the twin, along with the values it will store, in this case ",(0,a.kt)("strong",{parentName:"p"},"gps"),".\nWe will define this type within a namespace and assign it a name.\nThe combination of the namespace and the name will be referred to as the ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/basic-thing.html#thing-id"},"thingId"),"."),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Screenshots of the filled form"),(0,a.kt)("div",null,(0,a.kt)("center",null,(0,a.kt)("img",{src:n(9636).Z,alt:"Create type - Identification and type information"}),(0,a.kt)("img",{src:n(2748).Z,alt:"Create type - attributes and features"})))),(0,a.kt)("p",null,"The JSON generated in ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/basic-thing.html#model-specification"},"Ditto Thing")," model is shown to the right of the form, which in this case corresponds to the following JSON:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "thingId": "example:car",\n "policyId": "default:basic_policy",\n "attributes": {\n "name": "Car",\n "description": "Digital twin example for quickstart",\n "image": "https://images.pexels.com/photos/119435/pexels-photo-119435.jpeg"\n },\n "features": {\n "gps": {\n "properties": {\n "value": null\n }\n }\n }\n}\n')),(0,a.kt)("p",null,"Click on the blue ",(0,a.kt)("em",{parentName:"p"},"Create type")," button to create the type. A message should appear indicating that the type has been successfully created. You can close this message and return to the main screen."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"If you have installed OpenTwins with Helm, you should have a basic policy. Currently, we do not take into account the restriction of access to digital twins by ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/basic-policy.html"},"policy"),", so we always use the same one. Still, using this functionality is possible with OpenTwins, although you must interact directly with Eclipse Ditto. "),(0,a.kt)("p",{parentName:"admonition"},"For more details see the ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/http-api-doc.html#/Policies"},"Eclipse Ditto documentation"),".")),(0,a.kt)("h4",{id:"create-wheel-type"},"Create Wheel type"),(0,a.kt)("p",null,"Next we will create the type for the wheels.\nIn the list of types, we will access the type of the car we have just created to see its information.\nHere we select the ",(0,a.kt)("em",{parentName:"p"},"children")," tab and click on the ",(0,a.kt)("em",{parentName:"p"},"Create new type")," button.\nThis form is almost identical to the previous one, with the difference that we can directly specify the number of instances of this new type to be created when a car type is instantiated.\nIn our example we will have to indicate a 4 in this section and fill in the rest of the form as before.\nThis type, in addition to its identification and basic information, will have as features the ",(0,a.kt)("strong",{parentName:"p"},"velocity")," and ",(0,a.kt)("strong",{parentName:"p"},"direction")," of the wheel."),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Screenshots of the filled form"),(0,a.kt)("div",null,(0,a.kt)("center",null,(0,a.kt)("img",{src:n(8775).Z,alt:"Create type - Identification and type information"}),(0,a.kt)("img",{src:n(8226).Z,alt:"Create type - attributes and features"})))),(0,a.kt)("p",null,"In this case the JSON of the generated Ditto Thing is the following:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "thingId": "example:wheel",\n "policyId": "default:basic_policy",\n "attributes": {\n "name": "Wheel",\n "description": "Digital twin example for quickstart",\n "image": "https://images.pexels.com/photos/111766/pexels-photo-111766.jpeg"\n },\n "features": {\n "velocity": {\n "properties": {\n "value": null\n }\n },\n "direction": {\n "properties": {\n "value": null\n }\n }\n }\n}\n')),(0,a.kt)("p",null,"After clicking the ",(0,a.kt)("em",{parentName:"p"},"Create type")," button, a confirmation message will appear.\nIf we now navigate to the children tab of the car type, it will show that the wheel type is one of its children and will be instantiated four times."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(7390).Z,alt:"Children of car type",style:{width:600}})),(0,a.kt)("h4",{id:"create-the-digital-twins"},"Create the digital twins"),(0,a.kt)("p",null,"All that remains is to instantiate the car type so that all the twins are created.\nTo do this, navigate to the ",(0,a.kt)("em",{parentName:"p"},"Twins")," section and click on ",(0,a.kt)("em",{parentName:"p"},"Create a new twin"),".\nIn the form, specify the identification of the twin and select the car type.\nAll data will be filled in automatically, though you can modify it if desired by activating the customization switch."),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Screenshots of the filled form"),(0,a.kt)("div",null,(0,a.kt)("center",null,(0,a.kt)("img",{src:n(9726).Z,alt:"Create twin form"})))),(0,a.kt)("p",null,"After clicking on ",(0,a.kt)("em",{parentName:"p"},"Create twin"),", the 5 digital twins will be generated automatically. A successfull message will appear when the process is finished.\nIf we check the list of twins, we will see our twin example:car.\nBy clicking on it and accessing the children tab, we will find four twins corresponding to its wheels, each with the features specified in their respective type."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(4008).Z,alt:"Children of car type"})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"The composite digital twin has already been defined.")),(0,a.kt)("h3",{id:"connection"},"Connection"),(0,a.kt)("p",null,"Once we have the digital twin defined, we need to feed it with data.\nEclipse Ditto requires data updates to be sent in ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/protocol-specification.html#dittoProtocolEnvelope"},"Ditto Protocol"),", which is a JSON format that indicates which parts of the digital twin we want to update and how to do it."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"It is also possible to connect Eclipse Ditto with messaging brokers that use other message formats.\nWe can add a ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/connectivity-mapping.html#javascript-examples"},"JavaScript mapping")," to the Eclipse Ditto connection, which will automatically transform the messages to the Ditto Protocol format.")),(0,a.kt)("p",null,"For Eclipse Ditto to collect the data, it is necessary to establish a ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/connectivity-overview.html"},"connection")," through MQTT, AMQP or Kafka, providing all the required information (address, port, credentials, etc.).\nIn this example, we will take advantage of the source connection that is automatically created with the installation of Helm (",(0,a.kt)("inlineCode",{parentName:"p"},"mosquitto-source-connection"),").\nThis connection pulls messages via MQTT from the Mosquitto deployed with the platform, using any subtopic within the telemetry topic (i.e. ",(0,a.kt)("inlineCode",{parentName:"p"},"telemetry/#"),").\nBy default, it does not include any JavaScript mapping, so we will send messages directly in Ditto Protocol.\nIf you need to use another connection, see the ",(0,a.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/3.3/http-api-doc.html#/Connections"},"Eclipse Ditto documentation"),". "),(0,a.kt)("p",null,"We will need to get the address of Mosquitto, which will depend on your installation."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"If you are using a cluster in your network"),", the address will be your cluster address and the port can be obtained by running ",(0,a.kt)("inlineCode",{parentName:"li"},"kubectl get services")," and looking up the ",(0,a.kt)("a",{parentName:"li",href:"https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport"},(0,a.kt)("em",{parentName:"a"},"NodePort"))," of the Mosquitto service (default should be 30511)."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"If you are using Minikube"),", you must expose the Mosquitto service in order to access it from your ",(0,a.kt)("em",{parentName:"li"},"localhost"),".\nTo do this, find the name of the service with ",(0,a.kt)("inlineCode",{parentName:"li"},"kubectl get services")," and then run ",(0,a.kt)("inlineCode",{parentName:"li"},"minikube service --url"),".\nThis will return a URL with the address and port to connect to.")),(0,a.kt)("p",null,"Since we don't have real data, we are going to create a Python script that generates random data from the car and its wheels every 5 seconds and sends it in Ditto Protocol to Mosquitto.\nTo run the script we will need to install the ",(0,a.kt)("a",{parentName:"p",href:"https://pypi.org/project/paho-mqtt/"},"Paho library for MQTT")," (typing_extensions is one of its dependencies)."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-shell"},"pip install paho-mqtt\npip install typing_extensions\n")),(0,a.kt)("p",null,"In the following script you must ",(0,a.kt)("strong",{parentName:"p"},"change the MQTT broker address and port")," to your own."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-python"},'import paho.mqtt.client as mqtt\nimport random\nimport time\nimport json\n\n# Digital twin info\nnamespace = "example"\ncar_name = "mycar"\nwheels_name = "mycar:wheel_"\n\n# MQTT info\nbroker = "localhost" # MQTT broker address\nport = 1883 # MQTT port\ntopic = "telemetry/" # Topic where data will be published\n\n# MQTT connection\ndef on_connect(client, userdata, flags, rc):\n if rc == 0:\n print("Successful connection")\n else:\n print(f"Connection failed with code {rc}")\n\nclient = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)\nclient.on_connect = on_connect\nclient.username_pw_set(username, password)\nclient.connect(broker, port, 60)\n\n# Data generator\ndef generate_wheel_data():\n velocity = random.uniform(0, 100) # Generate random velocity (between 0 and 100 km/h)\n direction = random.uniform(-45, 45) # Generate random direction (between -45 and 45 degrees)\n return velocity, direction\n\ndef generate_gps_data():\n latitude = random.uniform(-90.0, 90.0)\n longitude = random.uniform(-180.0, 180.0)\n return latitude, longitude\n\n# Ditto Protocol\ndef get_ditto_protocol_value_car(time, latitude, longitude):\n return {\n "gps" : {\n "properties": {\n "latitude": latitude,\n "longitude": longitude,\n "time": time\n }\n }\n }\n\ndef get_ditto_protocol_value_wheel(time, velocity, direction):\n return {\n "velocity" : {\n "properties": {\n "value": velocity,\n "time": time\n }\n },\n "direction": {\n "properties" : {\n "value": direction,\n "time" : time\n }\n }\n }\n\ndef get_ditto_protocol_msg(name, value):\n return {\n "topic": "{}/{}/things/twin/commands/merge".format(namespace, name),\n "headers": {\n "content-type": "application/merge-patch+json"\n },\n "path": "/features",\n "value": value\n }\n\n# Send data\ntry:\n while True:\n t = round(time.time() * 1000) # Unix ms\n \n # Car twin\n latitude, longitude = generate_gps_data()\n msg = get_ditto_protocol_msg(car_name, get_ditto_protocol_value_car(t, latitude, longitude))\n client.publish(topic + namespace + "/" + car_name, json.dumps(msg))\n print(car_name + " data published")\n \n # Wheels twins\n for i in range(1, 5):\n name = wheels_name+str(i)\n velocity, direction = generate_wheel_data()\n msg = get_ditto_protocol_msg(name, get_ditto_protocol_value_wheel(t, velocity, direction))\n client.publish(topic + namespace + "/" + name, json.dumps(msg))\n print(name + " data published")\n \n time.sleep(5)\n \nexcept KeyboardInterrupt:\n client.disconnect()\n')),(0,a.kt)("p",null,"When you ",(0,a.kt)("strong",{parentName:"p"},"run the script"),", the data should start to be stored in the digital twins.\nYou can see if messages are being received by checking the information of the twins, where the values of their features will now have data."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(8606).Z,alt:"Children of car type",style:{width:700}})),(0,a.kt)("details",null,(0,a.kt)("summary",null,"Are the twins not being updated?"),(0,a.kt)("div",null,(0,a.kt)("p",null,"You can check if messages arrive to Mosquitto by using ",(0,a.kt)("a",{parentName:"p",href:"https://mqtt-explorer.com/"},"MQTT explorer"),".\nIf they are sending correctly, you should see something like the following image:"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"MQTT explorer",src:n(1845).Z,width:"1140",height:"628"})),(0,a.kt)("p",null,"And the messages being sent should be like these:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "topic": "example/mycar:wheel_2/things/twin/commands/merge",\n "headers": {\n "content-type": "application/merge-patch+json"\n },\n "path": "/features",\n "value": {\n "velocity": {\n "properties": {\n "value": 44.07908610511725,\n "time": 1715943644787\n }\n },\n "direction": {\n "properties": {\n "value": 37.92163063527694,\n "time": 1715943644787\n }\n }\n }\n}\n')),(0,a.kt)("p",null,"If the ",(0,a.kt)("strong",{parentName:"p"},"messages are not being received"),", debug the code to see what might be happening. Most likely you are not connecting correctly to Mosquitto (wrong address or port)."),(0,a.kt)("p",null,"If the ",(0,a.kt)("strong",{parentName:"p"},"messages are being received"),", then the problem is in the source connection to Eclipse Ditto. Check the connection logs with ",(0,a.kt)("inlineCode",{parentName:"p"},"http://:/api/2/connections/mosquitto-source-connection/logs"),".\nThe Eclipse Ditto ip and port are obtained the same as mosquitto's, but since Ditto has more than one service, you have to query/expose the ",(0,a.kt)("strong",{parentName:"p"},"nginx")," one."))),(0,a.kt)("h3",{id:"visualization"},"Visualization"),(0,a.kt)("p",null,"Finally, we need to present the data in a user-friendly and meaningful way for the users of the digital twin.\nTo achieve this, we will create a new ",(0,a.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/dashboards/"},"dashboard")," in Grafana and add ",(0,a.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/panels-visualizations/"},"panels")," to display the relevant digital twin information."),(0,a.kt)("p",null,"The digital twin data is stored in an ",(0,a.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/influxdb/v2/"},"InfluxDB2")," database, so we will have to query the information using ",(0,a.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/flux/v0/"},"Flux")," language.\nIf OpenTwins has been installed via Helm with default values, the ",(0,a.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/datasources/"},"connection")," between InfluxDB and Grafana should already be established, so it will only be necessary to select it as data source when creating a panel."),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(159).Z,alt:"Children of car type",style:{width:400}})),(0,a.kt)("p",null,"In this example, we will demonstrate a basic visualization. However, ",(0,a.kt)("strong",{parentName:"p"},"you can use any of Grafana's functionalities and plugins to customize it according to your specific objectives"),".\nWe will create four panels: one displaying the most recent GPS data of the car, another showing the evolution of the GPS data, a third panel indicating the current direction of all the wheels, and a fourth comparing the velocity of each wheel.\nThe result would look something like this:"),(0,a.kt)("center",null,(0,a.kt)("img",{src:n(589).Z,alt:"Grafana dashboard"})),(0,a.kt)("p",null,"For each of the four panels, we have selected the most convenient chart type, kept the default settings and added the related query in the Query section."),(0,a.kt)("p",null,"The panel displaying the ",(0,a.kt)("strong",{parentName:"p"},"current GPS")," data extracts the longitude and latitude information from the digital twin ",(0,a.kt)("em",{parentName:"p"},"example:mycar"),".\nIt renames the fields for proper display, retains the relevant fields, sorts the results by time, and keeps only the most recent entry."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => r["thingId"] == "example:mycar")\n |> filter(fn: (r) => r["_field"] == "value_gps_properties_latitude" or r["_field"] == "value_gps_properties_longitude")\n |> map(fn: (r) => ({ r with _field: strings.replace(v: r["_field"], t: "value_gps_properties_", u: "", i: 2) }))\n |> keep (columns: ["_value", "_field", "_time"])\n |> sort(columns: ["_time"], desc: false) \n |> last() \n')),(0,a.kt)("p",null,"The panel for show the ",(0,a.kt)("strong",{parentName:"p"},"GPS evolution")," also extracts the latitude and longitude data from the digital twin ",(0,a.kt)("em",{parentName:"p"},"example:mycar"),", but keeps all the entries instead of just the last one."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => r["thingId"] == "example:mycar")\n |> filter(fn: (r) => r["_field"] == "value_gps_properties_latitude" or r["_field"] == "value_gps_properties_longitude")\n |> map(fn: (r) => ({ r with _field: strings.replace(v: r["_field"], t: "value_gps_properties_", u: "", i: 2) }))\n |> keep (columns: ["_value", "_field", "_time"])\n')),(0,a.kt)("p",null,"The panel displaying the ",(0,a.kt)("strong",{parentName:"p"},"current direction of wheels")," extracts the direction data of the four twins corresponding to the wheels, identified by starting with ",(0,a.kt)("em",{parentName:"p"},"example:mycar:wheel_"),".\nIt modifies the identifiers of the twins for a more readable display and retains the most recent value based on time."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => strings.hasPrefix(v: r["thingId"], prefix: "example:mycar:wheel_"))\n |> filter(fn: (r) => r["_field"] == "value_direction_properties_value")\n |> map(fn: (r) => ({ r with thingId: strings.replace(v: r["thingId"], t: "example:mycar:", u: "", i: 2) }))\n |> keep (columns: ["thingId", "_value", "_time"])\n |> sort(columns: ["_time"], desc: false) \n |> last()\n')),(0,a.kt)("p",null,"Finally, the panel that makes a ",(0,a.kt)("strong",{parentName:"p"},"wheels velocity comparison")," is similar to the previous one, although extracting the velocity data from the 4 twins instead of the direction and keeping all the entries."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'import "strings"\nfrom(bucket: "opentwins")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")\n |> filter(fn: (r) => strings.hasPrefix(v: r["thingId"], prefix: "example:mycar:wheel_"))\n |> filter(fn: (r) => r["_field"] == "value_velocity_properties_value")\n |> map(fn: (r) => ({ r with thingId: strings.replace(v: r["thingId"], t: "example:mycar:", u: "", i: 2) }))\n |> keep (columns: ["thingId", "_value", "_time"])\n')),(0,a.kt)("p",null,"This satisfies the basic requirements to consider a system as a digital twin.\nHowever, to take full advantage of its capabilities, we recommend including other functionalities or additional data sources.\nThis will allow you to obtain a more complete and accurate view of the real system.\nYou can check our ",(0,a.kt)("a",{parentName:"p",href:"/opentwins/docs/guides/"},"guides")," for more information"))}h.isMDXComponent=!0},4008:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/children-car-twin-ca2cf91c075a327581d6ba641943742c.png"},7390:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/children-car-d181addcc20bcf1a9a75715cf3353c15.png"},2979:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-digital-twins-bd76130c9ab23c157cdfcd9dcb0fdc5b.png"},9726:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-twin-car-4a9968f0a40982680599c72e2f6d3b23.png"},9636:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-car-1-83399364c854df3e8b229885140649ba.png"},2748:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-car-2-c0b3b0d20c5b4291c77340e8a685d0c6.png"},8775:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-wheel-1-d71b44232fb9dfeebc601958e43d19fd.png"},8226:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-type-wheel-2-01daddbffbb636b06904956113d446fc.png"},589:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/grafana-dashboard-d0dbd9d8646a93fa599ba324ce583338.png"},159:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/grafana-datasource-e1e06ed3137227fd650fb894928415db.png"},4347:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/model-car-example-2b119ad662f43ec5caa875a83d9d7b7c.jpg"},8606:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/wheel-data-30d7b695d58b99fcec8f817d5d5b45e1.png"},1845:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/mqtt-explorer-ebaae1985874581cb44c024060bef150.png"}}]); \ No newline at end of file diff --git a/assets/js/8101ff7e.a7fd7485.js b/assets/js/8101ff7e.a7fd7485.js new file mode 100644 index 0000000..f198a30 --- /dev/null +++ b/assets/js/8101ff7e.a7fd7485.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5991],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>b});var a=n(7294);function r(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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),m=r,b=p["".concat(l,".").concat(m)]||p[m]||d[m]||i;return n?a.createElement(b,o(o({ref:t},u),{},{components:n})):a.createElement(b,o({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,o[1]=s;for(var c=2;c{n.d(t,{Z:()=>o});var a=n(7294),r=n(6010);const i={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:n,className:o}=e;return a.createElement("div",{role:"tabpanel",className:(0,r.Z)(i.tabItem,o),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>d});var a=n(7462),r=n(7294),i=n(6010),o=n(2389),s=n(7392),l=n(7094),c=n(2466);const u={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function p(e){const{lazy:t,block:n,defaultValue:o,values:p,groupId:d,className:m}=e,b=r.Children.map(e.children,(e=>{if((0,r.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=p??b.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),h=(0,s.l)(f,((e,t)=>e.value===t.value));if(h.length>0)throw new Error(`Docusaurus error: Duplicate values "${h.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const g=null===o?o:o??b.find((e=>e.props.default))?.props.value??b[0].props.value;if(null!==g&&!f.some((e=>e.value===g)))throw new Error(`Docusaurus error: The has a defaultValue "${g}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:v,setTabGroupChoices:w}=(0,l.U)(),[A,y]=(0,r.useState)(g),E=[],{blockElementScrollPositionUntilNextRender:T}=(0,c.o5)();if(null!=d){const e=v[d];null!=e&&e!==A&&f.some((t=>t.value===e))&&y(e)}const x=e=>{const t=e.currentTarget,n=E.indexOf(t),a=f[n].value;a!==A&&(T(t),y(a),null!=d&&w(d,String(a)))},j=e=>{let t=null;switch(e.key){case"Enter":x(e);break;case"ArrowRight":{const n=E.indexOf(e.currentTarget)+1;t=E[n]??E[0];break}case"ArrowLeft":{const n=E.indexOf(e.currentTarget)-1;t=E[n]??E[E.length-1];break}}t?.focus()};return r.createElement("div",{className:(0,i.Z)("tabs-container",u.tabList)},r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:o}=e;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:A===t?0:-1,"aria-selected":A===t,key:t,ref:e=>E.push(e),onKeyDown:j,onClick:x},o,{className:(0,i.Z)("tabs__item",u.tabItem,o?.className,{"tabs__item--active":A===t})}),n??t)}))),t?(0,r.cloneElement)(b.filter((e=>e.props.value===A))[0],{className:"margin-top--md"}):r.createElement("div",{className:"margin-top--md"},b.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==A})))))}function d(e){const t=(0,o.Z)();return r.createElement(p,(0,a.Z)({key:String(t)},e))}},4830:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>b,frontMatter:()=>s,metadata:()=>c,toc:()=>p});var a=n(7462),r=(n(7294),n(3905)),i=n(5488),o=n(5162);const s={sidebar_position:2},l="Create a digital twin",c={unversionedId:"guides/definition/dt-schema-creation",id:"guides/definition/dt-schema-creation",title:"Create a digital twin",description:"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.",source:"@site/docs/guides/definition/dt-schema-creation.mdx",sourceDirName:"guides/definition",slug:"/guides/definition/dt-schema-creation",permalink:"/opentwins/docs/guides/definition/dt-schema-creation",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/definition/dt-schema-creation.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Create a type",permalink:"/opentwins/docs/guides/definition/type-creation"},next:{title:"FMI Simulation",permalink:"/opentwins/docs/category/fmi-simulation"}},u={},p=[],d={toc:p},m="wrapper";function b(e){let{components:t,...s}=e;return(0,r.kt)(m,(0,a.Z)({},d,s,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"create-a-digital-twin"},"Create a digital twin"),(0,r.kt)("p",null,"The way to interact with ",(0,r.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/index.html"},"Eclipse Ditto")," and therefore create not only digital twins, but connections, etc. is through http requests and methods.\nAlthough the graphical interface of OpenTwins makes it unnecessary to go so low level, the option to communicate directly with Eclipse Ditto is still available."),(0,r.kt)(i.Z,{className:"unique-tabs",defaultValue:"ui",values:[{label:"Using Grafana interface",value:"ui"},{label:"Using http methods",value:"http"}],mdxType:"Tabs"},(0,r.kt)(o.Z,{value:"ui",mdxType:"TabItem"},(0,r.kt)("p",null,'To create a new digital twin schema using OpenTwins plugin in Grafana just select "Create new twin" button in Twins tab.\n',(0,r.kt)("img",{alt:"CreateTwin",src:n(4684).Z,width:"177",height:"42"}))),(0,r.kt)(o.Z,{value:"http",mdxType:"TabItem"},"This is an orange")))}b.isMDXComponent=!0},4684:(e,t,n)=>{n.d(t,{Z:()=>a});const a="data:image/png;base64,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"}}]); \ No newline at end of file diff --git a/assets/js/8777f386.1463edb8.js b/assets/js/8777f386.1463edb8.js deleted file mode 100644 index 57e98ec..0000000 --- a/assets/js/8777f386.1463edb8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4099],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>f});var r=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=r.createContext({}),c=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return r.createElement(l.Provider,{value:n},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=c(t),d=i,f=m["".concat(l,".").concat(d)]||m[d]||p[d]||a;return t?r.createElement(f,o(o({ref:n},u),{},{components:t})):r.createElement(f,o({ref:n},u))}));function f(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var a=t.length,o=new Array(a);o[0]=d;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[m]="string"==typeof e?e:i,o[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var r=t(7462),i=(t(7294),t(3905));t(4996),t(941);const a={sidebar_position:2},o="FMI Simulation concepts",s={unversionedId:"fmi/concepts",id:"fmi/concepts",title:"FMI Simulation concepts",description:"The FMI simulation service is currently being tested.",source:"@site/docs/fmi/concepts.mdx",sourceDirName:"fmi",slug:"/fmi/concepts",permalink:"/opentwins/docs/fmi/concepts",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/fmi/concepts.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Installation Guide",permalink:"/opentwins/docs/fmi/installation"},next:{title:"API Documentation",permalink:"/opentwins/docs/fmi/API"}},l={},c=[{value:"Simulation schema",id:"simulation-schema",level:2},{value:"Simulation running schema",id:"simulation-running-schema",level:2}],u={toc:c},m="wrapper";function p(e){let{components:n,...t}=e;return(0,i.kt)(m,(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"fmi-simulation-concepts"},"FMI Simulation concepts"),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"The FMI simulation service is currently being tested.")),(0,i.kt)("h2",{id:"simulation-schema"},"Simulation schema"),(0,i.kt)("p",null,"The schema is used to create simulation blueprints to store and create several simulation instances."),(0,i.kt)("p",null,"The schema can be create for a single FMU or several FMUs. The schema for a single FMU is:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id":"schema1",\n "name":"Schema 1",\n "description":"Sample schema",\n "relatedTwins":[\n "Twin1"\n ],\n "fmus":[\n {\n "id": "Controller",\n "inputs": [\n {"id": "u_s"},\n {"id": "u_m"}\n ],\n "outputs": [\n {"id": "y"}\n ]\n }\n ]\n}\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,(0,i.kt)("b",null,"Schema for several FMUs")),(0,i.kt)("p",null,"The following schema is designed to be used with multiple FMUs:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-tsx"},'{\n "id":"schema1",\n "name":"Schema 1",\n "description":"Sample schema",\n "relatedTwins":[\n "Twin1"\n ],\n "fmus":[\n {\n "id": "Controller",\n "inputs": [\n {"id": "u_s"},\n {"id": "u_m"}\n ],\n "outputs": [\n {"id": "y"}\n ]\n },\n {\n "id": "Drivetrain",\n "inputs": [\n {"id": "tau"}\n ],\n "outputs": [\n {"id": "w"}\n ]\n }\n ],\n "schema":[\n {\n "from": {"var": "w_ref"},\n "to": {"id": "controller", "var": "u_s"}\n },\n {\n "from": {"id": "drivetrain", "var": "w"},\n "to": {"id": "controller", "var": "u_m"}\n },\n {\n "from": {"id": "controller", "var": "y"},\n "to": {"id": "drivetrain", "var": "tau"}\n },\n {\n "from": {"id": "drivetrain", "var": "w"},\n "to": {"var": "w"}\n }\n ]\n}\n')),(0,i.kt)("p",null,"This will work properly, although hovering over",(0,i.kt)("inlineCode",{parentName:"p"},"ApparentGreetProps"),"may be a little intimidating. You can reduce this boilerplate with the",(0,i.kt)("inlineCode",{parentName:"p"},"ComponentProps")," utility detailed below.")),(0,i.kt)("h2",{id:"simulation-running-schema"},"Simulation running schema"),(0,i.kt)("p",null,"Once you have a schema stored in the system, you can create a simulation instance using that schema:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id":"Simulation1",\n "name":"Simulation1",\n "schemaId": "schema1",\n "targetConnection":{\n "BROKER_TYPE" : "mqtt",\n "BROKER_IP" : "",\n "BROKER_PORT" : "",\n "BROKER_TOPIC" : "",\n "BROKER_USERNAME" : "",\n "BROKER_PASSWORD" : ""\n },\n "configuration":{\n "SIMULATION_START_TIME":1,\n "SIMULATION_END_TIME":7,\n "SIMULATION_STEP_SIZE":1,\n "SIMULATION_DELAY_WARNING": 1,\n "SIMULATION_LAST_VALUE": true,\n "SIMULATION_TYPESCHEDULE": "one-time"\n },\n "inputs":[],\n "outputs": []\n}\n\n')),(0,i.kt)("p",null,"This schema is not different for one or several FMUs execution. It only contains information about execution."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.9e7c9e9d.js b/assets/js/935f2afb.9e7c9e9d.js new file mode 100644 index 0000000..da03085 --- /dev/null +++ b/assets/js/935f2afb.9e7c9e9d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Quickstart","href":"/opentwins/docs/quickstart","docId":"quickstart"},{"type":"category","label":"Overview","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Purpose","href":"/opentwins/docs/overview/purpose","docId":"overview/purpose"},{"type":"link","label":"Concepts","href":"/opentwins/docs/overview/concepts","docId":"overview/concepts"},{"type":"link","label":"Architecture","href":"/opentwins/docs/overview/architecture","docId":"overview/architecture"}],"href":"/opentwins/docs/category/overview"},{"type":"category","label":"Installation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Helm","href":"/opentwins/docs/installation/using-helm","docId":"installation/using-helm"},{"type":"category","label":"Manual","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"DT definition and monitoring (required)","href":"/opentwins/docs/installation/manual/essential","docId":"installation/manual/essential"},{"type":"link","label":"Composition (recommended)","href":"/opentwins/docs/installation/manual/composition","docId":"installation/manual/composition"},{"type":"link","label":"Machine Learning","href":"/opentwins/docs/installation/manual/machine-learning","docId":"installation/manual/machine-learning"},{"type":"link","label":"Simulations","href":"/opentwins/docs/installation/manual/simulations","docId":"installation/manual/simulations"},{"type":"link","label":"3D visualization","href":"/opentwins/docs/installation/manual/unity","docId":"installation/manual/unity"}],"href":"/opentwins/docs/installation/manual/"}],"href":"/opentwins/docs/category/installation"},{"type":"category","label":"Guides","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"DT definition","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Create a type","href":"/opentwins/docs/guides/definition/type-creation","docId":"guides/definition/type-creation"},{"type":"link","label":"Create a digital twin","href":"/opentwins/docs/guides/definition/dt-schema-creation","docId":"guides/definition/dt-schema-creation"}],"href":"/opentwins/docs/category/dt-definition"},{"type":"category","label":"FMI Simulation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Concepts","href":"/opentwins/docs/guides/fmi/concepts","docId":"guides/fmi/concepts"},{"type":"link","label":"API Documentation","href":"/opentwins/docs/guides/fmi/API","docId":"guides/fmi/API"}],"href":"/opentwins/docs/category/fmi-simulation"},{"type":"category","label":"Unity visualization","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Creation of Unity WebGL build","href":"/opentwins/docs/guides/unity/creating-unity-build","docId":"guides/unity/creating-unity-build"},{"type":"link","label":"Using Grafana Unity Plugin","href":"/opentwins/docs/guides/unity/using-grafana-plugin","docId":"guides/unity/using-grafana-plugin"}],"href":"/opentwins/docs/category/unity-visualization"}],"href":"/opentwins/docs/guides/"},{"type":"category","label":"Examples","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"String and number","href":"/opentwins/docs/examples/string-example","docId":"examples/string-example"},{"type":"category","label":"Raspberry Pi","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Raspberry","href":"/opentwins/docs/examples/raspberry-example/","docId":"examples/raspberry-example/raspberry-example"},{"type":"link","label":"Sending data to Ditto","href":"/opentwins/docs/examples/raspberry-example/sending-data","docId":"examples/raspberry-example/sending-data"}],"href":"/opentwins/docs/category/raspberry-pi"},{"type":"link","label":"Bouncing ball","href":"/opentwins/docs/examples/ball-example","docId":"examples/ball-example"}],"href":"/opentwins/docs/category/examples"}]},"docs":{"examples/ball-example":{"id":"examples/ball-example","title":"Bouncing ball","description":"","sidebar":"tutorialSidebar"},"examples/raspberry-example/raspberry-example":{"id":"examples/raspberry-example/raspberry-example","title":"Raspberry","description":"Requirements","sidebar":"tutorialSidebar"},"examples/raspberry-example/sending-data":{"id":"examples/raspberry-example/sending-data","title":"Sending data to Ditto","description":"In this case we will use a Raspberry Pi 3B with Raspbian buster OS connected to a DHT22 temperature and humidity sensor.","sidebar":"tutorialSidebar"},"examples/string-example":{"id":"examples/string-example","title":"String and number","description":"This is a very simple example of creating a ONE way digital twin for monitoring a device. In this case, the stored information will be a string and a number, both of them have a timestamp asociated.","sidebar":"tutorialSidebar"},"guides/definition/dt-schema-creation":{"id":"guides/definition/dt-schema-creation","title":"Create a digital twin","description":"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.","sidebar":"tutorialSidebar"},"guides/definition/type-creation":{"id":"guides/definition/type-creation","title":"Create a type","description":"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.","sidebar":"tutorialSidebar"},"guides/fmi/API":{"id":"guides/fmi/API","title":"API Documentation","description":"Welcome to the Example API documentation. This API allows developers to interact with our services easily and efficiently.","sidebar":"tutorialSidebar"},"guides/fmi/concepts":{"id":"guides/fmi/concepts","title":"FMI Simulation concepts","description":"The FMI simulation service is currently being tested.","sidebar":"tutorialSidebar"},"guides/index":{"id":"guides/index","title":"Guides","description":"The guides is being written right now. Sorry for the inconvenience.","sidebar":"tutorialSidebar"},"guides/unity/creating-unity-build":{"id":"guides/unity/creating-unity-build","title":"Creation of Unity WebGL build","description":"Basic creation of Unity build","sidebar":"tutorialSidebar"},"guides/unity/using-grafana-plugin":{"id":"guides/unity/using-grafana-plugin","title":"Using Grafana Unity Plugin","description":"Basic creation of Unity build","sidebar":"tutorialSidebar"},"installation/manual/composition":{"id":"installation/manual/composition","title":"Composition (recommended)","description":"Prerequisites","sidebar":"tutorialSidebar"},"installation/manual/essential":{"id":"installation/manual/essential","title":"DT definition and monitoring (required)","description":"This component is the essential functionality of OpenTwins and is required for the system to function properly. Regardless of your specific use case or configuration, it must be installed as a prerequisite. Please ensure that this component is installed correctly before proceeding with the configuration.","sidebar":"tutorialSidebar"},"installation/manual/index":{"id":"installation/manual/index","title":"Manual","description":"The documentation of this method is being written right now. We recommend using helm installation.","sidebar":"tutorialSidebar"},"installation/manual/machine-learning":{"id":"installation/manual/machine-learning","title":"Machine Learning","description":"Prerequisites","sidebar":"tutorialSidebar"},"installation/manual/simulations":{"id":"installation/manual/simulations","title":"Simulations","description":"FMI simulations","sidebar":"tutorialSidebar"},"installation/manual/unity":{"id":"installation/manual/unity","title":"3D visualization","description":"Prerequisites","sidebar":"tutorialSidebar"},"installation/using-helm":{"id":"installation/using-helm","title":"Helm","description":"Standard version","sidebar":"tutorialSidebar"},"overview/architecture":{"id":"overview/architecture","title":"Architecture","description":"OpenTwins is built on a open source microservices architecture, designed to enhance scalability, flexibility and efficiency in the development, extension, deployment and maintenance of the platform. All the components that make up this architecture are encapsulated in Docker containers, ideally managed through Kubernetes, which ensures efficient portability and management.","sidebar":"tutorialSidebar"},"overview/concepts":{"id":"overview/concepts","title":"Concepts","description":"In this section, we will explore in depth the concept of a digital twin as defined by the platform. We will detail the information it can contain, explain the idea of a \\"digital twin type\\", and discuss how the composition works.","sidebar":"tutorialSidebar"},"overview/purpose":{"id":"overview/purpose","title":"Purpose","description":"This platform has been designed to facilitate the development of digital twins and is characterised by the exclusive use of open source components. The aim is to achieve a platform that covers all the functionalities that a digital twin may require, from the most basic ones, such as simply checking its real-time state, to more advanced ones, such as the inclusion of predicted or simulated data or visualisation of 3D models of the twins.","sidebar":"tutorialSidebar"},"quickstart":{"id":"quickstart","title":"Quickstart","description":"Welcome to OpenTwins, a flexible platform adapted to your needs! Although OpenTwins offers extensive customization options, we understand the importance of simplicity for beginners. Therefore, let\'s embark on a short journey together, showing you the quickest route to deploy the platform and develop a functional digital twin.","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.caa8fb63.js b/assets/js/935f2afb.caa8fb63.js deleted file mode 100644 index 6cf7638..0000000 --- a/assets/js/935f2afb.caa8fb63.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Quickstart","href":"/opentwins/docs/quickstart","docId":"quickstart"},{"type":"category","label":"Overview","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Purpose","href":"/opentwins/docs/overview/purpose","docId":"overview/purpose"},{"type":"link","label":"Concepts","href":"/opentwins/docs/overview/concepts","docId":"overview/concepts"},{"type":"link","label":"Architecture","href":"/opentwins/docs/overview/architecture","docId":"overview/architecture"}],"href":"/opentwins/docs/category/overview"},{"type":"category","label":"Installation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Requirements","href":"/opentwins/docs/installation/requirements","docId":"installation/requirements"},{"type":"link","label":"Helm","href":"/opentwins/docs/installation/using-helm","docId":"installation/using-helm"},{"type":"link","label":"Manual","href":"/opentwins/docs/installation/manual","docId":"installation/manual"}],"href":"/opentwins/docs/category/installation"},{"type":"category","label":"Guides","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Create a type","href":"/opentwins/docs/guides/type-creation","docId":"guides/type-creation"},{"type":"link","label":"Create a digital twin","href":"/opentwins/docs/guides/dt-schema-creation","docId":"guides/dt-schema-creation"},{"type":"category","label":"Unity visualization","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Creation of Unity WebGL build","href":"/opentwins/docs/guides/unity/creating-unity-build","docId":"guides/unity/creating-unity-build"},{"type":"link","label":"Using Grafana Unity Plugin","href":"/opentwins/docs/guides/unity/using-grafana-plugin","docId":"guides/unity/using-grafana-plugin"}],"href":"/opentwins/docs/category/unity-visualization"}],"href":"/opentwins/docs/category/guides"},{"type":"category","label":"Examples","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"String and number","href":"/opentwins/docs/examples/string-example","docId":"examples/string-example"},{"type":"category","label":"Raspberry Pi","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Raspberry","href":"/opentwins/docs/examples/raspberry-example/","docId":"examples/raspberry-example/raspberry-example"},{"type":"link","label":"Sending data to Ditto","href":"/opentwins/docs/examples/raspberry-example/sending-data","docId":"examples/raspberry-example/sending-data"}],"href":"/opentwins/docs/category/raspberry-pi"},{"type":"link","label":"Bouncing ball","href":"/opentwins/docs/examples/ball-example","docId":"examples/ball-example"}],"href":"/opentwins/docs/category/examples"},{"type":"category","label":"FMI Simulation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Installation Guide","href":"/opentwins/docs/fmi/installation","docId":"fmi/installation"},{"type":"link","label":"FMI Simulation concepts","href":"/opentwins/docs/fmi/concepts","docId":"fmi/concepts"},{"type":"link","label":"API Documentation","href":"/opentwins/docs/fmi/API","docId":"fmi/API"}],"href":"/opentwins/docs/category/fmi-simulation"}]},"docs":{"examples/ball-example":{"id":"examples/ball-example","title":"Bouncing ball","description":"","sidebar":"tutorialSidebar"},"examples/raspberry-example/raspberry-example":{"id":"examples/raspberry-example/raspberry-example","title":"Raspberry","description":"Requirements","sidebar":"tutorialSidebar"},"examples/raspberry-example/sending-data":{"id":"examples/raspberry-example/sending-data","title":"Sending data to Ditto","description":"In this case we will use a Raspberry Pi 3B with Raspbian buster OS connected to a DHT22 temperature and humidity sensor.","sidebar":"tutorialSidebar"},"examples/string-example":{"id":"examples/string-example","title":"String and number","description":"This is a very simple example of creating a ONE way digital twin for monitoring a device. In this case, the stored information will be a string and a number, both of them have a timestamp asociated.","sidebar":"tutorialSidebar"},"fmi/API":{"id":"fmi/API","title":"API Documentation","description":"Welcome to the Example API documentation. This API allows developers to interact with our services easily and efficiently.","sidebar":"tutorialSidebar"},"fmi/concepts":{"id":"fmi/concepts","title":"FMI Simulation concepts","description":"The FMI simulation service is currently being tested.","sidebar":"tutorialSidebar"},"fmi/installation":{"id":"fmi/installation","title":"Installation Guide","description":"The FMI simulation service is currently being tested, so please be patient, as soon as it is properly tested, the public image will be available on Docker Hub.","sidebar":"tutorialSidebar"},"guides/dt-schema-creation":{"id":"guides/dt-schema-creation","title":"Create a digital twin","description":"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.","sidebar":"tutorialSidebar"},"guides/type-creation":{"id":"guides/type-creation","title":"Create a type","description":"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.","sidebar":"tutorialSidebar"},"guides/unity/creating-unity-build":{"id":"guides/unity/creating-unity-build","title":"Creation of Unity WebGL build","description":"Basic creation of Unity build","sidebar":"tutorialSidebar"},"guides/unity/using-grafana-plugin":{"id":"guides/unity/using-grafana-plugin","title":"Using Grafana Unity Plugin","description":"Basic creation of Unity build","sidebar":"tutorialSidebar"},"installation/manual":{"id":"installation/manual","title":"Manual","description":"The documentation of this method is being written right now. We recommend using helm installation.","sidebar":"tutorialSidebar"},"installation/requirements":{"id":"installation/requirements","title":"Requirements","description":"This page lists both software and hardware requirements for using OpenTwins.","sidebar":"tutorialSidebar"},"installation/using-helm":{"id":"installation/using-helm","title":"Helm","description":"Standard version","sidebar":"tutorialSidebar"},"overview/architecture":{"id":"overview/architecture","title":"Architecture","description":"OpenTwins is built on a open source microservices architecture, designed to enhance scalability, flexibility and efficiency in the development, extension, deployment and maintenance of the platform. All the components that make up this architecture are encapsulated in Docker containers, ideally managed through Kubernetes, which ensures efficient portability and management.","sidebar":"tutorialSidebar"},"overview/concepts":{"id":"overview/concepts","title":"Concepts","description":"In this section, we will explore in depth the concept of a digital twin as defined by the platform. We will detail the information it can contain, explain the idea of a \\"digital twin type\\", and discuss how the composition works.","sidebar":"tutorialSidebar"},"overview/purpose":{"id":"overview/purpose","title":"Purpose","description":"This platform has been designed to facilitate the development of digital twins and is characterised by the exclusive use of open source components. The aim is to achieve a platform that covers all the functionalities that a digital twin may require, from the most basic ones, such as simply checking its real-time state, to more advanced ones, such as the inclusion of predicted or simulated data or visualisation of 3D models of the twins.","sidebar":"tutorialSidebar"},"quickstart":{"id":"quickstart","title":"Quickstart","description":"Welcome to OpenTwins, a flexible platform adapted to your needs! Although OpenTwins offers extensive customization options, we understand the importance of simplicity for beginners. Therefore, let\'s embark on a short journey together, showing you the quickest route to deploy the platform and develop a functional digital twin.","sidebar":"tutorialSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/9501552e.874dbf69.js b/assets/js/9501552e.874dbf69.js new file mode 100644 index 0000000..f4b42fb --- /dev/null +++ b/assets/js/9501552e.874dbf69.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3329],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function o(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 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||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=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=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=o,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||i;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var c=2;c{n.d(t,{Z:()=>r});var a=n(7294),o=n(6010);const i={tabItem:"tabItem_Ymn6"};function r(e){let{children:t,hidden:n,className:r}=e;return a.createElement("div",{role:"tabpanel",className:(0,o.Z)(i.tabItem,r),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>u});var a=n(7462),o=n(7294),i=n(6010),r=n(2389),s=n(7392),l=n(7094),c=n(2466);const p={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function d(e){const{lazy:t,block:n,defaultValue:r,values:d,groupId:u,className:m}=e,h=o.Children.map(e.children,(e=>{if((0,o.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=d??h.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),g=(0,s.l)(f,((e,t)=>e.value===t.value));if(g.length>0)throw new Error(`Docusaurus error: Duplicate values "${g.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const k=null===r?r:r??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==k&&!f.some((e=>e.value===k)))throw new Error(`Docusaurus error: The has a defaultValue "${k}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:v,setTabGroupChoices:b}=(0,l.U)(),[y,N]=(0,o.useState)(k),w=[],{blockElementScrollPositionUntilNextRender:_}=(0,c.o5)();if(null!=u){const e=v[u];null!=e&&e!==y&&f.some((t=>t.value===e))&&N(e)}const T=e=>{const t=e.currentTarget,n=w.indexOf(t),a=f[n].value;a!==y&&(_(t),N(a),null!=u&&b(u,String(a)))},E=e=>{let t=null;switch(e.key){case"Enter":T(e);break;case"ArrowRight":{const n=w.indexOf(e.currentTarget)+1;t=w[n]??w[0];break}case"ArrowLeft":{const n=w.indexOf(e.currentTarget)-1;t=w[n]??w[w.length-1];break}}t?.focus()};return o.createElement("div",{className:(0,i.Z)("tabs-container",p.tabList)},o.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:r}=e;return o.createElement("li",(0,a.Z)({role:"tab",tabIndex:y===t?0:-1,"aria-selected":y===t,key:t,ref:e=>w.push(e),onKeyDown:E,onClick:T},r,{className:(0,i.Z)("tabs__item",p.tabItem,r?.className,{"tabs__item--active":y===t})}),n??t)}))),t?(0,o.cloneElement)(h.filter((e=>e.props.value===y))[0],{className:"margin-top--md"}):o.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,o.cloneElement)(e,{key:t,hidden:e.props.value!==y})))))}function u(e){const t=(0,r.Z)();return o.createElement(d,(0,a.Z)({key:String(t)},e))}},1320:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>c,toc:()=>d});var a=n(7462),o=(n(7294),n(3905)),i=n(5488),r=n(5162);const s={sidebar_position:1},l="DT definition and monitoring (required)",c={unversionedId:"installation/manual/essential",id:"installation/manual/essential",title:"DT definition and monitoring (required)",description:"This component is the essential functionality of OpenTwins and is required for the system to function properly. Regardless of your specific use case or configuration, it must be installed as a prerequisite. Please ensure that this component is installed correctly before proceeding with the configuration.",source:"@site/docs/installation/manual/essential.md",sourceDirName:"installation/manual",slug:"/installation/manual/essential",permalink:"/opentwins/docs/installation/manual/essential",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual/essential.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Manual",permalink:"/opentwins/docs/installation/manual/"},next:{title:"Composition (recommended)",permalink:"/opentwins/docs/installation/manual/composition"}},p={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Deploy",id:"deploy",level:2},{value:"MongoDB v6.0",id:"mongodb-v60",level:3},{value:"Eclipse Ditto v3.3",id:"eclipse-ditto-v33",level:3},{value:"InfluxDB v2",id:"influxdb-v2",level:3},{value:"Mosquitto v2.0",id:"mosquitto-v20",level:3},{value:"Apache Kafka v3.4",id:"apache-kafka-v34",level:3},{value:"Grafana v9.5",id:"grafana-v95",level:3},{value:"Eclipse Hono v2.4",id:"eclipse-hono-v24",level:3},{value:"Connect",id:"connect",level:2},{value:"Eclipse Ditto and InfluxDB",id:"eclipse-ditto-and-influxdb",level:3},{value:"InfluxDB and Grafana",id:"influxdb-and-grafana",level:3},{value:"Eclipse Ditto and Eclipse Hono",id:"eclipse-ditto-and-eclipse-hono",level:3}],u={toc:d},m="wrapper";function h(e){let{components:t,...s}=e;return(0,o.kt)(m,(0,a.Z)({},u,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"dt-definition-and-monitoring-required"},"DT definition and monitoring (required)"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"This component is the essential functionality of OpenTwins and is required for the system to function properly"),". Regardless of your specific use case or configuration, it must be installed as a prerequisite. Please ensure that this component is installed correctly before proceeding with the configuration."),(0,o.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,o.kt)("p",null,"Before you begin, ensure you have the following:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Container manager: Currently tested on ",(0,o.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")," and ",(0,o.kt)("a",{parentName:"li",href:"https://containerd.io/"},"ContainerD"),"."),(0,o.kt)("li",{parentName:"ul"},"Access to a ",(0,o.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")," (recommended) or ",(0,o.kt)("a",{parentName:"li",href:"https://k3s.io/"},"K3s")," cluster."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"kubectl")," installed and configured."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," version 16.14 or above.")),(0,o.kt)("h2",{id:"deploy"},"Deploy"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Note that the values files have the variables that we recommend for the installation of each Helm Chart, but they ",(0,o.kt)("strong",{parentName:"p"},"can be extended or modified according to your needs")," (please consult the Helm Chart documentation for each component).")),(0,o.kt)("p",null,"We recommend installing all components in the same Kubernetes namespace to make it easier to identify and control them all. In our case the namespace will be ",(0,o.kt)("em",{parentName:"p"},"opentwins"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl create namespace opentwins\n")),(0,o.kt)("p",null,"We installed all the components with their Helm versions and kept most of the values in their default configuration, except for those that are important for the interconnection of the components. In addition, we configure the services as NodePort to facilitate external access and set a specific port for each one. "),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"Depending on how you have persistence configured in your cluster, you may need to deploy ",(0,o.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/storage/persistent-volumes/"},"persistent volumes")," for MongoDB, InfluxDB and Grafana. The values for MongoDB are shown below, but they all follow the same template."),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre",className:"language-yaml"},"apiVersion: v1\nkind: PersistentVolume\nmetadata:\n name: pv-opentwins-mongodb\nspec:\n accessModes:\n - ReadWriteOnce\n capacity:\n storage: 8Gi\n hostPath:\n path: /mnt/opentwins/mongodb\n type: DirectoryOrCreate\n"))),(0,o.kt)("p",null,"Listed below are the essential components of the ",(0,o.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture"},"architecture")," along with their versions used, their Helm values and a link to the repository explaining their installation."),(0,o.kt)("h3",{id:"mongodb-v60"},"MongoDB v6.0"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://www.mongodb.com/docs/v6.0/introduction/"},"App v6.0 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/bitnami/charts/tree/main/bitnami/mongodb"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm install mongodb -n opentwins oci://registry-1.docker.io/bitnamicharts/mongodb --version 13.8.3 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"service:\n type: NodePort\n nodePorts:\n mongodb: 30717\npersistence:\n enabled: true\nvolumePermissions:\n enabled: true\nauth:\n enabled: false\n")),(0,o.kt)("h3",{id:"eclipse-ditto-v33"},"Eclipse Ditto v3.3"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://eclipse.dev/ditto/3.3/intro-overview.html"},"App v3.3 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/eclipse-ditto/ditto/tree/master/deployment/helm/ditto"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm install --dependency-update -n opentwins ditto oci://registry-1.docker.io/eclipse/ditto --version 3.3.7 --wait -f values.yaml\n")),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("ul",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ul"},"We advise not to modify any authentication configuration due to a bug in Eclipse Ditto that may cause access errors."),(0,o.kt)("li",{parentName:"ul"},"In the following values you have to replace ",(0,o.kt)("em",{parentName:"li"},"mongodb-service-name")," by the MongoDB service name"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"global:\n hashedBasicAuthUsers: false\n basicAuthUsers:\n ditto:\n user: ditto\n password: ditto\n devops:\n user: devops\n password: foobar\nnginx:\n service:\n type: NodePort\n nodePort: 30525\nswaggerui:\n enabled: false\ndittoui:\n enabled: false\nmongodb:\n enabled: false\ndbconfig:\n policies:\n uri: 'mongodb://:27017/ditto'\n things:\n uri: 'mongodb://:27017/ditto'\n connectivity:\n uri: 'mongodb://:27017/ditto'\n thingsSearch:\n uri: 'mongodb://:27017/ditto'\ngateway:\n config:\n authentication:\n enablePreAuthentication: true\n devops:\n devopsPassword: foobar\n statusPassword: foobar\n")),(0,o.kt)("h3",{id:"influxdb-v2"},"InfluxDB v2"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.influxdata.com/influxdb/v2/"},"App v2 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/influxdata/helm-charts/tree/master/charts/influxdb2"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add influxdata https://helm.influxdata.com/\nhelm repo update\nhelm install -n opentwins influxdb influxdata/influxdb2 --version 2.1.1 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"persistence:\n enabled: true\nservice:\n type: NodePort\n nodePort: 30716\nimage:\n pullPolicy: Always\n")),(0,o.kt)("h3",{id:"mosquitto-v20"},"Mosquitto v2.0"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"OpenTwins supports the use of Mosquitto and Kafka as intermediaries, but ",(0,o.kt)("strong",{parentName:"p"},"we recommend using Mosquitto")," due to its simpler configuration. Since there is no official Helm chart for Mosquitto, we have created one of our own that works fine, although there is no documentation yet. However, you can install Mosquitto in any of the ",(0,o.kt)("a",{parentName:"p",href:"https://mosquitto.org/download/"},"available ways"),".")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://mosquitto.org/documentation/"},"App documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/ertis-research/Helm-charts/blob/main/mosquitto/values.yaml"},"Helm values file"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add ertis https://ertis-research.github.io/Helm-charts/\nhelm repo update\nhelm install mosquitto ertis/mosquitto -n opentwins --wait --dependency-update -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"service:\n type: NodePort\n nodePort: 30511\nconfiguration:\n authentication:\n enabled: false\n")),(0,o.kt)("h3",{id:"apache-kafka-v34"},"Apache Kafka v3.4"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://kafka.apache.org/34/documentation.html"},"App v3.4 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/bitnami/charts/tree/main/bitnami/kafka"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm install kafka oci://registry-1.docker.io/bitnamicharts/kafka --version 22.0.0 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"autoCreateTopicsEnable: true\n")),(0,o.kt)("h3",{id:"grafana-v95"},"Grafana v9.5"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://grafana.com/docs/grafana/v9.5/"},"App v9.5.1 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/grafana/helm-charts/tree/main/charts/grafana"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add grafana https://grafana.github.io/helm-charts\nhelm repo update\nhelm install grafana grafana/grafana -n opentwins --version 6.56.1 -f values.yaml\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"persistence:\n enabled: true\nservice:\n type: NodePort\n nodePort: 30718\ngrafana.ini:\n plugins:\n plugin_admin_enabled: true\n allow_loading_unsigned_plugins: ertis-opentwins,ertis-unity-panel\nextraInitContainers:\n- name: install-opentwins-plugins\n image: busybox\n command:\n - /bin/sh\n - -c\n - |\n #!/bin/sh\n set -euo pipefail\n mkdir -p /grafana-storage/plugins\n cd /grafana-storage/plugins\n wget --no-check-certificate -O ertis-opentwins.zip https://github.com/ertis-research/opentwins-in-grafana/releases/download/latest/ertis-opentwins.zip\n unzip -o ertis-opentwins.zip\n rm ertis-opentwins.zip\n wget --no-check-certificate -O ertis-unity-panel.zip https://github.com/ertis-research/grafana-panel-unity/releases/download/latest/ertis-unity-panel.zip\n unzip -o ertis-unity-panel.zip\n rm ertis-unity-panel.zip\n volumeMounts:\n - name: storage\n mountPath: /grafana-storage\n")),(0,o.kt)("h3",{id:"eclipse-hono-v24"},"Eclipse Hono v2.4"),(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"This component is completely optional. We maintain support for its connection to OpenTwins, but ",(0,o.kt)("strong",{parentName:"p"},"we do not recommend its use"),". For a large number of devices or messages it increases considerably the latency of the platform.")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://eclipse.dev/hono/docs/2.4/"},"App v2.4 documentation")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/eclipse/packages/tree/master/charts/hono"},"Helm documentation"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add eclipse-iot https://eclipse.org/packages/charts\nhelm repo update\nhelm install hono eclipse-iot/hono -n opentwins -f values.yaml --version=2.5.5\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},"prometheus:\n createInstance: false\ngrafana:\n enabled: false\nuseLoadBalancer: false\nprobes:\n livenessProbe:\n initialDelaySeconds: 900\n readinessProbe:\n initialDelaySeconds: 45\nmessagingNetworkTypes:\n - amqp\nkafkaMessagingClusterExample:\n enabled: false\namqpMessagingNetworkExample:\n enabled: true\ndeviceRegistryExample:\n type: mongodb\n addExampleData: false\n mongoDBBasedDeviceRegistry:\n mongodb:\n host: '{{ .Release.Name }}-mongodb'\n port: 27017\n dbName: hono\n hono:\n registry:\n http:\n insecurePortEnabled: true\nadapters:\n mqtt:\n hono:\n mqtt:\n insecurePortEnabled: true\n http:\n hono:\n http:\n insecurePortEnabled: true\n amqp:\n hono:\n amqp:\n insecurePortEnabled: true\n\n")),(0,o.kt)("h2",{id:"connect"},"Connect"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Check ",(0,o.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture"},"architecture")," to see which connections you need to set up")),(0,o.kt)("h3",{id:"eclipse-ditto-and-influxdb"},"Eclipse Ditto and InfluxDB"),(0,o.kt)("p",null,"The process to connect Eclipse Ditto and InfluxDB will depend on Mosquitto or Apache Kafka. Choose the option you have selected in each step."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"You have to add an output connection in Eclipse Ditto that publishes the events of the twins in the intermediary. This is done with a ",(0,o.kt)("inlineCode",{parentName:"p"},"POST")," request to the URL ",(0,o.kt)("inlineCode",{parentName:"p"},"http://DITTO_NGINX_URL/api/2/connections")," with the following body and the basic credentials: user ",(0,o.kt)("em",{parentName:"p"},'"devops"')," and password ",(0,o.kt)("em",{parentName:"p"},'"foobar"'),". Remember to replace ",(0,o.kt)("strong",{parentName:"p"},"DITTO_NGINX_URL")," by a URL that allows access to the Eclipse Ditto Nginx service, you can check how to do it ",(0,o.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/tasks/access-application-cluster/service-access-application-cluster/"},"here"),"."),(0,o.kt)("p",{parentName:"li"},"You can check if the connection is working properly by reading the ",(0,o.kt)("em",{parentName:"p"},"opentwins")," topic in the selected broker with some tool or script and sending updates to some twin in ",(0,o.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/protocol-overview.html"},"Ditto Protocol")," format. To create the twin check ",(0,o.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/http-api-doc.html#/Things/put_api_2_things__thingId_"},"here")," and to see an example of an update message check ",(0,o.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/protocol-examples-modifyfeatures.html#modifyfeatures"},"here"),"."))),(0,o.kt)(i.Z,{groupId:"intermediary",mdxType:"Tabs"},(0,o.kt)(r.Z,{value:"mosquitto",label:"Mosquitto",default:!0,mdxType:"TabItem"},(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"Change ",(0,o.kt)("strong",{parentName:"p"},"MOSQUITTO_SERVICE_NAME")," to the name of the Mosquitto service. You can check it with ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get services"),".")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="PUT http://DITTO_NGINX_URL/api/2/connections"',title:'"PUT','http://DITTO_NGINX_URL/api/2/connections"':!0},'{\n "name": "mosquitto-target-connection",\n "connectionType": "mqtt-5",\n "connectionStatus": "open",\n "uri": "tcp://MOSQUITTO_SERVICE_NAME:1883",\n "clientCount": 1,\n "failoverEnabled": true,\n "sources": [],\n "targets": [\n {\n "address": "opentwins/{{ topic:channel }}/{{ topic:criterion }}/{{ thing:namespace }}/{{ thing:name }}",\n "topics": [\n "_/_/things/twin/events?extraFields=thingId,attributes/_parents,features/idSimulationRun/properties/value",\n "_/_/things/live/messages",\n "_/_/things/live/commands"\n ],\n "qos": 1,\n "authorizationContext": [\n "nginx:ditto"\n ]\n }\n ]\n}\n'))),(0,o.kt)(r.Z,{value:"kafka",label:"Apache Kafka",mdxType:"TabItem"},(0,o.kt)("admonition",{type:"warning"},(0,o.kt)("p",{parentName:"admonition"},"Change ",(0,o.kt)("strong",{parentName:"p"},"KAFKA_SERVICE_NAME")," to the name of the Apache Kafka service. You can check it with ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get services"),".")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="PUT http://DITTO_NGINX_URL/api/2/connections"',title:'"PUT','http://DITTO_NGINX_URL/api/2/connections"':!0},'{\n "name": "kafka-target-connection",\n "connectionType": "kafka",\n "connectionStatus": "open",\n "uri": "tcp://KAFKA_SERVICE_NAME:9092",\n "specificConfig": {\n "bootstrapServers": "KAFKA_SERVICE_NAME:9092",\n "saslMechanism": "plain"\n },\n "failoverEnabled": true,\n "sources": [],\n "targets": [\n {\n "address": "opentwins",\n "topics": [\n "_/_/things/twin/events?extraFields=thingId,attributes/_parents,features/idSimulationRun/properties/value",\n "_/_/things/live/messages",\n "_/_/things/live/commands"\n ],\n "authorizationContext": [\n "nginx:ditto"\n ]\n }\n ]\n}\n')))),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Now we will need to obtain a token in InfluxDB with write permissions. We will then access from a browser to the InfluxDB interface and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/influxdb/v2/admin/organizations/create-org/"},"create an ",(0,o.kt)("em",{parentName:"a"},"opentwins")," organization"),". Then, follow the instructions in their documentation to ",(0,o.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/influxdb/v2/admin/tokens/create-token/"},"create an API token")," in the organization. Save this token because we will use it next.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"An instance of Telegraf must be deployed to read the events written in the intermediary broker and write them to the database. For this we will use the Telegraf Helm and add the necessary configuration in its values. You can check to Telegraf v1 documentation for both the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.influxdata.com/telegraf/v1/"},"application")," and ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/influxdata/helm-charts/tree/master/charts/telegraf"},"Helm")," for more information."),(0,o.kt)("p",{parentName:"li"},"The commands to deploy it are the following, using the necessary values file in each case."))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"helm repo add influxdata https://helm.influxdata.com/\nhelm repo update\nhelm install -n opentwins telegraf influxdata/telegraf -f values.yaml --version=1.8.27 --set tplVersion=2\n")),(0,o.kt)(i.Z,{groupId:"intermediary",mdxType:"Tabs"},(0,o.kt)(r.Z,{value:"mosquitto",label:"Mosquitto",default:!0,mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},'service:\n enabled: false\nconfig:\n agent:\n debug: true\n processors:\n - rename:\n replace:\n - tag: "extra_attributes__parents"\n dest: "parent" \n - tag: "headers_ditto-originator"\n dest: "originator"\n - tag: "extra_features_idSimulationRun_properties_value"\n dest: "idSimulationRun"\n - tag: "extra_thingId"\n dest: "thingId"\n outputs:\n - influxdb_v2:\n urls:\n - "http://INFLUX_SERVICE_NAME:INFLUX_PORT"\n token: "INFLUXDB_TOKEN"\n organization: "opentwins"\n bucket: "default"\n inputs:\n - mqtt_consumer:\n servers:\n - "tcp://MOSQUITTO_SERVICE_NAME:1883"\n topics:\n - "opentwins/#"\n qos: 1\n tag_keys:\n - "extra_attributes__parents"\n - "extra_thingId"\n - "headers_ditto-originator"\n - "extra_features_idSimulationRun_properties_value"\n - "value_time_properties_value" \n data_format: "json"\nmetrics:\n internal:\n enabled: false\n'))),(0,o.kt)(r.Z,{value:"kafka",label:"Apache Kafka",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="values.yaml"',title:'"values.yaml"'},'service:\n enabled: false\nconfig:\n agent:\n debug: true\n processors:\n - rename:\n replace:\n - tag: "extra_attributes__parents"\n dest: "parent" \n - tag: "headers_ditto-originator"\n dest: "originator"\n - tag: "extra_features_idSimulationRun_properties_value"\n dest: "idSimulationRun"\n - tag: "extra_thingId"\n dest: "thingId"\n outputs:\n - influxdb_v2:\n urls:\n - "http://INFLUX_SERVICE_NAME:INFLUX_PORT"\n token: "INFLUXDB_TOKEN"\n organization: "opentwins"\n bucket: "default"\n inputs:\n - kafka_consumer:\n brokers:\n - "KAFKA_SERVICE_NAME:9092"\n topics:\n - "opentwins"\n tag_keys:\n - "extra_attributes__parents"\n - "extra_thingId"\n - "headers_ditto-originator"\n - "extra_features_idSimulationRun_properties_value"\n - "value_time_properties_value" \n data_format: "json"\nmetrics:\n internal:\n enabled: false\n')))),(0,o.kt)("p",null,"With this Eclipse Ditto and InfluxDB should be connected. You can check this by sending update messages to Eclipse Ditto and verifying if they are correctly written to the InfluxDB bucket. If not, check if the messages are arriving correctly to the intermediate broker and, if so, check the logs of the Telegraf pod to see if there is any error in the configuration (usually connection problems)."),(0,o.kt)("h3",{id:"influxdb-and-grafana"},"InfluxDB and Grafana"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Obtain a ",(0,o.kt)("a",{parentName:"li",href:"https://docs.influxdata.com/influxdb/v2/admin/tokens/create-token/"},"read access token in InfluxDB")," for Grafana."),(0,o.kt)("li",{parentName:"ol"},"Access ",(0,o.kt)("inlineCode",{parentName:"li"},"Configuration > Data sources")," on the Grafana interface and click on ",(0,o.kt)("em",{parentName:"li"},"Add data source"),"."),(0,o.kt)("li",{parentName:"ol"},"Select ",(0,o.kt)("em",{parentName:"li"},"InfluxDB")," from the list. In the setup form it is very important to select ",(0,o.kt)("em",{parentName:"li"},"Flux")," as query language. It will be necessary to fill in the URL section with the one that corresponds to InfluxDB service. You will also have to activate ",(0,o.kt)("em",{parentName:"li"},"Auth Basic")," and fill in the fields (in our case we have set the default admin of InfluxDB, but you can create a new user and fill in these fields). In the InfluxDB details you should indicate the organization, the bucket (default is ",(0,o.kt)("em",{parentName:"li"},"default"),") and the token you have generated. "),(0,o.kt)("li",{parentName:"ol"},"When saving and testing, it should come out that at least one bucket has been found, indicating that they are already connected.")),(0,o.kt)("h3",{id:"eclipse-ditto-and-eclipse-hono"},"Eclipse Ditto and Eclipse Hono"),(0,o.kt)("p",null,"In the following diagram you can see how Eclipse Hono and Eclipse Ditto are related in OpenTwins. "),(0,o.kt)("center",null,(0,o.kt)("img",{src:n(2728).Z,alt:"Ditto and Hono relationship",style:{width:500}})),(0,o.kt)("p",null,"Basically, you will need to ",(0,o.kt)("strong",{parentName:"p"},"create a connection between both for each Eclipse Hono tenant you want to use"),". ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/hono/docs/concepts/tenancy/"},"Tenants")," basically act as device containers, so you could simply create a single tenant connected to Eclipse Ditto and store all the devices you need there. In this case we will do it this way, but you could create as many tenants and connections as your needs require."),(0,o.kt)("p",null,"The first thing to do is to check the IPs and ports to use with ",(0,o.kt)("inlineCode",{parentName:"p"},"kubectl get services -n $NS"),". At this point we are interested in the ",(0,o.kt)("em",{parentName:"p"},"dt-service-device-registry-ext")," and ",(0,o.kt)("em",{parentName:"p"},"dt-ditto-nginx")," services, which correspond to Eclipse Hono and Eclipse Ditto respectively (if you have followed these instructions and services are NodePort, you will have to use port 3XXXX). "),(0,o.kt)("p",null,"We will then create a Hono tenant called, for example, ditto (you must override the variable ",(0,o.kt)("strong",{parentName:"p"},"HONO_TENANT")," if you have chosen another name)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"HONO_TENANT=ditto\ncurl -i -X POST http://$HONO_IP:$HONO_PORT/v1/tenants/$HONO_TENANT\n")),(0,o.kt)("p",null,"Now we will create the connection from Eclipse Ditto, which will act as a consumer of the AMQP endpoint of that tenant. To do this you will need to know the Eclipse Ditto devops password with the following command (the variable ",(0,o.kt)("strong",{parentName:"p"},"RELEASE")," is the name we gave to the Helm release when installing cloud2edge, if you have followed these instructions it should be dt)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'RELEASE=dt\nDITTO_DEVOPS_PWD=$(kubectl --namespace ${NS} get secret ${RELEASE}-ditto-gateway-secret -o jsonpath="{.data.devops-password}" | base64 --decode)\n')),(0,o.kt)("p",null,"Now we ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/connectivity-manage-connections.html#create-connection"},"create the connection from Eclipse Ditto")," with the following command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'curl -i -X POST -u devops:${DITTO_DEVOPS_PWD} -H \'Content-Type: application/json\' --data \'{\n "targetActorSelection": "/system/sharding/connection",\n "headers": {\n "aggregate": false\n },\n "piggybackCommand": {\n "type": "connectivity.commands:createConnection",\n "connection": {\n "id": "hono-connection-for-\'"${HONO_TENANT}"\'",\n "connectionType": "amqp-10",\n "connectionStatus": "open",\n "uri": "amqp://consumer%40HONO:verysecret@\'"${RELEASE}"\'-dispatch-router-ext:15672",\n "failoverEnabled": true,\n "sources": [\n {\n "addresses": [\n "telemetry/\'"${HONO_TENANT}"\'",\n "event/\'"${HONO_TENANT}"\'"\n ],\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "enforcement": {\n "input": "{{ header:device_id }}",\n "filters": [\n "{{ entity:id }}"\n ]\n },\n "headerMapping": {\n "hono-device-id": "{{ header:device_id }}",\n "content-type": "{{ header:content-type }}"\n },\n "replyTarget": {\n "enabled": true,\n "address": "{{ header:reply-to }}",\n "headerMapping": {\n "to": "command/\'"${HONO_TENANT}"\'/{{ header:hono-device-id }}",\n "subject": "{{ header:subject | fn:default(topic:action-subject) | fn:default(topic:criterion) }}-response",\n "correlation-id": "{{ header:correlation-id }}",\n "content-type": "{{ header:content-type | fn:default(\'"\'"\'application/vnd.eclipse.ditto+json\'"\'"\') }}"\n },\n "expectedResponseTypes": [\n "response",\n "error"\n ]\n },\n "acknowledgementRequests": {\n "includes": [],\n "filter": "fn:filter(header:qos,\'"\'"\'ne\'"\'"\',\'"\'"\'0\'"\'"\')"\n }\n },\n {\n "addresses": [\n "command_response/\'"${HONO_TENANT}"\'/replies"\n ],\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "headerMapping": {\n "content-type": "{{ header:content-type }}",\n "correlation-id": "{{ header:correlation-id }}",\n "status": "{{ header:status }}"\n },\n "replyTarget": {\n "enabled": false,\n "expectedResponseTypes": [\n "response",\n "error"\n ]\n }\n }\n ],\n "targets": [\n {\n "address": "command/\'"${HONO_TENANT}"\'",\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "topics": [\n "_/_/things/live/commands",\n "_/_/things/live/messages"\n ],\n "headerMapping": {\n "to": "command/\'"${HONO_TENANT}"\'/{{ thing:id }}",\n "subject": "{{ header:subject | fn:default(topic:action-subject) }}",\n "content-type": "{{ header:content-type | fn:default(\'"\'"\'application/vnd.eclipse.ditto+json\'"\'"\') }}",\n "correlation-id": "{{ header:correlation-id }}",\n "reply-to": "{{ fn:default(\'"\'"\'command_response/\'"${HONO_TENANT}"\'/replies\'"\'"\') | fn:filter(header:response-required,\'"\'"\'ne\'"\'"\',\'"\'"\'false\'"\'"\') }}"\n }\n },\n {\n "address": "command/\'"${HONO_TENANT}"\'",\n "authorizationContext": [\n "pre-authenticated:hono-connection"\n ],\n "topics": [\n "_/_/things/twin/events",\n "_/_/things/live/events"\n ],\n "headerMapping": {\n "to": "command/\'"${HONO_TENANT}"\'/{{ thing:id }}",\n "subject": "{{ header:subject | fn:default(topic:action-subject) }}",\n "content-type": "{{ header:content-type | fn:default(\'"\'"\'application/vnd.eclipse.ditto+json\'"\'"\') }}",\n "correlation-id": "{{ header:correlation-id }}"\n }\n }\n ]\n }\n }\n}\' http://$DITTO_IP:$DITTO_PORT/devops/piggyback/connectivity\n')),(0,o.kt)("p",null,"This connection is configured so that if an ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/hono/docs/concepts/device-identity/"},"Eclipse Hono device")," has the ",(0,o.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/basic-thing.html#thing-id"},"ThingId")," of an Eclipse Ditto twin as its identifier, its messages will be redirected to that twin directly (explained in more detail in the ",(0,o.kt)("a",{parentName:"p",href:"#usage"},"usage")," section)."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Now you have all the essential OpenTwins functionality (DT definition and monitoring) working.")))}h.isMDXComponent=!0},2728:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/ditto-hono-relationship-05edfdb26b9df807a0860fad82192684.jpg"}}]); \ No newline at end of file diff --git a/assets/js/ac75af2e.f73fc938.js b/assets/js/ac75af2e.f73fc938.js deleted file mode 100644 index 53b686e..0000000 --- a/assets/js/ac75af2e.f73fc938.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1199],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(r),d=a,f=c["".concat(s,".").concat(d)]||c[d]||m[d]||i;return r?n.createElement(f,o(o({ref:t},p),{},{components:r})):n.createElement(f,o({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var u=2;u{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var n=r(7462),a=(r(7294),r(3905));const i={sidebar_position:1},o="Requirements",l={unversionedId:"installation/requirements",id:"installation/requirements",title:"Requirements",description:"This page lists both software and hardware requirements for using OpenTwins.",source:"@site/docs/installation/requirements.md",sourceDirName:"installation",slug:"/installation/requirements",permalink:"/opentwins/docs/installation/requirements",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/requirements.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Installation",permalink:"/opentwins/docs/category/installation"},next:{title:"Helm",permalink:"/opentwins/docs/installation/using-helm"}},s={},u=[{value:"Hardware requirements",id:"hardware-requirements",level:2},{value:"Software requirements",id:"software-requirements",level:2}],p={toc:u},c="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(c,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"This page lists both software and hardware requirements for using OpenTwins."),(0,a.kt)("h2",{id:"hardware-requirements"},"Hardware requirements"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("h3",{parentName:"li",id:"for-standard-architecture"},"For standard architecture"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"2 CPU cores"),(0,a.kt)("li",{parentName:"ul"},"8 GB of RAM"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("h3",{parentName:"li",id:"for-lightweight-architecture"},"For lightweight architecture"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Raspberry Pi 4")))),(0,a.kt)("h2",{id:"software-requirements"},"Software requirements"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Container manager:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Tested on ",(0,a.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")," and ",(0,a.kt)("a",{parentName:"li",href:"https://containerd.io/"},"ContainerD"),"."))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes"),":",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"Tested on ",(0,a.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")," and ",(0,a.kt)("a",{parentName:"li",href:"https://k3s.io/"},"K3s"),"."))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://helm.sh/docs/intro/install/"},"Helm")," version 16.14 or above.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d03241c9.4c55d6e8.js b/assets/js/d03241c9.4c55d6e8.js new file mode 100644 index 0000000..81faade --- /dev/null +++ b/assets/js/d03241c9.4c55d6e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2871],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=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 r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(n),m=i,f=d["".concat(s,".").concat(m)]||d[m]||p[m]||o;return n?r.createElement(f,a(a({ref:t},u),{},{components:n})):r.createElement(f,a({ref:t},u))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:i,a[1]=c;for(var l=2;l{n.d(t,{Z:()=>y});var r=n(7294),i=n(6010),o=n(3438),a=n(9960),c=n(3919),s=n(5999);const l={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};function u(e){let{href:t,children:n}=e;return r.createElement(a.Z,{href:t,className:(0,i.Z)("card padding--lg",l.cardContainer)},n)}function d(e){let{href:t,icon:n,title:o,description:a}=e;return r.createElement(u,{href:t},r.createElement("h2",{className:(0,i.Z)("text--truncate",l.cardTitle),title:o},n," ",o),a&&r.createElement("p",{className:(0,i.Z)("text--truncate",l.cardDescription),title:a},a))}function p(e){let{item:t}=e;const n=(0,o.Wl)(t);return n?r.createElement(d,{href:n,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:(0,s.I)({message:"{count} items",id:"theme.docs.DocCard.categoryDescription",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t.items.length})}):null}function m(e){let{item:t}=e;const n=(0,c.Z)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",i=(0,o.xz)(t.docId??void 0);return r.createElement(d,{href:t.href,icon:n,title:t.label,description:i?.description})}function f(e){let{item:t}=e;switch(t.type){case"link":return r.createElement(m,{item:t});case"category":return r.createElement(p,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function g(e){let{className:t}=e;const n=(0,o.jA)();return r.createElement(y,{items:n.items,className:t})}function y(e){const{items:t,className:n}=e;if(!t)return r.createElement(g,e);const a=(0,o.MN)(t);return r.createElement("section",{className:(0,i.Z)("row",n)},a.map(((e,t)=>r.createElement("article",{key:t,className:"col col--6 margin-bottom--lg"},r.createElement(f,{item:e})))))}},652:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>m,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var r=n(7462),i=(n(7294),n(3905)),o=n(2991);const a={sidebar_position:4},c="Guides",s={unversionedId:"guides/index",id:"guides/index",title:"Guides",description:"The guides is being written right now. Sorry for the inconvenience.",source:"@site/docs/guides/index.md",sourceDirName:"guides",slug:"/guides/",permalink:"/opentwins/docs/guides/",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/index.md",tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"tutorialSidebar",previous:{title:"3D visualization",permalink:"/opentwins/docs/installation/manual/unity"},next:{title:"DT definition",permalink:"/opentwins/docs/category/dt-definition"}},l={},u=[],d={toc:u},p="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"guides"},"Guides"),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"The guides is being written right now. Sorry for the inconvenience.")),(0,i.kt)(o.Z,{className:"DocCardList--no-description",mdxType:"DocCardList"}))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d3d686ac.c9777f1c.js b/assets/js/d3d686ac.26d4bc4a.js similarity index 60% rename from assets/js/d3d686ac.c9777f1c.js rename to assets/js/d3d686ac.26d4bc4a.js index d0bface..b579bec 100644 --- a/assets/js/d3d686ac.c9777f1c.js +++ b/assets/js/d3d686ac.26d4bc4a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1495],{173:i=>{i.exports=JSON.parse('{"title":"FMI Simulation","description":"OpenTwins supports the Functional Mock-up Interface (FMI) standard for simulation.","slug":"/category/fmi-simulation","permalink":"/opentwins/docs/category/fmi-simulation","navigation":{"previous":{"title":"Bouncing ball","permalink":"/opentwins/docs/examples/ball-example"},"next":{"title":"Installation Guide","permalink":"/opentwins/docs/fmi/installation"}}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1495],{173:i=>{i.exports=JSON.parse('{"title":"FMI Simulation","description":"OpenTwins supports the Functional Mock-up Interface (FMI) standard for simulation.","slug":"/category/fmi-simulation","permalink":"/opentwins/docs/category/fmi-simulation","navigation":{"previous":{"title":"Create a digital twin","permalink":"/opentwins/docs/guides/definition/dt-schema-creation"},"next":{"title":"Concepts","permalink":"/opentwins/docs/guides/fmi/concepts"}}}')}}]); \ No newline at end of file diff --git a/assets/js/d72ac48e.28c67a5d.js b/assets/js/d72ac48e.28c67a5d.js new file mode 100644 index 0000000..a5c96c4 --- /dev/null +++ b/assets/js/d72ac48e.28c67a5d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6513],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>u});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=i.createContext({}),p=function(e){var t=i.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},c=function(e){var t=p(e.components);return i.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),h=p(a),m=n,u=h["".concat(l,".").concat(m)]||h[m]||d[m]||o;return a?i.createElement(u,r(r({ref:t},c),{},{components:a})):i.createElement(u,r({ref:t},c))}));function u(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:n,r[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var i=a(7462),n=(a(7294),a(3905));const o={sidebar_position:3},r="Architecture",s={unversionedId:"overview/architecture",id:"overview/architecture",title:"Architecture",description:"OpenTwins is built on a open source microservices architecture, designed to enhance scalability, flexibility and efficiency in the development, extension, deployment and maintenance of the platform. All the components that make up this architecture are encapsulated in Docker containers, ideally managed through Kubernetes, which ensures efficient portability and management.",source:"@site/docs/overview/architecture.md",sourceDirName:"overview",slug:"/overview/architecture",permalink:"/opentwins/docs/overview/architecture",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/overview/architecture.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Concepts",permalink:"/opentwins/docs/overview/concepts"},next:{title:"Installation",permalink:"/opentwins/docs/category/installation"}},l={},p=[{value:"Standard architecture",id:"standard-architecture",level:2},{value:"Essential functionality",id:"essential-functionality",level:3},{value:"Compositional support",id:"compositional-support",level:3},{value:"Data prediction with machine learning",id:"data-prediction-with-machine-learning",level:3},{value:"3D representation",id:"3d-representation",level:3},{value:"Lightweight architecture",id:"lightweight-architecture",level:2}],c={toc:p},h="wrapper";function d(e){let{components:t,...o}=e;return(0,n.kt)(h,(0,i.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"architecture"},"Architecture"),(0,n.kt)("p",null,"OpenTwins is built on a ",(0,n.kt)("strong",{parentName:"p"},"open source microservices architecture"),", designed to enhance scalability, flexibility and efficiency in the development, extension, deployment and maintenance of the platform. All the components that make up this architecture are encapsulated in ",(0,n.kt)("a",{parentName:"p",href:"https://www.docker.com/"},"Docker")," containers, ideally managed through ",(0,n.kt)("a",{parentName:"p",href:"https://kubernetes.io/"},"Kubernetes"),", which ensures efficient portability and management. "),(0,n.kt)("h2",{id:"standard-architecture"},"Standard architecture"),(0,n.kt)("admonition",{type:"note"},(0,n.kt)("p",{parentName:"admonition"},"Although it is possible to deploy and connect the different components without containerization, this approach is not recommended due to the difficulties involved in terms of installation and management. However, it is important to note that OpenTwins could be ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/manual/"},"manually connected")," to non-containerized components, such as a local instance of Grafana.")),(0,n.kt)("p",null,"The following image illustrates the current architecture of OpenTwins, in which each color of the boxes represents the functionality covered by each component. Most of these components are external projects to our organization, however, we also include certain services specifically designed to enrich the functionality of the platform. Both the code and documentation of the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/opentwins/tree/main/components"},"components")," are available in their respective repositories."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Architecture",src:a(3160).Z,width:"1904",height:"911"})),(0,n.kt)("h3",{id:"essential-functionality"},"Essential functionality"),(0,n.kt)("p",null,"The elements highlighted in ",(0,n.kt)("strong",{parentName:"p"},"blue")," form the heart of OpenTwins, as they provide the ",(0,n.kt)("strong",{parentName:"p"},"essential functionalities")," of a digital twin development platform: the definition of digital twins, the connection to IoT devices, the storage of information and the user-friendly visualisation of data. The tools used in this case include:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/"},"Eclipse Ditto"),". This is ",(0,n.kt)("strong",{parentName:"p"},"the core component of OpenTwins"),", an open-source framework for digital twins developed by the ",(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/"},"Eclipse Foundation"),". Eclipse Ditto provides an abstract entity ",(0,n.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/basic-thing.html"},'"Thing"'),', which allows describing digital twins through JSON schemas that include both static and dynamic data of the entity. The framework stores the current state of the "Thing" entity and facilitates its ',(0,n.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/basic-connections.html"},"connection")," to input and output data sources through various IoT protocols. In a typical scenario, the Thing entity will update its information via a source connection, generating events that are sent to the indicated target connections. In addition, the tool provides an ",(0,n.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/http-api-doc.html"},"API")," that allows querying the current state of the entity and managing its schema and connections.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/hono/"},"Eclipse Hono"),". This component facilitates the ",(0,n.kt)("strong",{parentName:"p"},"reception of data through various IoT protocols")," and centralizes it into a single endpoint, either ",(0,n.kt)("a",{parentName:"p",href:"https://www.amqp.org/"},"AMQP 1.0")," or ",(0,n.kt)("a",{parentName:"p",href:"https://kafka.apache.org/"},"Kafka"),". This output connects directly to Eclipse Ditto, eliminating the need for users to manually connect to an external broker to extract data. This allows the platform to receive data through the most common IoT protocols, giving devices the flexibility to connect to the most appropriate protocol for their particular case. "),(0,n.kt)("admonition",{parentName:"li",type:"warning"},(0,n.kt)("p",{parentName:"admonition"},"Despite its advantages, we have observed that ",(0,n.kt)("strong",{parentName:"p"},"Eclipse Hono does not scale correctly when the message frequency is high"),", so we do not recommend its use in these cases. For this reason, or if it is not necessary to offer different input protocols, you can choose to connect Eclipse Ditto to one or more specific messaging brokers, such as ",(0,n.kt)("a",{parentName:"p",href:"https://mosquitto.org/"},"Mosquitto")," or ",(0,n.kt)("a",{parentName:"p",href:"https://www.rabbitmq.com/"},"RabbitMQ"),"."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.mongodb.com/"},"MongoDB"),". This tool is the ",(0,n.kt)("strong",{parentName:"p"},"internal database used by Eclipse Hono and Eclipse Ditto"),'. Eclipse Ditto stores data about the current state of digital twins ("things"), policies, connections and recent events, while Eclipse Hono stores information about defined devices and groups.')),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/products/influxdb-overview/"},"InfluxDB v2"),". This database provides an optimized architecture for time series, which guarantees superior performance in ",(0,n.kt)("strong",{parentName:"p"},"storing and querying digital twin data"),". Its high scalability and simplicity of use allow it to efficiently handle large volumes of data, facilitating the integration and analysis of information in real time. In addition, it is one of the most popular options in the field of the Internet of Things (IoT), generating an active community that consolidates its position as a robust solution.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/time-series-platform/telegraf/"},"Telegraf"),". This server-based agent for ",(0,n.kt)("strong",{parentName:"p"},"collecting and sending metrics")," offers easy configuration and a wide range of plugins to integrate various data sources and destinations. It is the recommended choice for data ingestion into InfluxDB. Its role in the platform is to capture digital twin updates, presented as Eclipse Ditto events, processing the data as time series for storage in the database.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://kafka.apache.org/"},"Apache Kafka")," or ",(0,n.kt)("a",{parentName:"p",href:"https://mosquitto.org/"},"Eclipse Mosquitto"),". An ",(0,n.kt)("strong",{parentName:"p"},"intermediary messaging broker")," is required for Telegraf to collect event data from Eclipse Ditto, since none of these technologies provide this role and do not have a direct connection. For this purpose, any messaging broker where Eclipse Ditto can publish and read Telegraf is valid. The options available on the platform include Apache Kafka, known for its scalability and error tolerance in processing large volumes of data, and Mosquitto, recognized for its efficiency in messaging and its flexibility in IoT environments.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://grafana.com/oss/grafana/"},"Grafana"),". This solution acts as the ",(0,n.kt)("strong",{parentName:"p"},"platform's main front-end"),", providing a highly adaptable data visualization that allows users to create intuitive and easily understandable dashboards. Its ability to integrate with a wide variety of data sources and its active community of users and developers make it a powerful tool for monitoring and analyzing complex systems, such as digital twins. In addition, it allows users to expand its functionality by creating custom plugins, giving them the ability to integrate new visualizations, use-case specific panels and connectors to additional data sources. "))),(0,n.kt)("h3",{id:"compositional-support"},"Compositional support"),(0,n.kt)("p",null,"The ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twins-composition"},"composition of digital twins")," represents one of the main contributions of this platform, distinguishing it from other similar solutions. In addition, OpenTwins provides the ability to define and compose ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twin-type"},'"types" of digital twins'),", making development simpler. The services marked in ",(0,n.kt)("strong",{parentName:"p"},"green")," in the architecture are responsible for integrating these functionalities."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/extended-api-for-eclipse-ditto/"},"Extended API for Eclipse Ditto"),'. The Thing entity provided by Eclipse Ditto must follow a specific JSON schema, although it offers great flexibility within it. Our goal is to simplify type definition and entity composition by taking advantage of the flexibility of this schema. This "extended API" acts as a ',(0,n.kt)("strong",{parentName:"p"},"layer on top of the Eclipse Ditto API"),", distinguishing between the management of twins and types, and applying all the necessary constraints and checks to ensure the composition of these entities according to the constraints imposed by each (types form graphs, while twins form trees).")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/opentwins-in-grafana/"},"OpenTwins app plugin for Grafana"),". To have a pleasant and usable platform for as many users as possible, it is important to have a simple ",(0,n.kt)("strong",{parentName:"p"},"interface")," capable of performing the functionalities available. Therefore, an app plugin is included for Grafana that uses the extended API to query and manage twins, types and their composition in a user-friendly way. Moreover, this approach keeps the entire platform front-end within a single tool, making it easy to use and accessible."))),(0,n.kt)("h3",{id:"data-prediction-with-machine-learning"},"Data prediction with machine learning"),(0,n.kt)("p",null,"The architecture highlights in ",(0,n.kt)("strong",{parentName:"p"},"yellow")," the components that facilitate the integration of digital twins with Machine Learning models. Providing this support represents a crucial aspect in the development of a digital twin, since it provides a complementary or comparative perspective with real data, enriching the understanding of the replicated object. To achieve this goal, the following tools are used:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/kafka-ml"},"Kafka-ML"),". This open source framework manages the lifecycle of ML/AI applications in production environments through continuous data streams. Unlike traditional frameworks that work with static data sets, Kafka-ML enables both training and inference with continuous data streams, allowing users to have fine-grained control over ingestion data. Currently, Kafka-ML is compatible with the most popular ML frameworks, ",(0,n.kt)("a",{parentName:"p",href:"https://www.tensorflow.org/"},"TensorFlow")," and ",(0,n.kt)("a",{parentName:"p",href:"https://pytorch.org/"},"PyTorch"),", and enables the ",(0,n.kt)("strong",{parentName:"p"},"management and deployment of ML models"),", from definition to final deployment for inference. This component operates as a black box in OpenTwins, receiving input data for a deployed model through a Kafka topic and sending the predicted result to another topic, which is connected to Eclipse Ditto in a way that updates to the corresponding digital twin.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/eclipse-hono-to-kafka-ml"},"Eclipse Hono to Kafka-ML"),". Kafka-ML can receive input data from any source that is able to publish to a Kafka topic. However, at OpenTwins we have decided to simplify this process when the data comes from Eclipse Hono. Therefore, we have developed an optional service that automates the data feed of ML models deployed in Kafka-ML. This service ",(0,n.kt)("strong",{parentName:"p"},"automatically sends the data needed to make a prediction")," every time a new data is received from any of the devices required by the model. To use this tool, we provide an API that allows you to specify which devices should be taken into account, what data is required from these devices and how they should be formatted to work correctly as input for Kafka-ML.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/error-detection-for-eclipse-hono-with-kafka-ml"},"Error detection for Eclipse Hono with Kafka-ML"),". An ML model useful in the construction of a digital twin is one capable of generating data that a sensor should produce in case it loses connection or experiences a failure. To automate this, we have developed an optional service with similar functionalities to the one mentioned above, but with an important particularity: it will only invoke the model when an interruption in data reception by the device is detected. This service takes into account the frequency with which the data is emitted by the device. As soon as an anomaly is identified, the service will format and send the last data received following the expected frequency until the connection is restored and real data is received again. In this way, the ",(0,n.kt)("strong",{parentName:"p"},"normal operation of the device is simulated"),", ensuring continuity of information for the digital twin."))),(0,n.kt)("h3",{id:"3d-representation"},"3D representation"),(0,n.kt)("admonition",{type:"note"},(0,n.kt)("p",{parentName:"admonition"},"Although Unity is not open source, at the moment it is the only graphics engine we have tested the plugin with.\nHowever, it could be replaced by any other graphics engine that compiles in WebGL, such as ",(0,n.kt)("a",{parentName:"p",href:"https://godotengine.org/"},"Godot"),", since the plugin is expected to be able to render any WebGL compilation. However, since we have not yet tested with other graphics engines, we cannot guarantee this.")),(0,n.kt)("p",null,"Although it may seem a secondary aspect, the representation of the digital twin makes a major difference in its utility and adoption. An intuitive and attractive visual interface for users will facilitate the understanding and accessibility of the data received, which simplifies the optimization of the actual system. 3D representations stand out as one of the most effective options in this sense, which motivates most private digital twin platforms to offer support for them. For this reason, OpenTwins allows adding an interactive 3D representation of the digital twin that reacts dynamically to data received from any source (real, predicted or simulated). The components highlighted in ",(0,n.kt)("strong",{parentName:"p"},"red")," are the ones that enable this functionality."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://unity.com/"},"Unity")," This powerful ",(0,n.kt)("strong",{parentName:"p"},"graphics engine"),", versatile in both 3D and 2D development, is widely used in the creation of video games, simulations and engineering. It is recognized as one of the most popular, supported by a large and active community. Although it is not open source software, it can be used ",(0,n.kt)("a",{parentName:"p",href:"https://unity.com/es/products/unity-personal?currency=EUR"},"free of charge for personal or low-profit projects"),". The technology of this engine allows to assign behaviors to 3D objects by means of scripts, which facilitates interaction both with the user and with other elements of the environment."),(0,n.kt)("admonition",{parentName:"li",type:"info"},(0,n.kt)("p",{parentName:"admonition"},"Unity offers a wide range of ",(0,n.kt)("a",{parentName:"p",href:"https://docs.unity3d.com/2023.2/Documentation/Manual/3D-formats.html"},"formats for importing 3D models"),", but we emphasize its integration with ",(0,n.kt)("a",{parentName:"p",href:"https://www.blender.org/"},"Blender"),", an open source 3D creation suite that is equally popular and supported by an active community. ")),(0,n.kt)("p",{parentName:"li"},"On the other hand, Unity provides the possibility to compile projects in the ",(0,n.kt)("strong",{parentName:"p"},"Unity ",(0,n.kt)("a",{parentName:"strong",href:"https://get.webgl.org/"},"WebGL"))," format, perfect for web rendering. This option is the choice of OpenTwins, as it allows easy integration with existing web technologies, ensuring accessibility and distribution without the need for additional installations.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/unity-plugin-for-grafana"},"Unity panel plugin for Grafana"),". Since Grafana serves as the front-end of OpenTwins, it is convenient that the 3D representations are embedded directly into this tool, providing a unified management and visualization of the digital twin. To achieve this, a plugin capable of ",(0,n.kt)("strong",{parentName:"p"},"rendering WebGL compilations within a Grafana panel")," has been developed. This plugin is able to send the digital twin data from Grafana to the compilation, allowing it to influence the rendering in real time. In addition, this plugin enables direct user interaction with the 3D model, allowing actions on 3D elements to affect other panels of the dashboard. For example, by clicking on a 3D element, another Grafana panel can automatically display data related to it."))),(0,n.kt)("h2",{id:"lightweight-architecture"},"Lightweight architecture"),(0,n.kt)("admonition",{type:"note"},(0,n.kt)("p",{parentName:"admonition"},"Although it is possible to deploy and connect the different components without containerization, this approach is not recommended due to the difficulties involved in terms of installation and management. However, it is important to note that Lightweight version of OpenTwins could be ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/manual/"},"manually connected")," to non-containerized components.")),(0,n.kt)("p",null,"The following image illustrates the current lightweigh architecture of OpenTwins, the field of digital twins is closely linked to the IoT, highlighting the critical importance of reducing data transmission delays. Additionally, IoT devices typically have limited processing capabilities, which makes running resource-demanding software impractical. This new architecture has been developed to facilitate dependable IoT applications within a distributed Edge/Fog/Cloud infrastructure. Developing a lightweight distributed version of OpenTwins can offer several advantages and address various needs depending on the context and goals of the project."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"LightweightArchitecture",src:a(7526).Z,width:"1795",height:"702"})),(0,n.kt)("p",null,"Like the main platform, the core component of this new architecture remains ",(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/"},"Eclipse Ditto"),". Most of the components has been removed to achieve lower consumptions."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Message broker:")," The ",(0,n.kt)("a",{parentName:"p",href:"https://kafka.apache.org/"},"Apache Kafka")," messaging broker has been replaced by ",(0,n.kt)("a",{parentName:"p",href:"https://mosquitto.org/"},"Eclipse Mosquitto")," that uses ",(0,n.kt)("a",{parentName:"p",href:"https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html"},"MQTT5"),", as it is best suited messaging protocol for IoT.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Persistence:")," As the platform is designed to be used in low-resource environments such as IoT devices or Raspberry Pi, for example, it has been decided not to have persistence of historical data, so ",(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/products/influxdb-overview/"},"InfluxDB")," is not used. In the case of a persistence need, the ",(0,n.kt)("a",{parentName:"p",href:"https://www.mongodb.com/"},"MongoDB")," database that Eclipse Ditto needs to work can be used. ",(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/time-series-platform/telegraf/"},"Telegraf")," can introduce the historical data in this database. In this way, although we do not have a database optimized to store data in the form of time series, it would be possible to have persistence with a single database.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Visualization:")," Both IoT and Edge devices are not typically used for visualization-related tasks and are sometimes lacking the power to do so. This is why it has been decided to remove this component from the new lightweight architecture.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Simulation components:")," Due to the technical limitations mentioned above, the simulation components present in the original architecture have been eliminated.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"ML components:")," As mentioned above, some edge or IoT are not capable of handling the necessary components to run the ML module, so its installation, although it has been used in this work, is optional."))),(0,n.kt)("p",null,"All modules that are not present in this version of the platform are still fully available and compatible, so users can make use of any component if necessary by activating them in the platform installation process by ",(0,n.kt)("a",{parentName:"p",href:"https://helm.sh/"},"Helm"),"(WIP)"))}d.isMDXComponent=!0},3160:(e,t,a)=>{a.d(t,{Z:()=>i});const i=a.p+"assets/images/architecture-ff30194687d6d921534d28bb801abe74.jpg"},7526:(e,t,a)=>{a.d(t,{Z:()=>i});const i=a.p+"assets/images/lightweightArchitecture-21af82d7bc7628d2b18b2392dca7ed29.png"}}]); \ No newline at end of file diff --git a/assets/js/d72ac48e.cd787f6d.js b/assets/js/d72ac48e.cd787f6d.js deleted file mode 100644 index 8577fd6..0000000 --- a/assets/js/d72ac48e.cd787f6d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6513],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>u});var i=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=i.createContext({}),p=function(e){var t=i.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},c=function(e){var t=p(e.components);return i.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),h=p(a),m=n,u=h["".concat(l,".").concat(m)]||h[m]||d[m]||o;return a?i.createElement(u,r(r({ref:t},c),{},{components:a})):i.createElement(u,r({ref:t},c))}));function u(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:n,r[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var i=a(7462),n=(a(7294),a(3905));const o={sidebar_position:3},r="Architecture",s={unversionedId:"overview/architecture",id:"overview/architecture",title:"Architecture",description:"OpenTwins is built on a open source microservices architecture, designed to enhance scalability, flexibility and efficiency in the development, extension, deployment and maintenance of the platform. All the components that make up this architecture are encapsulated in Docker containers, ideally managed through Kubernetes, which ensures efficient portability and management.",source:"@site/docs/overview/architecture.md",sourceDirName:"overview",slug:"/overview/architecture",permalink:"/opentwins/docs/overview/architecture",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/overview/architecture.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"tutorialSidebar",previous:{title:"Concepts",permalink:"/opentwins/docs/overview/concepts"},next:{title:"Installation",permalink:"/opentwins/docs/category/installation"}},l={},p=[{value:"Standard architecture",id:"standard-architecture",level:2},{value:"Essential functionality",id:"essential-functionality",level:3},{value:"Compositional support",id:"compositional-support",level:3},{value:"Data prediction with machine learning",id:"data-prediction-with-machine-learning",level:3},{value:"3D representation",id:"3d-representation",level:3},{value:"Lightweight architecture",id:"lightweight-architecture",level:2}],c={toc:p},h="wrapper";function d(e){let{components:t,...o}=e;return(0,n.kt)(h,(0,i.Z)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"architecture"},"Architecture"),(0,n.kt)("p",null,"OpenTwins is built on a ",(0,n.kt)("strong",{parentName:"p"},"open source microservices architecture"),", designed to enhance scalability, flexibility and efficiency in the development, extension, deployment and maintenance of the platform. All the components that make up this architecture are encapsulated in ",(0,n.kt)("a",{parentName:"p",href:"https://www.docker.com/"},"Docker")," containers, ideally managed through ",(0,n.kt)("a",{parentName:"p",href:"https://kubernetes.io/"},"Kubernetes"),", which ensures efficient portability and management. "),(0,n.kt)("h2",{id:"standard-architecture"},"Standard architecture"),(0,n.kt)("admonition",{type:"note"},(0,n.kt)("p",{parentName:"admonition"},"Although it is possible to deploy and connect the different components without containerization, this approach is not recommended due to the difficulties involved in terms of installation and management. However, it is important to note that OpenTwins could be ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/manual"},"manually connected")," to non-containerized components, such as a local instance of Grafana.")),(0,n.kt)("p",null,"The following image illustrates the current architecture of OpenTwins, in which each color of the boxes represents the functionality covered by each component. Most of these components are external projects to our organization, however, we also include certain services specifically designed to enrich the functionality of the platform. Both the code and documentation of the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/opentwins/tree/main/components"},"components")," are available in their respective repositories."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Architecture",src:a(3160).Z,width:"1904",height:"911"})),(0,n.kt)("h3",{id:"essential-functionality"},"Essential functionality"),(0,n.kt)("p",null,"The elements highlighted in ",(0,n.kt)("strong",{parentName:"p"},"blue")," form the heart of OpenTwins, as they provide the ",(0,n.kt)("strong",{parentName:"p"},"essential functionalities")," of a digital twin development platform: the definition of digital twins, the connection to IoT devices, the storage of information and the user-friendly visualisation of data. The tools used in this case include:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/"},"Eclipse Ditto"),". This is ",(0,n.kt)("strong",{parentName:"p"},"the core component of OpenTwins"),", an open-source framework for digital twins developed by the ",(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/"},"Eclipse Foundation"),". Eclipse Ditto provides an abstract entity ",(0,n.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/basic-thing.html"},'"Thing"'),', which allows describing digital twins through JSON schemas that include both static and dynamic data of the entity. The framework stores the current state of the "Thing" entity and facilitates its ',(0,n.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/basic-connections.html"},"connection")," to input and output data sources through various IoT protocols. In a typical scenario, the Thing entity will update its information via a source connection, generating events that are sent to the indicated target connections. In addition, the tool provides an ",(0,n.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/http-api-doc.html"},"API")," that allows querying the current state of the entity and managing its schema and connections.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/hono/"},"Eclipse Hono"),". This component facilitates the ",(0,n.kt)("strong",{parentName:"p"},"reception of data through various IoT protocols")," and centralizes it into a single endpoint, either ",(0,n.kt)("a",{parentName:"p",href:"https://www.amqp.org/"},"AMQP 1.0")," or ",(0,n.kt)("a",{parentName:"p",href:"https://kafka.apache.org/"},"Kafka"),". This output connects directly to Eclipse Ditto, eliminating the need for users to manually connect to an external broker to extract data. This allows the platform to receive data through the most common IoT protocols, giving devices the flexibility to connect to the most appropriate protocol for their particular case. "),(0,n.kt)("admonition",{parentName:"li",type:"warning"},(0,n.kt)("p",{parentName:"admonition"},"Despite its advantages, we have observed that ",(0,n.kt)("strong",{parentName:"p"},"Eclipse Hono does not scale correctly when the message frequency is high"),", so we do not recommend its use in these cases. For this reason, or if it is not necessary to offer different input protocols, you can choose to connect Eclipse Ditto to one or more specific messaging brokers, such as ",(0,n.kt)("a",{parentName:"p",href:"https://mosquitto.org/"},"Mosquitto")," or ",(0,n.kt)("a",{parentName:"p",href:"https://www.rabbitmq.com/"},"RabbitMQ"),"."))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.mongodb.com/"},"MongoDB"),". This tool is the ",(0,n.kt)("strong",{parentName:"p"},"internal database used by Eclipse Hono and Eclipse Ditto"),'. Eclipse Ditto stores data about the current state of digital twins ("things"), policies, connections and recent events, while Eclipse Hono stores information about defined devices and groups.')),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/products/influxdb-overview/"},"InfluxDB v2"),". This database provides an optimized architecture for time series, which guarantees superior performance in ",(0,n.kt)("strong",{parentName:"p"},"storing and querying digital twin data"),". Its high scalability and simplicity of use allow it to efficiently handle large volumes of data, facilitating the integration and analysis of information in real time. In addition, it is one of the most popular options in the field of the Internet of Things (IoT), generating an active community that consolidates its position as a robust solution.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/time-series-platform/telegraf/"},"Telegraf"),". This server-based agent for ",(0,n.kt)("strong",{parentName:"p"},"collecting and sending metrics")," offers easy configuration and a wide range of plugins to integrate various data sources and destinations. It is the recommended choice for data ingestion into InfluxDB. Its role in the platform is to capture digital twin updates, presented as Eclipse Ditto events, processing the data as time series for storage in the database.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://kafka.apache.org/"},"Apache Kafka")," or ",(0,n.kt)("a",{parentName:"p",href:"https://mosquitto.org/"},"Eclipse Mosquitto"),". An ",(0,n.kt)("strong",{parentName:"p"},"intermediary messaging broker")," is required for Telegraf to collect event data from Eclipse Ditto, since none of these technologies provide this role and do not have a direct connection. For this purpose, any messaging broker where Eclipse Ditto can publish and read Telegraf is valid. The options available on the platform include Apache Kafka, known for its scalability and error tolerance in processing large volumes of data, and Mosquitto, recognized for its efficiency in messaging and its flexibility in IoT environments.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://grafana.com/oss/grafana/"},"Grafana"),". This solution acts as the ",(0,n.kt)("strong",{parentName:"p"},"platform's main front-end"),", providing a highly adaptable data visualization that allows users to create intuitive and easily understandable dashboards. Its ability to integrate with a wide variety of data sources and its active community of users and developers make it a powerful tool for monitoring and analyzing complex systems, such as digital twins. In addition, it allows users to expand its functionality by creating custom plugins, giving them the ability to integrate new visualizations, use-case specific panels and connectors to additional data sources. "))),(0,n.kt)("h3",{id:"compositional-support"},"Compositional support"),(0,n.kt)("p",null,"The ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twins-composition"},"composition of digital twins")," represents one of the main contributions of this platform, distinguishing it from other similar solutions. In addition, OpenTwins provides the ability to define and compose ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/concepts#digital-twin-type"},'"types" of digital twins'),", making development simpler. The services marked in ",(0,n.kt)("strong",{parentName:"p"},"green")," in the architecture are responsible for integrating these functionalities."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/extended-api-for-eclipse-ditto/"},"Extended API for Eclipse Ditto"),'. The Thing entity provided by Eclipse Ditto must follow a specific JSON schema, although it offers great flexibility within it. Our goal is to simplify type definition and entity composition by taking advantage of the flexibility of this schema. This "extended API" acts as a ',(0,n.kt)("strong",{parentName:"p"},"layer on top of the Eclipse Ditto API"),", distinguishing between the management of twins and types, and applying all the necessary constraints and checks to ensure the composition of these entities according to the constraints imposed by each (types form graphs, while twins form trees).")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/opentwins-in-grafana/"},"OpenTwins app plugin for Grafana"),". To have a pleasant and usable platform for as many users as possible, it is important to have a simple ",(0,n.kt)("strong",{parentName:"p"},"interface")," capable of performing the functionalities available. Therefore, an app plugin is included for Grafana that uses the extended API to query and manage twins, types and their composition in a user-friendly way. Moreover, this approach keeps the entire platform front-end within a single tool, making it easy to use and accessible."))),(0,n.kt)("h3",{id:"data-prediction-with-machine-learning"},"Data prediction with machine learning"),(0,n.kt)("p",null,"The architecture highlights in ",(0,n.kt)("strong",{parentName:"p"},"yellow")," the components that facilitate the integration of digital twins with Machine Learning models. Providing this support represents a crucial aspect in the development of a digital twin, since it provides a complementary or comparative perspective with real data, enriching the understanding of the replicated object. To achieve this goal, the following tools are used:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/kafka-ml"},"Kafka-ML"),". This open source framework manages the lifecycle of ML/AI applications in production environments through continuous data streams. Unlike traditional frameworks that work with static data sets, Kafka-ML enables both training and inference with continuous data streams, allowing users to have fine-grained control over ingestion data. Currently, Kafka-ML is compatible with the most popular ML frameworks, ",(0,n.kt)("a",{parentName:"p",href:"https://www.tensorflow.org/"},"TensorFlow")," and ",(0,n.kt)("a",{parentName:"p",href:"https://pytorch.org/"},"PyTorch"),", and enables the ",(0,n.kt)("strong",{parentName:"p"},"management and deployment of ML models"),", from definition to final deployment for inference. This component operates as a black box in OpenTwins, receiving input data for a deployed model through a Kafka topic and sending the predicted result to another topic, which is connected to Eclipse Ditto in a way that updates to the corresponding digital twin.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/eclipse-hono-to-kafka-ml"},"Eclipse Hono to Kafka-ML"),". Kafka-ML can receive input data from any source that is able to publish to a Kafka topic. However, at OpenTwins we have decided to simplify this process when the data comes from Eclipse Hono. Therefore, we have developed an optional service that automates the data feed of ML models deployed in Kafka-ML. This service ",(0,n.kt)("strong",{parentName:"p"},"automatically sends the data needed to make a prediction")," every time a new data is received from any of the devices required by the model. To use this tool, we provide an API that allows you to specify which devices should be taken into account, what data is required from these devices and how they should be formatted to work correctly as input for Kafka-ML.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/error-detection-for-eclipse-hono-with-kafka-ml"},"Error detection for Eclipse Hono with Kafka-ML"),". An ML model useful in the construction of a digital twin is one capable of generating data that a sensor should produce in case it loses connection or experiences a failure. To automate this, we have developed an optional service with similar functionalities to the one mentioned above, but with an important particularity: it will only invoke the model when an interruption in data reception by the device is detected. This service takes into account the frequency with which the data is emitted by the device. As soon as an anomaly is identified, the service will format and send the last data received following the expected frequency until the connection is restored and real data is received again. In this way, the ",(0,n.kt)("strong",{parentName:"p"},"normal operation of the device is simulated"),", ensuring continuity of information for the digital twin."))),(0,n.kt)("h3",{id:"3d-representation"},"3D representation"),(0,n.kt)("admonition",{type:"note"},(0,n.kt)("p",{parentName:"admonition"},"Although Unity is not open source, at the moment it is the only graphics engine we have tested the plugin with.\nHowever, it could be replaced by any other graphics engine that compiles in WebGL, such as ",(0,n.kt)("a",{parentName:"p",href:"https://godotengine.org/"},"Godot"),", since the plugin is expected to be able to render any WebGL compilation. However, since we have not yet tested with other graphics engines, we cannot guarantee this.")),(0,n.kt)("p",null,"Although it may seem a secondary aspect, the representation of the digital twin makes a major difference in its utility and adoption. An intuitive and attractive visual interface for users will facilitate the understanding and accessibility of the data received, which simplifies the optimization of the actual system. 3D representations stand out as one of the most effective options in this sense, which motivates most private digital twin platforms to offer support for them. For this reason, OpenTwins allows adding an interactive 3D representation of the digital twin that reacts dynamically to data received from any source (real, predicted or simulated). The components highlighted in ",(0,n.kt)("strong",{parentName:"p"},"red")," are the ones that enable this functionality."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://unity.com/"},"Unity")," This powerful ",(0,n.kt)("strong",{parentName:"p"},"graphics engine"),", versatile in both 3D and 2D development, is widely used in the creation of video games, simulations and engineering. It is recognized as one of the most popular, supported by a large and active community. Although it is not open source software, it can be used ",(0,n.kt)("a",{parentName:"p",href:"https://unity.com/es/products/unity-personal?currency=EUR"},"free of charge for personal or low-profit projects"),". The technology of this engine allows to assign behaviors to 3D objects by means of scripts, which facilitates interaction both with the user and with other elements of the environment."),(0,n.kt)("admonition",{parentName:"li",type:"info"},(0,n.kt)("p",{parentName:"admonition"},"Unity offers a wide range of ",(0,n.kt)("a",{parentName:"p",href:"https://docs.unity3d.com/2023.2/Documentation/Manual/3D-formats.html"},"formats for importing 3D models"),", but we emphasize its integration with ",(0,n.kt)("a",{parentName:"p",href:"https://www.blender.org/"},"Blender"),", an open source 3D creation suite that is equally popular and supported by an active community. ")),(0,n.kt)("p",{parentName:"li"},"On the other hand, Unity provides the possibility to compile projects in the ",(0,n.kt)("strong",{parentName:"p"},"Unity ",(0,n.kt)("a",{parentName:"strong",href:"https://get.webgl.org/"},"WebGL"))," format, perfect for web rendering. This option is the choice of OpenTwins, as it allows easy integration with existing web technologies, ensuring accessibility and distribution without the need for additional installations.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/unity-plugin-for-grafana"},"Unity panel plugin for Grafana"),". Since Grafana serves as the front-end of OpenTwins, it is convenient that the 3D representations are embedded directly into this tool, providing a unified management and visualization of the digital twin. To achieve this, a plugin capable of ",(0,n.kt)("strong",{parentName:"p"},"rendering WebGL compilations within a Grafana panel")," has been developed. This plugin is able to send the digital twin data from Grafana to the compilation, allowing it to influence the rendering in real time. In addition, this plugin enables direct user interaction with the 3D model, allowing actions on 3D elements to affect other panels of the dashboard. For example, by clicking on a 3D element, another Grafana panel can automatically display data related to it."))),(0,n.kt)("h2",{id:"lightweight-architecture"},"Lightweight architecture"),(0,n.kt)("admonition",{type:"note"},(0,n.kt)("p",{parentName:"admonition"},"Although it is possible to deploy and connect the different components without containerization, this approach is not recommended due to the difficulties involved in terms of installation and management. However, it is important to note that Lightweight version of OpenTwins could be ",(0,n.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/manual"},"manually connected")," to non-containerized components.")),(0,n.kt)("p",null,"The following image illustrates the current lightweigh architecture of OpenTwins, the field of digital twins is closely linked to the IoT, highlighting the critical importance of reducing data transmission delays. Additionally, IoT devices typically have limited processing capabilities, which makes running resource-demanding software impractical. This new architecture has been developed to facilitate dependable IoT applications within a distributed Edge/Fog/Cloud infrastructure. Developing a lightweight distributed version of OpenTwins can offer several advantages and address various needs depending on the context and goals of the project."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"LightweightArchitecture",src:a(7526).Z,width:"1795",height:"702"})),(0,n.kt)("p",null,"Like the main platform, the core component of this new architecture remains ",(0,n.kt)("a",{parentName:"p",href:"https://www.eclipse.org/ditto/"},"Eclipse Ditto"),". Most of the components has been removed to achieve lower consumptions."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Message broker:")," The ",(0,n.kt)("a",{parentName:"p",href:"https://kafka.apache.org/"},"Apache Kafka")," messaging broker has been replaced by ",(0,n.kt)("a",{parentName:"p",href:"https://mosquitto.org/"},"Eclipse Mosquitto")," that uses ",(0,n.kt)("a",{parentName:"p",href:"https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html"},"MQTT5"),", as it is best suited messaging protocol for IoT.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Persistence:")," As the platform is designed to be used in low-resource environments such as IoT devices or Raspberry Pi, for example, it has been decided not to have persistence of historical data, so ",(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/products/influxdb-overview/"},"InfluxDB")," is not used. In the case of a persistence need, the ",(0,n.kt)("a",{parentName:"p",href:"https://www.mongodb.com/"},"MongoDB")," database that Eclipse Ditto needs to work can be used. ",(0,n.kt)("a",{parentName:"p",href:"https://www.influxdata.com/time-series-platform/telegraf/"},"Telegraf")," can introduce the historical data in this database. In this way, although we do not have a database optimized to store data in the form of time series, it would be possible to have persistence with a single database.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Visualization:")," Both IoT and Edge devices are not typically used for visualization-related tasks and are sometimes lacking the power to do so. This is why it has been decided to remove this component from the new lightweight architecture.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Simulation components:")," Due to the technical limitations mentioned above, the simulation components present in the original architecture have been eliminated.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"ML components:")," As mentioned above, some edge or IoT are not capable of handling the necessary components to run the ML module, so its installation, although it has been used in this work, is optional."))),(0,n.kt)("p",null,"All modules that are not present in this version of the platform are still fully available and compatible, so users can make use of any component if necessary by activating them in the platform installation process by ",(0,n.kt)("a",{parentName:"p",href:"https://helm.sh/"},"Helm"),"(WIP)"))}d.isMDXComponent=!0},3160:(e,t,a)=>{a.d(t,{Z:()=>i});const i=a.p+"assets/images/architecture-ff30194687d6d921534d28bb801abe74.jpg"},7526:(e,t,a)=>{a.d(t,{Z:()=>i});const i=a.p+"assets/images/lightweightArchitecture-21af82d7bc7628d2b18b2392dca7ed29.png"}}]); \ No newline at end of file diff --git a/assets/js/e11471c7.3a30b136.js b/assets/js/e11471c7.3a30b136.js new file mode 100644 index 0000000..b77c57e --- /dev/null +++ b/assets/js/e11471c7.3a30b136.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9784],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});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 l(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 s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),d=p(n),m=i,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||o;return n?a.createElement(h,l(l({ref:t},u),{},{components:n})):a.createElement(h,l({ref:t},u))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,l=new Array(o);l[0]=m;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[d]="string"==typeof e?e:i,l[1]=r;for(var p=2;p{n.d(t,{Z:()=>l});var a=n(7294),i=n(6010);const o={tabItem:"tabItem_Ymn6"};function l(e){let{children:t,hidden:n,className:l}=e;return a.createElement("div",{role:"tabpanel",className:(0,i.Z)(o.tabItem,l),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>c});var a=n(7462),i=n(7294),o=n(6010),l=n(2389),r=n(7392),s=n(7094),p=n(2466);const u={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function d(e){const{lazy:t,block:n,defaultValue:l,values:d,groupId:c,className:m}=e,h=i.Children.map(e.children,(e=>{if((0,i.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=d??h.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),g=(0,r.l)(f,((e,t)=>e.value===t.value));if(g.length>0)throw new Error(`Docusaurus error: Duplicate values "${g.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const k=null===l?l:l??h.find((e=>e.props.default))?.props.value??h[0].props.value;if(null!==k&&!f.some((e=>e.value===k)))throw new Error(`Docusaurus error: The has a defaultValue "${k}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:y,setTabGroupChoices:b}=(0,s.U)(),[v,w]=(0,i.useState)(k),N=[],{blockElementScrollPositionUntilNextRender:T}=(0,p.o5)();if(null!=c){const e=y[c];null!=e&&e!==v&&f.some((t=>t.value===e))&&w(e)}const O=e=>{const t=e.currentTarget,n=N.indexOf(t),a=f[n].value;a!==v&&(T(t),w(a),null!=c&&b(c,String(a)))},I=e=>{let t=null;switch(e.key){case"Enter":O(e);break;case"ArrowRight":{const n=N.indexOf(e.currentTarget)+1;t=N[n]??N[0];break}case"ArrowLeft":{const n=N.indexOf(e.currentTarget)-1;t=N[n]??N[N.length-1];break}}t?.focus()};return i.createElement("div",{className:(0,o.Z)("tabs-container",u.tabList)},i.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},m)},f.map((e=>{let{value:t,label:n,attributes:l}=e;return i.createElement("li",(0,a.Z)({role:"tab",tabIndex:v===t?0:-1,"aria-selected":v===t,key:t,ref:e=>N.push(e),onKeyDown:I,onClick:O},l,{className:(0,o.Z)("tabs__item",u.tabItem,l?.className,{"tabs__item--active":v===t})}),n??t)}))),t?(0,i.cloneElement)(h.filter((e=>e.props.value===v))[0],{className:"margin-top--md"}):i.createElement("div",{className:"margin-top--md"},h.map(((e,t)=>(0,i.cloneElement)(e,{key:t,hidden:e.props.value!==v})))))}function c(e){const t=(0,l.Z)();return i.createElement(d,(0,a.Z)({key:String(t)},e))}},9737:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>r,metadata:()=>p,toc:()=>d});var a=n(7462),i=(n(7294),n(3905)),o=n(5488),l=n(5162);const r={sidebar_position:2},s="Composition (recommended)",p={unversionedId:"installation/manual/composition",id:"installation/manual/composition",title:"Composition (recommended)",description:"Prerequisites",source:"@site/docs/installation/manual/composition.md",sourceDirName:"installation/manual",slug:"/installation/manual/composition",permalink:"/opentwins/docs/installation/manual/composition",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual/composition.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"DT definition and monitoring (required)",permalink:"/opentwins/docs/installation/manual/essential"},next:{title:"Machine Learning",permalink:"/opentwins/docs/installation/manual/machine-learning"}},u={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Deploy",id:"deploy",level:2},{value:"Extended API for Eclipse Ditto",id:"extended-api-for-eclipse-ditto",level:3},{value:"OpenTwins app plugin for Grafana",id:"opentwins-app-plugin-for-grafana",level:3},{value:"Connect",id:"connect",level:2},{value:"Obtain external URLs",id:"obtain-external-urls",level:3},{value:"Configure OpenTwins plugin",id:"configure-opentwins-plugin",level:3}],c={toc:d},m="wrapper";function h(e){let{components:t,...r}=e;return(0,i.kt)(m,(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"composition-recommended"},"Composition (recommended)"),(0,i.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("p",null,"Before you begin, ensure you have the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Container manager: Currently tested on ",(0,i.kt)("a",{parentName:"li",href:"https://www.docker.com/"},"Docker")," and ",(0,i.kt)("a",{parentName:"li",href:"https://containerd.io/"},"ContainerD"),"."),(0,i.kt)("li",{parentName:"ul"},"Access to a ",(0,i.kt)("a",{parentName:"li",href:"https://kubernetes.io/releases/download/"},"Kubernetes")," (recommended) or ",(0,i.kt)("a",{parentName:"li",href:"https://k3s.io/"},"K3s")," cluster."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"kubectl")," installed and configured.")),(0,i.kt)("h2",{id:"deploy"},"Deploy"),(0,i.kt)("p",null,"To provide OpenTwins with digital twin composition capabilities it is necessary to add two components. You can check ",(0,i.kt)("a",{parentName:"p",href:"/opentwins/docs/overview/architecture#compositional-support"},"architecture")," to know what is the functionality of each one and how it connects with the rest of the elements."),(0,i.kt)("h3",{id:"extended-api-for-eclipse-ditto"},"Extended API for Eclipse Ditto"),(0,i.kt)("p",null,"This component, developed in NodeJS, has its code available in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/extended-api-for-eclipse-ditto"},"its repository"),". It has been containerized with Docker and published in ",(0,i.kt)("a",{parentName:"p",href:"https://hub.docker.com/r/ertis/ditto-extended-api"},"DockerHub"),"."),(0,i.kt)("p",null,"To install it in a Kubernetes cluster we will use a deployment and a service, but it will be necessary to previously modify the environment variables containing the Eclipse Ditto IP and its credentials. In addition, to enable the query of all policies, it must also be configured with the IP of the MongoDB instance used by Eclipse Ditto."),(0,i.kt)("p",null,"These are the environment variables of the component:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Name"),(0,i.kt)("th",{parentName:"tr",align:null},"Type"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"HOST")),(0,i.kt)("td",{parentName:"tr",align:null},"IP"),(0,i.kt)("td",{parentName:"tr",align:null},"Host where the API will be deployed (default: localhost)")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"PORT")),(0,i.kt)("td",{parentName:"tr",align:null},"int"),(0,i.kt)("td",{parentName:"tr",align:null},"Port to serve as endpoint for the API (default: 8080)")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"MONGO_URI_POLICIES")),(0,i.kt)("td",{parentName:"tr",align:null},"URI"),(0,i.kt)("td",{parentName:"tr",align:null},"MongoDB URI to extract the policies. It must follow the format: ",(0,i.kt)("em",{parentName:"td"},"mongodb://IP_MONGODB:PORT_MONGODB/policies"))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"DITTO_URI_THINGS")),(0,i.kt)("td",{parentName:"tr",align:null},"URI"),(0,i.kt)("td",{parentName:"tr",align:null},"Eclipse Ditto ",(0,i.kt)("strong",{parentName:"td"},"nginx")," service URI to provide functionality and apply constraints for composition. It must follow the format: ",(0,i.kt)("em",{parentName:"td"},"http://IP_DITTO:PORT_DITTO"))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"DITTO_USERNAME_API")),(0,i.kt)("td",{parentName:"tr",align:null},"text"),(0,i.kt)("td",{parentName:"tr",align:null},"Eclipse Ditto API user")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"DITTO_PASSWORD_API")),(0,i.kt)("td",{parentName:"tr",align:null},"text"),(0,i.kt)("td",{parentName:"tr",align:null},"Eclipse Ditto API password")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"DITTO_USERNAME_DEVOPS")),(0,i.kt)("td",{parentName:"tr",align:null},"text"),(0,i.kt)("td",{parentName:"tr",align:null},"Eclipse Ditto Devops user (user who can create connections)")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"DITTO_PASSWORD_DEVOPS")),(0,i.kt)("td",{parentName:"tr",align:null},"text"),(0,i.kt)("td",{parentName:"tr",align:null},"Eclipse Ditto Devops password")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("strong",{parentName:"td"},"ALL_LOGS")),(0,i.kt)("td",{parentName:"tr",align:null},"boolean"),(0,i.kt)("td",{parentName:"tr",align:null},"If enabled, the component logs will show the results of all requests it sends to Eclipse Ditto. It is only useful if you need to debug (default: false)")))),(0,i.kt)("p",null,"It is ",(0,i.kt)("strong",{parentName:"p"},"necessary to set up all the ones that start with DITTO"),", although it is highly recommended to set up the MONGO_URI_POLICIES one as well."),(0,i.kt)("p",null,"With this information, we will create a YAML file for a deployment and a YAML file for a service. All values, including those for credentials, correspond to the default values of Eclipse Ditto for the version indicated in the ",(0,i.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/manual/essential#eclipse-ditto-v33"},"essential")," part. If you have changed the default values, you may need to modify these. "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="deployment.yaml"',title:'"deployment.yaml"'},'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: opentwins-ditto-extended-api\nspec:\n selector:\n matchLabels:\n app.kubernetes.io/name: opentwins-ditto-extended-api\n replicas: 1\n template:\n metadata:\n labels:\n app.kubernetes.io/name: opentwins-ditto-extended-api\n spec:\n containers:\n - name: ditto-extended-api\n image: ertis/ditto-extended-api:latest\n imagePullPolicy: Always\n ports:\n - containerPort: 8080\n protocol: TCP\n env: \n - name: HOST \n value: "localhost" \n - name: PORT \n value: "8080" \n - name: MONGO_URI_POLICIES \n value: "mongodb://mongodb:27017/policies" \n - name: DITTO_URI_THINGS \n value: "http://ditto-nginx:30525" \n - name: DITTO_USERNAME_API \n value: "ditto" \n - name: DITTO_PASSWORD_API \n value: "ditto" \n - name: DITTO_USERNAME_DEVOPS \n value: "devops" \n - name: DITTO_PASSWORD_DEVOPS \n value: "foobar"\n - name: ALL_LOGS \n value: false\n')),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml",metastring:'title="service.yaml"',title:'"service.yaml"'},"apiVersion: v1\nkind: Service\nmetadata:\n name: opentwins-ditto-extended-api\n labels:\n app.kubernetes.io/name: opentwins-ditto-extended-api\nspec:\n type: NodePort\n ports:\n - name: http\n nodePort: 30526\n port: 8080\n protocol: TCP\n targetPort: 8080\n selector:\n app.kubernetes.io/name: opentwins-ditto-extended-api\n")),(0,i.kt)("p",null,"To deploy them in the Kubernetes cluster we will use the commands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"kubectl apply -f deployment.yaml -n opentwins\nkubectl apply -f service.yaml -n opentwins\n")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Verify that the component is running correctly")," by querying the pod status, which should be Running and Ready 1/1. "),(0,i.kt)("h3",{id:"opentwins-app-plugin-for-grafana"},"OpenTwins app plugin for Grafana"),(0,i.kt)("p",null,"The code of this plugin can be found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/grafana-app-opentwins"},"his repository")," and the latest version of the plugin will always be compiled in a zip file as a ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ertis-research/grafana-app-opentwins/releases/tag/latest"},"release"),"."),(0,i.kt)("p",null,"The installation of the OpenTwins plugin in Grafana will depend on how Grafana was installed and the version you are using. Below, we explain the process for installations done via Helm and for local installations. However, it is highly recommended to check the ",(0,i.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/latest/administration/plugin-management/#install-grafana-plugins"},"official Grafana documentation")," for detailed instructions on plugin installation, as there may be specific variations depending on your environment or version."),(0,i.kt)(o.Z,{groupId:"environment",mdxType:"Tabs"},(0,i.kt)(l.Z,{value:"helm",label:"Helm",default:!0,mdxType:"TabItem"},(0,i.kt)("p",null,"To install the plugin you need to add its compiled code in a folder with the same name as its ID inside the Grafana plugins folder, which is ",(0,i.kt)("em",{parentName:"p"},"/var/lib/grafana/plugins")," by default.\nTo do this using Helm, add an extraInitContainer to your values.yaml, where you navigate to the plugins folder, download the zip of the latest release and unzip it.\nBelow is what you need to add."),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"Note that some keys may overlap with other keys you already have in your values.yaml, ",(0,i.kt)("strong",{parentName:"p"},"do not just copy it but mix both YAMLs"))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml",metastring:"title=values.yaml",title:"values.yaml"},"extraInitContainers:\n- name: install-opentwins-plugins\n image: busybox\n command:\n - /bin/sh\n - -c\n - |\n #!/bin/sh\n set -euo pipefail\n mkdir -p /grafana-storage/plugins\n cd /grafana-storage/plugins\n wget --no-check-certificate -O ertis-opentwins.zip https://github.com/ertis-research/opentwins-in-grafana/releases/download/latest/ertis-opentwins.zip\n unzip -o ertis-opentwins.zip\n rm ertis-opentwins.zip\n volumeMounts:\n - name: storage\n mountPath: /grafana-storage\n")),(0,i.kt)("p",null,"At the moment the plugin is not signed, so you will have to add the plugin id (",(0,i.kt)("em",{parentName:"p"},"ertis-opentwins"),") to the list of unsigned plugins, which is also defined inside the values.yaml. This will allow Grafana to show it as an installable plugin (if not, it will not appear at all). Below is what you need to add (note that if you have followed the manual installation of the ",(0,i.kt)("a",{parentName:"p",href:"/opentwins/docs/installation/manual/essential#grafana-v95"},"essential functionality")," you should already have it configured.)."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-yaml",metastring:"title=values.yaml",title:"values.yaml"},"grafana.ini:\n plugins:\n allow_loading_unsigned_plugins: ertis-opentwins,ertis-unity-panel\n")),(0,i.kt)("p",null,"Now update the Grafana helm: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"helm upgrade grafana grafana/grafana -n opentwins --version 6.56.1 -f values.yaml\n")),(0,i.kt)("p",null,"Verify that the Grafana pod is in Running and Ready status. The OpenTwins plugin should now be available for enabling in the Grafana configuration.")),(0,i.kt)(l.Z,{value:"local",label:"Local",mdxType:"TabItem"},(0,i.kt)("p",null,"To install the plugin on a local Grafana, you must first download the zip file of the latest plugin release and then access the Grafana folder on your PC. "),(0,i.kt)("p",null,"In this folder you have to find the ",(0,i.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/v9.5/setup-grafana/configure-grafana"},"Grafana configuration file"),". Follow the ",(0,i.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/v9.5/setup-grafana/configure-grafana/#configuration-file-location"},"Grafana documentation")," to know its location, the name of the file and how to modify it. When you have it, modify the appropriate file by uncommenting and adding the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ini"},"[plugins]\n# Enter a comma-separated list of plugin identifiers to identify plugins to load even if they are unsigned. Plugins with modified signatures are never loaded.\nallow_loading_unsigned_plugins = ertis-opentwins\n")),(0,i.kt)("p",null,"In the same file, check the ",(0,i.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/v9.5/setup-grafana/configure-grafana/#plugins"},"path to the plugins folder"),'. You can modify it if you consider it convenient. Then, go to that folder and unzip the plugin zip file. You should get a folder with the name "ertis-opentwins" which must have something like this inside (make sure that there are no intermediate folders).'),(0,i.kt)("center",null,(0,i.kt)("img",{src:n(3098).Z,alt:"Kubectl get services",style:{width:700}})),(0,i.kt)("p",null,"For the changes to take effect, ",(0,i.kt)("strong",{parentName:"p"},"Grafana must be restarted"),". Please refer to ",(0,i.kt)("a",{parentName:"p",href:"https://grafana.com/docs/grafana/v9.5/setup-grafana/start-restart-grafana/"},"its documentation")," to find out how to do this depending on your operating system. The OpenTwins plugin should now be available for enabling in the Grafana configuration."))),(0,i.kt)("h2",{id:"connect"},"Connect"),(0,i.kt)("p",null,"Now you have to ",(0,i.kt)("strong",{parentName:"p"},"configure the OpenTwins plugin")," in Grafana with the Ditto Extended API and Eclipse Ditto URLs."),(0,i.kt)("h3",{id:"obtain-external-urls"},"Obtain external URLs"),(0,i.kt)("p",null,"Get the name of the services with ",(0,i.kt)("inlineCode",{parentName:"p"},"kubectl get services"),". The method to obtain the URL may vary depending on the configuration of your cluster. The URL for each service will match the cluster IP and the port that will depend on the ",(0,i.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types"},"type of service")," (LoadBalancer or NodePort). For example, if our cluster IP is ",(0,i.kt)("inlineCode",{parentName:"p"},"192.168.32.25")," and uses a NodePort service with the port 30718, the URL for Grafana would be ",(0,i.kt)("inlineCode",{parentName:"p"},"192.168.32.25:30718"),"."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Are you using ",(0,i.kt)("b",null,"Minikube")," to deploy OpenTwins?"),(0,i.kt)("div",null,(0,i.kt)("p",null,"As Minikube is a local cluster, you ",(0,i.kt)("strong",{parentName:"p"},"cannot directly use the IP of the cluster"),". Therefore, you will have to ",(0,i.kt)("a",{parentName:"p",href:"https://minikube.sigs.k8s.io/docs/handbook/accessing/"},"expose the services")," that you want to use externally with a command."),(0,i.kt)("p",null,"Open three terminals, one for each service, and run the following command on each terminal with a different service name. These will return a URL of your localhost with a port that will forward all traffic to the specified service. ",(0,i.kt)("strong",{parentName:"p"},"These are the URLs you should use.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"minikube service --url\n")))),(0,i.kt)("h3",{id:"configure-opentwins-plugin"},"Configure OpenTwins plugin"),(0,i.kt)("p",null,"Access Grafana in any browser with the URL you have obtained. The credentials must match those indicated in the Helm values, which by default are user ",(0,i.kt)("em",{parentName:"p"},"admin")," and password ",(0,i.kt)("em",{parentName:"p"},"admin"),". "),(0,i.kt)("p",null,"Access the left drop-down menu and select ",(0,i.kt)("inlineCode",{parentName:"p"},"Administration > Plugins"),". Once there, find the ",(0,i.kt)("em",{parentName:"p"},"OpenTwins")," plugin and activate it by clicking ",(0,i.kt)("em",{parentName:"p"},"Enable"),". Then, go to the ",(0,i.kt)("em",{parentName:"p"},"Configuration")," tab where you will need to enter the Eclipse Ditto and Extended API URLs in the corresponding fields. Use ",(0,i.kt)("em",{parentName:"p"},"ditto")," for both the Eclipse Ditto username and password if you have not changed the credentials. Then click on ",(0,i.kt)("em",{parentName:"p"},"Save settings")," to complete the plugin configuration."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Screenshots"),(0,i.kt)("div",null,(0,i.kt)("center",null,(0,i.kt)("img",{src:n(6482).Z,alt:"Plugin",style:{width:600}})),(0,i.kt)("center",null,(0,i.kt)("img",{src:n(3508).Z,alt:"Configuration",style:{width:600}})),(0,i.kt)("center",null,(0,i.kt)("img",{src:n(8407).Z,alt:"Configuration",style:{width:400}})))),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"If you are using the latest version of the interface, you may find two fields intended for an agent service. This functionality is currently under development and is not yet available, so leave them empty and disregard them for now.")),(0,i.kt)("p",null,"Find the available application in the ",(0,i.kt)("inlineCode",{parentName:"p"},"App > OpenTwins")," section of the left drop-down menu. "),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"You have now support for the composition of digital twins.")))}h.isMDXComponent=!0},3508:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/configuration-interfaz-c20eaffea1d3bec206f55464ba19679a.png"},6482:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/enable-plugin-0aa4a65c98ecbff05f27d2b540455e1b.png"},8407:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/opentwins-access-2eb74b7ab18c9e4a88906e0a9a5a13fd.png"},3098:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/opentwins-plugin-content-0ab721e980fb07462f0ea875e004ac60.png"}}]); \ No newline at end of file diff --git a/assets/js/e677b25a.4140a2d3.js b/assets/js/e677b25a.4140a2d3.js deleted file mode 100644 index 52578df..0000000 --- a/assets/js/e677b25a.4140a2d3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9048],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>b});var a=n(7294);function r(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 a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",m={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,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),d=r,b=p["".concat(l,".").concat(d)]||p[d]||m[d]||i;return n?a.createElement(b,o(o({ref:t},u),{},{components:n})):a.createElement(b,o({ref:t},u))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,o[1]=s;for(var c=2;c{n.d(t,{Z:()=>o});var a=n(7294),r=n(6010);const i={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:n,className:o}=e;return a.createElement("div",{role:"tabpanel",className:(0,r.Z)(i.tabItem,o),hidden:n},t)}},5488:(e,t,n)=>{n.d(t,{Z:()=>m});var a=n(7462),r=n(7294),i=n(6010),o=n(2389),s=n(7392),l=n(7094),c=n(2466);const u={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function p(e){const{lazy:t,block:n,defaultValue:o,values:p,groupId:m,className:d}=e,b=r.Children.map(e.children,(e=>{if((0,r.isValidElement)(e)&&"value"in e.props)return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)})),f=p??b.map((e=>{let{props:{value:t,label:n,attributes:a}}=e;return{value:t,label:n,attributes:a}})),h=(0,s.l)(f,((e,t)=>e.value===t.value));if(h.length>0)throw new Error(`Docusaurus error: Duplicate values "${h.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`);const g=null===o?o:o??b.find((e=>e.props.default))?.props.value??b[0].props.value;if(null!==g&&!f.some((e=>e.value===g)))throw new Error(`Docusaurus error: The has a defaultValue "${g}" but none of its children has the corresponding value. Available values are: ${f.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);const{tabGroupChoices:v,setTabGroupChoices:w}=(0,l.U)(),[A,y]=(0,r.useState)(g),E=[],{blockElementScrollPositionUntilNextRender:T}=(0,c.o5)();if(null!=m){const e=v[m];null!=e&&e!==A&&f.some((t=>t.value===e))&&y(e)}const x=e=>{const t=e.currentTarget,n=E.indexOf(t),a=f[n].value;a!==A&&(T(t),y(a),null!=m&&w(m,String(a)))},j=e=>{let t=null;switch(e.key){case"Enter":x(e);break;case"ArrowRight":{const n=E.indexOf(e.currentTarget)+1;t=E[n]??E[0];break}case"ArrowLeft":{const n=E.indexOf(e.currentTarget)-1;t=E[n]??E[E.length-1];break}}t?.focus()};return r.createElement("div",{className:(0,i.Z)("tabs-container",u.tabList)},r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},d)},f.map((e=>{let{value:t,label:n,attributes:o}=e;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:A===t?0:-1,"aria-selected":A===t,key:t,ref:e=>E.push(e),onKeyDown:j,onClick:x},o,{className:(0,i.Z)("tabs__item",u.tabItem,o?.className,{"tabs__item--active":A===t})}),n??t)}))),t?(0,r.cloneElement)(b.filter((e=>e.props.value===A))[0],{className:"margin-top--md"}):r.createElement("div",{className:"margin-top--md"},b.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==A})))))}function m(e){const t=(0,o.Z)();return r.createElement(p,(0,a.Z)({key:String(t)},e))}},6618:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>b,frontMatter:()=>s,metadata:()=>c,toc:()=>p});var a=n(7462),r=(n(7294),n(3905)),i=n(5488),o=n(5162);const s={sidebar_position:2},l="Create a digital twin",c={unversionedId:"guides/dt-schema-creation",id:"guides/dt-schema-creation",title:"Create a digital twin",description:"The way to interact with Eclipse Ditto and therefore create not only digital twins, but connections, etc. is through http requests and methods.",source:"@site/docs/guides/dt-schema-creation.mdx",sourceDirName:"guides",slug:"/guides/dt-schema-creation",permalink:"/opentwins/docs/guides/dt-schema-creation",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/guides/dt-schema-creation.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Create a type",permalink:"/opentwins/docs/guides/type-creation"},next:{title:"Unity visualization",permalink:"/opentwins/docs/category/unity-visualization"}},u={},p=[],m={toc:p},d="wrapper";function b(e){let{components:t,...s}=e;return(0,r.kt)(d,(0,a.Z)({},m,s,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"create-a-digital-twin"},"Create a digital twin"),(0,r.kt)("p",null,"The way to interact with ",(0,r.kt)("a",{parentName:"p",href:"https://eclipse.dev/ditto/index.html"},"Eclipse Ditto")," and therefore create not only digital twins, but connections, etc. is through http requests and methods.\nAlthough the graphical interface of OpenTwins makes it unnecessary to go so low level, the option to communicate directly with Eclipse Ditto is still available."),(0,r.kt)(i.Z,{className:"unique-tabs",defaultValue:"ui",values:[{label:"Using Grafana interface",value:"ui"},{label:"Using http methods",value:"http"}],mdxType:"Tabs"},(0,r.kt)(o.Z,{value:"ui",mdxType:"TabItem"},(0,r.kt)("p",null,'To create a new digital twin schema using OpenTwins plugin in Grafana just select "Create new twin" button in Twins tab.\n',(0,r.kt)("img",{alt:"CreateTwin",src:n(2382).Z,width:"177",height:"42"}))),(0,r.kt)(o.Z,{value:"http",mdxType:"TabItem"},"This is an orange")))}b.isMDXComponent=!0},2382:(e,t,n)=>{n.d(t,{Z:()=>a});const a="data:image/png;base64,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"}}]); \ No newline at end of file diff --git a/assets/js/e950844d.858a3214.js b/assets/js/e950844d.858a3214.js new file mode 100644 index 0000000..67b9bf5 --- /dev/null +++ b/assets/js/e950844d.858a3214.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3734],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var r=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 a(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||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(n),m=i,f=p["".concat(s,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(f,o(o({ref:t},c),{},{components:n})):r.createElement(f,o({ref:t},c))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:i,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>u});var r=n(7462),i=(n(7294),n(3905));const a={sidebar_position:5},o="3D visualization",l={unversionedId:"installation/manual/unity",id:"installation/manual/unity",title:"3D visualization",description:"Prerequisites",source:"@site/docs/installation/manual/unity.md",sourceDirName:"installation/manual",slug:"/installation/manual/unity",permalink:"/opentwins/docs/installation/manual/unity",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/installation/manual/unity.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"tutorialSidebar",previous:{title:"Simulations",permalink:"/opentwins/docs/installation/manual/simulations"},next:{title:"Guides",permalink:"/opentwins/docs/guides/"}},s={},u=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Deploy",id:"deploy",level:2},{value:"Connect",id:"connect",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"3d-visualization"},"3D visualization"),(0,i.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("h2",{id:"deploy"},"Deploy"),(0,i.kt)("h2",{id:"connect"},"Connect"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/eb58dad4.ce7e3bd0.js b/assets/js/eb58dad4.f93dfa8b.js similarity index 90% rename from assets/js/eb58dad4.ce7e3bd0.js rename to assets/js/eb58dad4.f93dfa8b.js index cd03ddb..09bc60e 100644 --- a/assets/js/eb58dad4.ce7e3bd0.js +++ b/assets/js/eb58dad4.f93dfa8b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5998],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),p=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(r),f=a,d=u["".concat(i,".").concat(f)]||u[f]||m[f]||o;return r?n.createElement(d,l(l({ref:t},s),{},{components:r})):n.createElement(d,l({ref:t},s))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[u]="string"==typeof e?e:a,l[1]=c;for(var p=2;p{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={},l="Bouncing ball",c={unversionedId:"examples/ball-example",id:"examples/ball-example",title:"Bouncing ball",description:"",source:"@site/docs/examples/ball-example.md",sourceDirName:"examples",slug:"/examples/ball-example",permalink:"/opentwins/docs/examples/ball-example",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/examples/ball-example.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Sending data to Ditto",permalink:"/opentwins/docs/examples/raspberry-example/sending-data"},next:{title:"FMI Simulation",permalink:"/opentwins/docs/category/fmi-simulation"}},i={},p=[],s={toc:p},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"bouncing-ball"},"Bouncing ball"))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5998],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),p=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(r),f=a,d=u["".concat(i,".").concat(f)]||u[f]||m[f]||o;return r?n.createElement(d,l(l({ref:t},s),{},{components:r})):n.createElement(d,l({ref:t},s))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[u]="string"==typeof e?e:a,l[1]=c;for(var p=2;p{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={},l="Bouncing ball",c={unversionedId:"examples/ball-example",id:"examples/ball-example",title:"Bouncing ball",description:"",source:"@site/docs/examples/ball-example.md",sourceDirName:"examples",slug:"/examples/ball-example",permalink:"/opentwins/docs/examples/ball-example",draft:!1,editUrl:"https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/docs/examples/ball-example.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Sending data to Ditto",permalink:"/opentwins/docs/examples/raspberry-example/sending-data"}},i={},p=[],s={toc:p},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"bouncing-ball"},"Bouncing ball"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/main.20867153.js b/assets/js/main.20867153.js new file mode 100644 index 0000000..fa0e77d --- /dev/null +++ b/assets/js/main.20867153.js @@ -0,0 +1,2 @@ +/*! For license information please see main.20867153.js.LICENSE.txt */ +(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(7462),o=n(8356),i=n.n(o),l=n(6887);const s={"01a85c17":[()=>Promise.all([n.e(532),n.e(4013)]).then(n.bind(n,1223)),"@theme/BlogTagsListPage",1223],"0598cbc5":[()=>n.e(4576).then(n.t.bind(n,8895,19)),"~blog/default/opentwins-blog-tags-docusaurus-7d9.json",8895],"0964aedb":[()=>n.e(7632).then(n.t.bind(n,8233,19)),"~blog/default/opentwins-blog-tags-hello-e14.json",8233],"118e913f":[()=>n.e(7979).then(n.bind(n,4772)),"@site/docs/overview/concepts.md",4772],"14eb3368":[()=>Promise.all([n.e(532),n.e(9817)]).then(n.bind(n,5541)),"@theme/DocCategoryGeneratedIndexPage",5541],"15555c3b":[()=>n.e(4298).then(n.bind(n,2354)),"@site/docs/installation/manual/simulations.md",2354],"16179cba":[()=>Promise.all([n.e(532),n.e(8465)]).then(n.bind(n,4252)),"@site/docs/installation/manual/index.md",4252],17896441:[()=>Promise.all([n.e(532),n.e(210),n.e(7918)]).then(n.bind(n,5154)),"@theme/DocItem",5154],"1ba72f0d":[()=>n.e(8906).then(n.t.bind(n,531,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-installation-be0.json",531],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1c4bf583":[()=>n.e(7431).then(n.t.bind(n,7503,19)),"~blog/default/opentwins-blog-ef0.json",7503],"1df93b7f":[()=>Promise.all([n.e(532),n.e(3237)]).then(n.bind(n,6924)),"@site/src/pages/index.tsx",6924],"1f391b9e":[()=>Promise.all([n.e(532),n.e(210),n.e(3085)]).then(n.bind(n,4247)),"@theme/MDXPage",4247],"29451ac5":[()=>Promise.all([n.e(532),n.e(8040)]).then(n.bind(n,8747)),"@site/docs/guides/definition/type-creation.mdx",8747],32191809:[()=>Promise.all([n.e(532),n.e(2614)]).then(n.bind(n,7607)),"@site/docs/examples/raspberry-example/raspberry-example.mdx",7607],"393be207":[()=>n.e(7414).then(n.bind(n,3123)),"@site/src/pages/markdown-page.md",3123],"3c0fcc1c":[()=>n.e(9521).then(n.t.bind(n,3034,19)),"~blog/default/opentwins-blog-archive-d07.json",3034],"3fb959cb":[()=>n.e(9534).then(n.t.bind(n,5745,19)),"/home/runner/work/opentwins/opentwins/docs/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],"40b0d055":[()=>n.e(1144).then(n.t.bind(n,8151,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-overview-546.json",8151],47986192:[()=>n.e(301).then(n.bind(n,7861)),"@site/docs/installation/manual/machine-learning.md",7861],59362658:[()=>n.e(2267).then(n.bind(n,8642)),"@site/blog/2021-08-01-mdx-blog-post.mdx",8642],"5a7456e0":[()=>Promise.all([n.e(532),n.e(1826)]).then(n.bind(n,6029)),"@site/docs/installation/using-helm.mdx",6029],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"5eb90766":[()=>n.e(4283).then(n.bind(n,248)),"@site/docs/guides/unity/using-grafana-plugin.mdx",248],"65d05370":[()=>n.e(6045).then(n.t.bind(n,7634,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-dt-definition-781.json",7634],"65f6152f":[()=>n.e(9601).then(n.bind(n,9090)),"@site/docs/guides/fmi/concepts.mdx",9090],"661cef18":[()=>n.e(9106).then(n.bind(n,85)),"@site/docs/guides/fmi/API.md",85],"6875c492":[()=>Promise.all([n.e(532),n.e(210),n.e(2529),n.e(8610)]).then(n.bind(n,1714)),"@theme/BlogTagsPostsPage",1714],"68c71cca":[()=>Promise.all([n.e(532),n.e(6216)]).then(n.bind(n,8657)),"@site/docs/examples/raspberry-example/sending-data.mdx",8657],70066871:[()=>n.e(5466).then(n.t.bind(n,5470,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-unity-visualization-49b.json",5470],"73664a40":[()=>n.e(3514).then(n.bind(n,1976)),"@site/blog/2019-05-29-long-blog-post.md",1976],74876495:[()=>n.e(5049).then(n.bind(n,4235)),"@site/docs/quickstart.mdx",4235],"7661071f":[()=>n.e(9642).then(n.bind(n,6911)),"@site/blog/2021-08-26-welcome/index.md?truncated=true",6911],"8101ff7e":[()=>Promise.all([n.e(532),n.e(5991)]).then(n.bind(n,4830)),"@site/docs/guides/definition/dt-schema-creation.mdx",4830],"814f3328":[()=>n.e(2535).then(n.t.bind(n,5641,19)),"~blog/default/blog-post-list-prop-default.json",5641],85531627:[()=>n.e(4699).then(n.t.bind(n,5570,19)),"~blog/default/opentwins-blog-tags-facebook-e48-list.json",5570],"8717b14a":[()=>n.e(948).then(n.bind(n,3352)),"@site/blog/2019-05-29-long-blog-post.md?truncated=true",3352],"8dd02d2f":[()=>n.e(2690).then(n.t.bind(n,8082,19)),"~blog/default/opentwins-blog-tags-facebook-e48.json",8082],"8ee96214":[()=>n.e(7826).then(n.bind(n,5190)),"@site/docs/examples/string-example.md",5190],"908ba98b":[()=>n.e(114).then(n.t.bind(n,4540,19)),"~blog/default/opentwins-blog-tags-tags-1fa.json",4540],"925b3f96":[()=>n.e(9003).then(n.bind(n,8856)),"@site/blog/2019-05-28-first-blog-post.md?truncated=true",8856],"9281dd35":[()=>n.e(5391).then(n.t.bind(n,4349,19)),"~blog/default/opentwins-blog-tags-docusaurus-7d9-list.json",4349],"928e06c2":[()=>n.e(7557).then(n.bind(n,8748)),"@site/docs/overview/purpose.md",8748],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"9501552e":[()=>Promise.all([n.e(532),n.e(3329)]).then(n.bind(n,1320)),"@site/docs/installation/manual/essential.md",1320],"96e1810e":[()=>n.e(8364).then(n.t.bind(n,4469,19)),"/home/runner/work/opentwins/opentwins/docs/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",4469],"9e4087bc":[()=>n.e(3608).then(n.bind(n,3169)),"@theme/BlogArchivePage",3169],a6aa9e1f:[()=>Promise.all([n.e(532),n.e(210),n.e(2529),n.e(3089)]).then(n.bind(n,46)),"@theme/BlogListPage",46],aa3c268d:[()=>n.e(5041).then(n.t.bind(n,7068,19)),"~blog/default/opentwins-blog-tags-hola-af8.json",7068],acac1da9:[()=>n.e(1761).then(n.t.bind(n,3769,19)),"/home/runner/work/opentwins/opentwins/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],b0bae498:[()=>n.e(788).then(n.t.bind(n,132,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-examples-5ba.json",132],c0eb0ada:[()=>n.e(799).then(n.t.bind(n,7849,19)),"~blog/default/opentwins-blog-tags-hola-af8-list.json",7849],ccc49370:[()=>Promise.all([n.e(532),n.e(210),n.e(2529),n.e(6103)]).then(n.bind(n,5203)),"@theme/BlogPostPage",5203],d03241c9:[()=>Promise.all([n.e(532),n.e(2871)]).then(n.bind(n,652)),"@site/docs/guides/index.md",652],d3d686ac:[()=>n.e(1495).then(n.t.bind(n,173,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-fmi-simulation-1c0.json",173],d72ac48e:[()=>n.e(6513).then(n.bind(n,5577)),"@site/docs/overview/architecture.md",5577],d9f32620:[()=>n.e(1914).then(n.bind(n,2900)),"@site/blog/2021-08-26-welcome/index.md",2900],dcc71bcc:[()=>n.e(9850).then(n.bind(n,1415)),"@site/docs/guides/unity/creating-unity-build.mdx",1415],e11471c7:[()=>Promise.all([n.e(532),n.e(9784)]).then(n.bind(n,9737)),"@site/docs/installation/manual/composition.md",9737],e273c56f:[()=>n.e(2362).then(n.bind(n,1947)),"@site/blog/2019-05-28-first-blog-post.md",1947],e950844d:[()=>n.e(3734).then(n.bind(n,3498)),"@site/docs/installation/manual/unity.md",3498],e9a1c9e5:[()=>n.e(4397).then(n.t.bind(n,1743,19)),"~docs/default/category-opentwinsdocs-tutorialsidebar-category-raspberry-pi-59c.json",1743],eb58dad4:[()=>n.e(5998).then(n.bind(n,8701)),"@site/docs/examples/ball-example.md",8701],ec3c7536:[()=>n.e(7063).then(n.t.bind(n,4326,19)),"~blog/default/opentwins-blog-tags-hello-e14-list.json",4326],f4f34a3a:[()=>n.e(8636).then(n.bind(n,5145)),"@site/blog/2021-08-01-mdx-blog-post.mdx?truncated=true",5145]};function u(e){let{error:t,retry:n,pastDelay:a}=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"))):a?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 p(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 o=l[`${e}-${t}`],p={},f=[],m=[],g=(0,c.Z)(o);return Object.entries(g).forEach((e=>{let[t,n]=e;const r=s[n];r&&(p[t]=r[0],f.push(r[1]),m.push(r[2]))})),i().Map({loading:u,loader:p,modules:f,webpack:()=>m,render(t,n){const i=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let o=i;const l=n.split(".");l.slice(0,-1).forEach((e=>{o=o[e]})),o[l[l.length-1]]=a}));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,a.Z)({},i,n)))}})}const f=[{path:"/opentwins/blog",component:p("/opentwins/blog","147"),exact:!0},{path:"/opentwins/blog/archive",component:p("/opentwins/blog/archive","554"),exact:!0},{path:"/opentwins/blog/first-blog-post",component:p("/opentwins/blog/first-blog-post","e7a"),exact:!0},{path:"/opentwins/blog/long-blog-post",component:p("/opentwins/blog/long-blog-post","2fa"),exact:!0},{path:"/opentwins/blog/mdx-blog-post",component:p("/opentwins/blog/mdx-blog-post","3e4"),exact:!0},{path:"/opentwins/blog/tags",component:p("/opentwins/blog/tags","f32"),exact:!0},{path:"/opentwins/blog/tags/docusaurus",component:p("/opentwins/blog/tags/docusaurus","540"),exact:!0},{path:"/opentwins/blog/tags/facebook",component:p("/opentwins/blog/tags/facebook","972"),exact:!0},{path:"/opentwins/blog/tags/hello",component:p("/opentwins/blog/tags/hello","1c2"),exact:!0},{path:"/opentwins/blog/tags/hola",component:p("/opentwins/blog/tags/hola","8e6"),exact:!0},{path:"/opentwins/blog/welcome",component:p("/opentwins/blog/welcome","9a6"),exact:!0},{path:"/opentwins/markdown-page",component:p("/opentwins/markdown-page","2f5"),exact:!0},{path:"/opentwins/docs",component:p("/opentwins/docs","a90"),routes:[{path:"/opentwins/docs/category/dt-definition",component:p("/opentwins/docs/category/dt-definition","fe8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/category/examples",component:p("/opentwins/docs/category/examples","97a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/category/fmi-simulation",component:p("/opentwins/docs/category/fmi-simulation","134"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/category/installation",component:p("/opentwins/docs/category/installation","976"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/category/overview",component:p("/opentwins/docs/category/overview","c3d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/category/raspberry-pi",component:p("/opentwins/docs/category/raspberry-pi","cba"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/category/unity-visualization",component:p("/opentwins/docs/category/unity-visualization","67c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/examples/ball-example",component:p("/opentwins/docs/examples/ball-example","3fa"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/examples/raspberry-example",component:p("/opentwins/docs/examples/raspberry-example","c00"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/examples/raspberry-example/sending-data",component:p("/opentwins/docs/examples/raspberry-example/sending-data","20b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/examples/string-example",component:p("/opentwins/docs/examples/string-example","40e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides",component:p("/opentwins/docs/guides","3c2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides/definition/dt-schema-creation",component:p("/opentwins/docs/guides/definition/dt-schema-creation","878"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides/definition/type-creation",component:p("/opentwins/docs/guides/definition/type-creation","38f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides/fmi/API",component:p("/opentwins/docs/guides/fmi/API","f1e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides/fmi/concepts",component:p("/opentwins/docs/guides/fmi/concepts","00c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides/unity/creating-unity-build",component:p("/opentwins/docs/guides/unity/creating-unity-build","532"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/guides/unity/using-grafana-plugin",component:p("/opentwins/docs/guides/unity/using-grafana-plugin","091"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/manual",component:p("/opentwins/docs/installation/manual","41f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/manual/composition",component:p("/opentwins/docs/installation/manual/composition","3f8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/manual/essential",component:p("/opentwins/docs/installation/manual/essential","c39"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/manual/machine-learning",component:p("/opentwins/docs/installation/manual/machine-learning","f9a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/manual/simulations",component:p("/opentwins/docs/installation/manual/simulations","b7d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/manual/unity",component:p("/opentwins/docs/installation/manual/unity","8fa"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/installation/using-helm",component:p("/opentwins/docs/installation/using-helm","e63"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/overview/architecture",component:p("/opentwins/docs/overview/architecture","6e0"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/overview/concepts",component:p("/opentwins/docs/overview/concepts","f3b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/overview/purpose",component:p("/opentwins/docs/overview/purpose","129"),exact:!0,sidebar:"tutorialSidebar"},{path:"/opentwins/docs/quickstart",component:p("/opentwins/docs/quickstart","20d"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/opentwins/",component:p("/opentwins/","5ac"),exact:!0},{path:"*",component:p("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>o});var r=n(7294);const a=r.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{o(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),o=n(3727),i=n(405),l=n(412);const s=[n(2497),n(3310),n(8320),n(2295)];var u=n(723),c=n(6550),d=n(8790);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var f=n(7462),m=n(5742),g=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,g.Z)(),n=(0,y.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function x(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.Z)(),a=function(){const{siteConfig:{url:e}}=(0,g.Z)(),{pathname:t}=(0,c.TH)();return e+(0,h.Z)(t)}(),o=t?`${n}${t}`:a;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:o}),r.createElement("link",{rel:"canonical",href:o}))}function _(){const{i18n:{currentLocale:e}}=(0,g.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(m.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(x,null),r.createElement(S,null),r.createElement(E.Z,{tag:k.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,f.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 P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const R=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(a&&function(e){const{hash:t}=e;if(t){const e=decodeURIComponent(t.substring(1)),n=document.getElementById(e);n?.scrollIntoView()}else window.scrollTo(0,0)}(n),P("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function N(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=>e.route.component.preload?.())))}class O extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?P("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=P("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),N(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(R,{previousLocation:this.previousLocation,location:t},r.createElement(c.AW,{location:t,render:()=>e}))}}const I=O,D="docusaurus-base-url-issue-banner-container",M="docusaurus-base-url-issue-banner",F="docusaurus-base-url-issue-banner-suggestion-container",B="__DOCUSAURUS_INSERT_BASEURL_BANNER";function j(e){return`\nwindow['${B}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${B}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${D}');\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[B]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,j(e))),r.createElement("div",{id:D}))}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.Z)(),{pathname:n}=(0,c.TH)();return t&&n===e?r.createElement(z,null):null}function $(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:o}}=(0,g.Z)(),i=(0,h.Z)(e),{htmlLang:l,direction:s}=o[a];return r.createElement(m.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 q=n(4763);function G(){const e=(0,d.H)(u.Z),t=(0,c.TH)();return r.createElement(q.Z,null,r.createElement(L.M,null,r.createElement(A.t,null,r.createElement(p,null,r.createElement($,null),r.createElement(_,null),r.createElement(U,null),r.createElement(I,{location:T(t)},e)))))}var H=n(6887);const Z=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var V=n(9670);const W=new Set,Y=new Set,K=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Q={prefetch(e){if(!(e=>!K()&&!Y.has(e)&&!W.has(e))(e))return!1;W.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,V.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Z(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!K()&&!Y.has(e))(e)&&(Y.add(e),N(e))},X=Object.freeze(Q);if(l.Z.canUseDOM){window.docusaurus=X;const e=a.hydrate;N(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(o.VK,null,r.createElement(G,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>c,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/opentwins/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/opentwins/docs","mainDocId":"quickstart","docs":[{"id":"examples/ball-example","path":"/opentwins/docs/examples/ball-example","sidebar":"tutorialSidebar"},{"id":"examples/raspberry-example/raspberry-example","path":"/opentwins/docs/examples/raspberry-example/","sidebar":"tutorialSidebar"},{"id":"examples/raspberry-example/sending-data","path":"/opentwins/docs/examples/raspberry-example/sending-data","sidebar":"tutorialSidebar"},{"id":"examples/string-example","path":"/opentwins/docs/examples/string-example","sidebar":"tutorialSidebar"},{"id":"guides/definition/dt-schema-creation","path":"/opentwins/docs/guides/definition/dt-schema-creation","sidebar":"tutorialSidebar"},{"id":"guides/definition/type-creation","path":"/opentwins/docs/guides/definition/type-creation","sidebar":"tutorialSidebar"},{"id":"guides/fmi/API","path":"/opentwins/docs/guides/fmi/API","sidebar":"tutorialSidebar"},{"id":"guides/fmi/concepts","path":"/opentwins/docs/guides/fmi/concepts","sidebar":"tutorialSidebar"},{"id":"guides/index","path":"/opentwins/docs/guides/","sidebar":"tutorialSidebar"},{"id":"guides/unity/creating-unity-build","path":"/opentwins/docs/guides/unity/creating-unity-build","sidebar":"tutorialSidebar"},{"id":"guides/unity/using-grafana-plugin","path":"/opentwins/docs/guides/unity/using-grafana-plugin","sidebar":"tutorialSidebar"},{"id":"installation/manual/composition","path":"/opentwins/docs/installation/manual/composition","sidebar":"tutorialSidebar"},{"id":"installation/manual/essential","path":"/opentwins/docs/installation/manual/essential","sidebar":"tutorialSidebar"},{"id":"installation/manual/index","path":"/opentwins/docs/installation/manual/","sidebar":"tutorialSidebar"},{"id":"installation/manual/machine-learning","path":"/opentwins/docs/installation/manual/machine-learning","sidebar":"tutorialSidebar"},{"id":"installation/manual/simulations","path":"/opentwins/docs/installation/manual/simulations","sidebar":"tutorialSidebar"},{"id":"installation/manual/unity","path":"/opentwins/docs/installation/manual/unity","sidebar":"tutorialSidebar"},{"id":"installation/using-helm","path":"/opentwins/docs/installation/using-helm","sidebar":"tutorialSidebar"},{"id":"overview/architecture","path":"/opentwins/docs/overview/architecture","sidebar":"tutorialSidebar"},{"id":"overview/concepts","path":"/opentwins/docs/overview/concepts","sidebar":"tutorialSidebar"},{"id":"overview/purpose","path":"/opentwins/docs/overview/purpose","sidebar":"tutorialSidebar"},{"id":"quickstart","path":"/opentwins/docs/quickstart","sidebar":"tutorialSidebar"},{"id":"/category/overview","path":"/opentwins/docs/category/overview","sidebar":"tutorialSidebar"},{"id":"/category/installation","path":"/opentwins/docs/category/installation","sidebar":"tutorialSidebar"},{"id":"/category/dt-definition","path":"/opentwins/docs/category/dt-definition","sidebar":"tutorialSidebar"},{"id":"/category/fmi-simulation","path":"/opentwins/docs/category/fmi-simulation","sidebar":"tutorialSidebar"},{"id":"/category/unity-visualization","path":"/opentwins/docs/category/unity-visualization","sidebar":"tutorialSidebar"},{"id":"/category/examples","path":"/opentwins/docs/category/examples","sidebar":"tutorialSidebar"},{"id":"/category/raspberry-pi","path":"/opentwins/docs/category/raspberry-pi","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/opentwins/docs/quickstart","label":"quickstart"}}}}],"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"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.2.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.2.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.2.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.2.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.2.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.2.0"}}}'),u={siteConfig:a.default,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},c=r.createContext(u);function d(e){let{children:t}=e;return r.createElement(c.Provider,{value:u},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});var r=n(7294),a=n(412),o=n(5742),i=n(817);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(o.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){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??u)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(405);function o(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7462),a=n(7294),o=n(3727),i=n(8780),l=n(2263),s=n(3919),u=n(412);const c=a.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.Z)(),{withBaseUrl:k}=(0,d.C)(),E=(0,a.useContext)(c),S=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>S.current));const x=p||f;const _=(0,s.Z)(x),C=x?.replace("pathname://","");let T=void 0!==C?(A=C,b&&(e=>e.startsWith("/"))(A)?k(A):A):void 0;var A;T&&_&&(T=(0,i.applyTrailingSlash)(T,{trailingSlash:y,baseUrl:w}));const L=(0,a.useRef)(!1),P=n?o.OL:o.rU,R=u.Z.canUseIntersectionObserver,N=(0,a.useRef)(),O=()=>{L.current||null==T||(window.docusaurus.preload(T),L.current=!0)};(0,a.useEffect)((()=>(!R&&_&&null!=T&&window.docusaurus.prefetch(T),()=>{R&&N.current&&N.current.disconnect()})),[N,T,R,_]);const I=T?.startsWith("#")??!1,D=!T||!_||I;return D||h||E.collectLink(T),D?a.createElement("a",(0,r.Z)({ref:S,href:T},x&&!_&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(P,(0,r.Z)({},v,{onMouseEnter:O,onTouchStart:O,innerRef:e=>{S.current=e,R&&e&&_&&(N.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(N.current.unobserve(e),N.current.disconnect(),null!=T&&window.docusaurus.prefetch(T))}))})),N.current.observe(e))},to:T},n&&{isActive:g,activeClassName:m}))}const f=a.forwardRef(p)},1875:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r=()=>null},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s,I:()=>l});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(7529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(i({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:o}=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,a(l,o))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>o,Z:()=>i});var r=n(2263),a=n(3919);function o(){const{siteConfig:{baseUrl:e,url:t}}=(0,r.Z)();return{withBaseUrl:(n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:o=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,a.b)(n))return n;if(o)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}=o();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[o,i]=n;const l=a?`${a}.${o}`:o;r(i)?e(i,l):t[l]=i}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>o});var r=n(7294);const a=r.createContext(null);function o(e){let{children:t,value:n}=e;const o=r.useContext(a),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,...n?.data};return{plugin:t.plugin,data:r}}({parent:o,value:n})),[o,n]);return r.createElement(a.Provider,{value:i},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>g,gA:()=>p,_r:()=>c,Jo:()=>h,zh:()=>d,yW:()=>m,gB:()=>f});var r=n(6550),a=n(2263),o=n(9935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.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),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const u={},c=()=>i("docusaurus-plugin-content-docs")??u,d=e=>function(e,t,n){void 0===t&&(t=o.m),void 0===n&&(n={});const r=i(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=c(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=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})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&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 o}(t,n,e)}function f(e){return d(e).versions}function m(e){const t=d(e);return l(t)}function g(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:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(6726)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function o(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:a.iconExternalLink},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"}))}},817:(e,t,n)=>{"use strict";n.d(t,{Z:()=>et});var r=n(7294),a=n(6010),o=n(4763),i=n(1944),l=n(7462),s=n(6550),u=n(5999),c=n(5936);const d="docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,c.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,u.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function g(e){const t=e.children??m,{containerRef:n,onClick:a}=f();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:`#${d}`,onClick:a}),t))}var h=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(g,{className:v.skipToContent})}var w=n(6668),k=n(9689);function E(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:o=1.2,className:i,...s}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:o},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const S={closeButton:"closeButton_CVFx"};function x(e){return r.createElement("button",(0,l.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,a.Z)("clean-btn close",S.closeButton,e.className)}),r.createElement(E,{width:14,height:14,strokeWidth:3.1}))}const _={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(_.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const T={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function A(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,k.nT)();if(!t)return null;const{backgroundColor:a,textColor:o,isCloseable:i}=e;return r.createElement("div",{className:T.announcementBar,style:{backgroundColor:a,color:o},role:"banner"},i&&r.createElement("div",{className:T.announcementBarPlaceholder}),r.createElement(C,{className:T.announcementBarContent}),i&&r.createElement(x,{onClick:n,className:T.announcementBarClose}))}var L=n(2961),P=n(2466);var R=n(902),N=n(3102);const O=r.createContext(null);function I(e){let{children:t}=e;const n=function(){const e=(0,L.e)(),t=(0,N.HY)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,R.D9)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(O.Provider,{value:n},t)}function D(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(O);if(!e)throw new R.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,N.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:D(o)})),[a,o,t])}function F(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.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"},o)))}var B=n(529),j=n(1327);function z(){return r.createElement(j.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function U(){const e=(0,L.e)();return r.createElement("button",{type:"button","aria-label":(0,u.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(E,{color:"var(--ifm-color-emphasis-600)"}))}function $(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(z,null),r.createElement(B.Z,{className:"margin-right--md"}),r.createElement(U,null))}var q=n(9960),G=n(4996),H=n(3919);function Z(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var V=n(9471);function W(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:u,prependBaseUrlToHref:c,...d}=e;const p=(0,G.Z)(a),f=(0,G.Z)(t),m=(0,G.Z)(o,{forcePrependBaseUrl:!0}),g=i&&o&&!(0,H.Z)(o),h=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,g&&r.createElement(V.Z,u&&{width:12,height:12}))};return o?r.createElement(q.Z,(0,l.Z)({href:c?m:o},d,h)):r.createElement(q.Z,(0,l.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?Z(n,t.pathname):t.pathname.startsWith(f)},d,h))}function Y(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(W,(0,l.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},o));return n?r.createElement("li",null,i):i}function K(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(W,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function Q(e){let{mobile:t=!1,position:n,...a}=e;const o=t?K:Y;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var X=n(6043),J=n(8596),ee=n(2263);function te(e,t){return e.some((e=>function(e,t){return!!(0,J.Mg)(e.to,t)||!!Z(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ne(e){let{items:t,position:n,className:o,onClick:i,...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,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":c})},r.createElement(W,(0,l.Z)({"aria-haspopup":"true","aria-expanded":c,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",o)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!c))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,n)=>r.createElement(he,(0,l.Z)({isDropdownItem:!0,onKeyDown:e=>{if(n===t.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:n}))))))}function re(e){let{items:t,className:n,position:o,onClick:i,...u}=e;const c=function(){const{siteConfig:{baseUrl:e}}=(0,ee.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=te(t,c),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,X.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[c,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(W,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},u,{onClick:e=>{e.preventDefault(),f()}}),u.children??u.label),r.createElement(X.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(he,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function ae(e){let{mobile:t=!1,...n}=e;const a=t?re:ne;return r.createElement(a,n)}var oe=n(4711);function ie(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),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"}))}const le="iconLanguage_nlXk";var se=n(1875);const ue={searchBox:"searchBox_ZlJk"};function ce(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,ue.searchBox)},t)}var de=n(143),pe=n(3438);var fe=n(373);const me=e=>e.docs.find((t=>t.id===e.mainDocId));const ge={default:Q,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:c,localeConfigs:d}}=(0,ee.Z)(),p=(0,oe.l)(),{search:f,hash:m}=(0,s.TH)(),g=[...n,...c.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...a],h=t?(0,u.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(ae,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(ie,{className:le}),h),items:g}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(ce,{className:n},r.createElement(se.Z,null))},dropdown:ae,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:i=!1}=e;const l=i?"li":"div";return r.createElement(l,{className:(0,a.Z)({navbar__item:!o&&!i,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,de.Iw)(a),s=(0,pe.vY)(t,a);return null===s?null:r.createElement(Q,(0,l.Z)({exact:!0},o,{isActive:()=>i?.path===s.path||!!i?.sidebar&&i.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,de.Iw)(a),s=(0,pe.oz)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(Q,(0,l.Z)({exact:!0},o,{isActive:()=>i?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...o}=e;const i=(0,pe.lO)(a)[0],s=t??i.label,u=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(Q,(0,l.Z)({},o,{label:s,to:u}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...c}=e;const{search:d,hash:p}=(0,s.TH)(),f=(0,de.Iw)(n),m=(0,de.gB)(n),{savePreferredVersionName:g}=(0,fe.J)(n),h=[...o,...m.map((e=>{const t=f.alternateDocVersions[e.name]??me(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>g(e.name)}})),...i],b=(0,pe.lO)(n)[0],v=t&&h.length>1?(0,u.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&h.length>1?void 0:me(b).path;return h.length<=1?r.createElement(Q,(0,l.Z)({},c,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(ae,(0,l.Z)({},c,{mobile:t,label:v,to:y,items:h,isActive:a?()=>!1:void 0}))}};function he(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=ge[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function be(){const e=(0,L.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(he,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function ve(e){return r.createElement("button",(0,l.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 ye(){const e=0===(0,w.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(ve,{onClick:()=>t.hide()}),t.content)}function we(){const e=(0,L.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(F,{header:r.createElement($,null),primaryMenu:r.createElement(be,null),secondaryMenu:r.createElement(ye,null)}):null}const ke={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ee(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Se(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,w.L)(),i=(0,L.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,P.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+u{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,className:(0,a.Z)("navbar","navbar--fixed-top",n&&[ke.navbarHideable,!s&&ke.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Ee,{onClick:i.toggle}),r.createElement(we,null))}const xe="right";function _e(e){let{width:t=30,height:n=30,className:a,...o}=e;return r.createElement("svg",(0,l.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},o),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Ce(){const{toggle:e,shown:t}=(0,L.e)();return r.createElement("button",{onClick:e,"aria-label":(0,u.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(_e,null))}const Te={colorModeToggle:"colorModeToggle_DEke"};function Ae(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(he,(0,l.Z)({},e,{key:t})))))}function Le(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 Pe(){const e=(0,L.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??xe)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement(Le,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Ce,null),r.createElement(z,null),r.createElement(Ae,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Ae,{items:a}),r.createElement(B.Z,{className:Te.colorModeToggle}),!o&&r.createElement(ce,null,r.createElement(se.Z,null)))})}function Re(){return r.createElement(Se,null,r.createElement(Pe,null))}function Ne(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,u=(0,G.Z)(n),c=(0,G.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(q.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?c:a}:{to:u},s),o,a&&!(0,H.Z)(a)&&r.createElement(V.Z,null))}function Oe(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(Ne,{item:t}))}function Ie(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(Oe,{key:t,item:e})))))}function De(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Ie,{key:t,column:e}))))}function Me(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function Fe(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(Ne,{item:t})}function Be(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(Fe,{item:e}),t.length!==n+1&&r.createElement(Me,null))))))}function je(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(De,{columns:t}):r.createElement(Be,{links:t})}var ze=n(941);const Ue={footerLogoLink:"footerLogoLink_BH7S"};function $e(e){let{logo:t}=e;const{withBaseUrl:n}=(0,G.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(ze.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function qe(e){let{logo:t}=e;return t.href?r.createElement(q.Z,{href:t.href,className:Ue.footerLogoLink,target:t.target},r.createElement($e,{logo:t})):r.createElement($e,{logo:t})}function Ge(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function He(e){let{style:t,links:n,logo:o,copyright:i}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(o||i)&&r.createElement("div",{className:"footer__bottom text--center"},o&&r.createElement("div",{className:"margin-bottom--sm"},o),i)))}function Ze(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(He,{style:o,links:n&&n.length>0&&r.createElement(je,{links:n}),logo:a&&r.createElement(qe,{logo:a}),copyright:t&&r.createElement(Ge,{copyright:t})})}const Ve=r.memo(Ze);var We=n(2949),Ye=n(7094);const Ke=(0,R.Qc)([We.S,k.pl,Ye.z,P.OC,fe.L5,i.VC,function(e){let{children:t}=e;return r.createElement(N.n2,null,r.createElement(L.M,null,r.createElement(I,null,t)))}]);function Qe(e){let{children:t}=e;return r.createElement(Ke,null,t)}function Xe(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"))))))}const Je={mainWrapper:"mainWrapper_z2l0"};function et(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:u}=e;return(0,b.t)(),r.createElement(Qe,null,r.createElement(i.d,{title:s,description:u}),r.createElement(y,null),r.createElement(A,null),r.createElement(Re,null),r.createElement("div",{id:d,className:(0,a.Z)(h.k.wrapper.main,Je.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(Xe,e)},t)),!n&&r.createElement(Ve,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),o=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 o={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},l=a.createElement(u.Z,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.Z)(),{navbar:{title:n,logo:u}}=(0,s.L)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,i.Z)(u?.href||"/"),g=n?"":t,h=u?.alt??g;return a.createElement(o.Z,(0,r.Z)({to:m},f,u?.target&&{target:u.target}),u&&a.createElement(c,{logo:u,alt:h,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},529:(e,t,n)=>{"use strict";n.d(t,{Z:()=>g});var r=n(7294),a=n(6668),o=n(2949),i=n(6010),l=n(2389),s=n(5999),u=n(7462);function c(e){return r.createElement("svg",(0,u.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 d(e){return r.createElement("svg",(0,u.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"}))}const p={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function f(e){let{className:t,value:n,onChange:a}=e;const o=(0,l.Z)(),u=(0,s.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,s.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,s.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,i.Z)(p.toggle,t)},r.createElement("button",{className:(0,i.Z)("clean-btn",p.toggleButton,!o&&p.toggleButtonDisabled),type:"button",onClick:()=>a("dark"===n?"light":"dark"),disabled:!o,title:u,"aria-label":u,"aria-live":"polite"},r.createElement(c,{className:(0,i.Z)(p.toggleIcon,p.lightToggleIcon)}),r.createElement(d,{className:(0,i.Z)(p.toggleIcon,p.darkToggleIcon)})))}const m=r.memo(f);function g(e){let{className:t}=e;const n=(0,a.L)().colorMode.disableSwitch,{colorMode:i,setColorMode:l}=(0,o.I)();return n?null:r.createElement(m,{className:t,value:i,onChange:l})}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(5742);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),o&&r.createElement("meta",{name:"docusaurus_tag",content:o}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),o&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var r=n(7462),a=n(7294),o=n(6010),i=n(2389),l=n(2949);const 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,...p}=e,f=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,f.map((e=>a.createElement("img",(0,r.Z)({key:e,src:u[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],c)},p)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>l,z:()=>g});var r=n(7462),a=n(7294),o=n(412);const i="ease-in-out";function l(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),o=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:o}}const s={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function c(e,t){const n=t?s:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const o=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??i}`,height:`${t}px`}}function l(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return c(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function p(e){if(!o.Z.canUseDOM)return e?s:u}function f(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const u=(0,a.useRef)(null);return d({collapsibleRef:u,collapsed:n,animation:o}),a.createElement(t,{ref:u,style:s?void 0:p(n),onTransitionEnd:e=>{"height"===e.propertyName&&(c(u.current,n),i?.(n))},className:l},r)}function m(e){let{collapsed:t,...n}=e;const[o,i]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,a.useLayoutEffect)((()=>{o&&s(t)}),[o,t]),o?a.createElement(f,(0,r.Z)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?m:f;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>f});var r=n(7294),a=n(2389),o=n(12),i=n(902),l=n(6668);const s=(0,o.W)("docusaurus.announcement.dismiss"),u=(0,o.W)("docusaurus.announcement.id"),c=()=>"true"===s.get(),d=e=>s.set(String(e)),p=r.createContext(null);function f(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,a.Z)(),[n,o]=(0,r.useState)((()=>!!t&&c()));(0,r.useEffect)((()=>{o(c())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!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()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(p.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(p);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>h,S:()=>g});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),u="theme",c=(0,i.W)(u),d={light:"light",dark:"dark"},p=e=>e===d.dark?d.dark:d.light,f=e=>a.Z.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),m=e=>{c.set(p(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,o]=(0,r.useState)(f(e));(0,r.useEffect)((()=>{t&&c.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&m(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light: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&&i(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(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||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===d.dark},setLightTheme(){i(d.light)},setDarkTheme(){i(d.dark)}})),[a,i])}();return r.createElement(s.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(s);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>v,L5:()=>h});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(3438),s=n(902),u=n(12);const c=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,u.W)(c(e),{persistence:t}).set(n)},read:(e,t)=>(0,u.W)(c(e),{persistence:t}).get(),clear:(e,t)=>{(0,u.W)(c(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const f=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function h(e){let{children:t}=e;return l.cE?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(f);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.m);const t=(0,a.zh)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,b:()=>l});var r=n(7294),a=n(902);const o=Symbol("EmptyContext"),i=r.createContext(o);function l(e){let{children:t,name:n,items:a}=e;const o=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(i.Provider,{value:o},t)}function s(){const e=(0,r.useContext)(i);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>l,q:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t,version:n}=e;return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(null===e)throw new a.i6("DocsVersionProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>f});var r=n(7294),a=n(3102),o=n(7524),i=n(6550),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,a.HY)(),{items:t}=(0,u.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.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 p(e){let{children:t}=e;const n=d();return r.createElement(c.Provider,{value:n},t)}function f(){const e=r.useContext(c);if(void 0===e)throw new l.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>s,n2:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=i,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},7094:(e,t,n)=>{"use strict";n.d(t,{U:()=>u,z:()=>s});var r=n(7294),a=n(12),o=n(902);const i="docusaurus.tab.",l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,a.W)(`${i}${e}`).set(t)}),[]);(0,r.useEffect)((()=>{try{const e={};(0,a._)().forEach((t=>{if(t.startsWith(i)){const n=t.substring(i.length);e[n]=(0,a.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(l.Provider,{value:n},t)}function u(){const e=(0,r.useContext)(l);if(null==e)throw new o.i6("TabGroupChoiceProvider");return e}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>o});var r=n(7294);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>u});var r=n(7294),a=n(412);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){return a.Z.canUseDOM?window.innerWidth>i?o.desktop:o.mobile:o.ssr}const s=!1;function u(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>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:{}}},3438:(e,t,n)=>{"use strict";n.d(t,{MN:()=>_,Wl:()=>m,_F:()=>v,cE:()=>p,hI:()=>x,jA:()=>g,lO:()=>k,oz:()=>E,s1:()=>w,vY:()=>S,xz:()=>f});var r=n(7294),a=n(6550),o=n(8790),i=n(143),l=n(373),s=n(4477),u=n(1116),c=n(7392),d=n(8596);const p=!!i._r;function f(e){const t=(0,s.E)();if(!e)return;const n=t.docs[e];if(!n)throw new Error(`no version doc found by id=${e}`);return n}function m(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=m(t);if(e)return e}}}function g(){const{pathname:e}=(0,a.TH)(),t=(0,u.V)();if(!t)throw new Error("Unexpected: cant find current sidebar in context");const n=y({sidebarItems:t.items,pathname:e,onlyCategories:!0}).slice(-1)[0];if(!n)throw new Error(`${e} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`);return n}const h=(e,t)=>void 0!==e&&(0,d.Mg)(e,t),b=(e,t)=>e.some((e=>v(e,t)));function v(e,t){return"link"===e.type?h(e.href,t):"category"===e.type&&(h(e.href,t)||b(e.items,t))}function y(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,d.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,d.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function w(){const e=(0,u.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?y({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>(0,c.j)([t,n,a].filter(Boolean))),[t,n,a])}function E(e,t){const n=k(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 S(e,t){const n=k(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- ${(0,c.j)(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function x(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),i=t.routes,l=i.find((e=>(0,a.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,u=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:u}}function _(e){return e.filter((e=>"category"!==e.type||!!m(e)))}},7392:(e,t,n)=>{"use strict";function r(e,t){return void 0===t&&(t=(e,t)=>e===t),e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function a(e){return Array.from(new Set(e))}n.d(t,{j:()=>a,l:()=>r})},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>c,VC:()=>f});var r=n(7294),a=n(6010),o=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:a,image:i,children:l}=e;const c=function(e){const{siteConfig:t}=(0,u.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.C)(),p=i?d(i,{absolute:!0}):void 0;return r.createElement(o.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}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),l)}const d=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const i=r.useContext(d),l=(0,a.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(o.Z,null,r.createElement("html",{className:l})),n)}function f(e){let{children:t}=e;const n=l(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,a.Z)(o,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>u,Ql:()=>s,i6:()=>l,zX:()=>o});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function o(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${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:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>l});var r=n(7294),a=n(723),o=n(2263);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,o.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 a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>f,OC:()=>s,RF:()=>d,o5:()=>p});var r=n(7294),a=n(412),o=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=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=u(),a=(0,r.useRef)(c()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=c();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function p(){const e=u(),t=function(){const e=(0,r.useRef)({elem:null,top:0}),t=(0,r.useCallback)((t=>{e.current={elem:t,top:t.getBoundingClientRect().top}}),[]),n=(0,r.useCallback)((()=>{const{current:{elem:t,top:n}}=e;if(!t)return{restored:!1};const r=t.getBoundingClientRect().top-n;return r&&window.scrollBy({left:0,top:r}),e.current={elem:null,top:0},{restored:0!==r}}),[]);return(0,r.useMemo)((()=>({save:t,restore:n})),[n,t])}(),n=(0,r.useRef)(void 0),a=(0,r.useCallback)((r=>{t.save(r),e.disableScrollEvents(),n.current=()=>{const{restored:r}=t.restore();if(n.current=void 0,r){const t=()=>{e.enableScrollEvents(),window.removeEventListener("scroll",t)};window.addEventListener("scroll",t)}else e.enableScrollEvents()}}),[e,t]);return(0,r.useLayoutEffect)((()=>{n.current?.()})),{blockElementScrollPositionUntilNextRender:a}}function f(){const e=(0,r.useRef)(null),t=(0,o.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 a=document.documentElement.scrollTop;(n&&a>e||!n&&at&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>a});n(2263);const r="default";function a(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{W:()=>l,_:()=>s});const r="localStorage";function a(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,o||(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),o=!0),null}var t}let o=!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=a(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=a(e);if(!t)return[];const n=[];for(let r=0;r{"use strict";n.d(t,{l:()=>o});var r=n(2263),a=n(6550);function o(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:o}}=(0,r.Z)(),{pathname:i}=(0,a.TH)(),l=o===n?e:e.replace(`/${o}/`,"/"),s=i.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${l}`:`${l}${e}/`}(r)}${s}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(7294),a=n(6550),o=n(902);function i(e){const t=(0,a.TH)(),n=(0,o.D9)(t),i=(0,o.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(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[a]=e.split(/[#?]/),o="/"===a||a===r?a:(i=a,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(a,o)}},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 a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}})},6010:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;ta});const a=function(){for(var e,t,n=0,a="";n{"use strict";n.d(t,{lX:()=>w,q_:()=>C,ob:()=>f,PP:()=>A,Ep:()=>p});var r=n(7462);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r=0;p--){var f=i[p];"."===f?o(i,p):".."===f?(o(i,p),d++):d&&(o(i,p),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(8776);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 p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!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,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,g(),w.location);c.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var u=Object.defineProperty,c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=f(n);a&&a!==m&&e(t,a,r)}var i=c(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,(function(){return u[c++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function a(e,t,n){return en?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}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=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),u=o.querySelector(r.barSelector),c=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{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)*a(Math.random()*t,.1,.95)),t=a(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 a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),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&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var 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,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function u(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=p(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;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(a){return!1}}()?Object.assign:function(e,a){for(var o,i,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s{"use strict";n.d(t,{Z:()=>o});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);S+=E.value.length,E=E.next){var x=E.value;if(t.length>e.length)return;if(!(x instanceof a)){var _,C=1;if(v){if(!(_=o(k,S,e,b))||_.index>=e.length)break;var T=_.index,A=_.index+_[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 a)continue;for(var P=E;P!==t.tail&&(Ld.reach&&(d.reach=I);var D=E.prev;if(N&&(D=s(t,D,N),S+=N.length),u(t,D,C),E=s(t,D,new a(p,h?r.tokenize(R,h):R,y,R)),O&&s(t,E,O),C>1){var M={cause:p+","+m,reach:I};i(e,t,n,E.prev,S,M),d&&M.reach>d.reach&&(d.reach=M.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,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function u(e,t,n){for(var r=t.next,a=0;a"+o.content+""},r}(),a=r;r.default=r,a.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]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.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:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.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 a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.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|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.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},a.languages.c.string],char:a.languages.c.char,comment:a.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:a.languages.c}}}}),a.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 a.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"])}(a),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"))}(a),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},a={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:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.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}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.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:a.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:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.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:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.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:a.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"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.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")),a.languages.js=a.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}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\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})),o=/"(?:[^"\\\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"(?:"+a+"|"+o+")"}))),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(o),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}(a),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,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \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("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),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}(a),a.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:a.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+/},a.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=p(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s=0&&f(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,a=r.inside["interpolation-punctuation"],o=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 a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function u(t){var n={};n["interpolation-punctuation"]=a;var o=e.tokenize(t,n);if(3===o.length){var i=[1,1];i.push.apply(i,s(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,i)}return new e.Token("interpolation",o,r.alias,t)}function c(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,c={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(i++,r)););return c[n]=a,n})).join(""),n,r),p=Object.keys(c);return i=0,function e(t){for(var n=0;n=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=p[i],o="string"==typeof r?r:r.content,l=o.indexOf(a);if(-1!==l){++i;var s=o.substring(0,l),d=u(c[a]),f=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),f){var g=[f];e(g),m.push.apply(m,g)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}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 p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=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}(a),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 o(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return a})),RegExp(e,t)}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\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:o(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=/.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(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:i(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=i(a);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)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),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],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,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})}(a),a.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},a.languages.go=a.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/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.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,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=o.length);s++){var u=l[s];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=o[a],d=n.tokenStack[c],p="string"==typeof u?u:u.content,f=t(r,c),m=p.indexOf(f);if(m>-1){++a;var g=p.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(m+f.length),v=[];g&&v.push.apply(v,i([g])),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)}}}})}(a),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}(a),a.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"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.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:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.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:/[:;(){}]/},a.languages.objectivec=a.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 a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.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/},a.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:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.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/}),a.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 a.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}})}(a),a.languages.scss=a.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]+\}/}}}),a.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}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.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}}),a.languages.scss.atrule.inside.rest=a.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:/[{}()\[\];:.]/}}(a),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}(a),a.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:/[()]/};const o=a},9901:e=>{e.exports&&(e.exports={core:{meta:{path:"components/prism-core.js",option:"mandatory"},core:"Core"},themes:{meta:{path:"themes/{id}.css",link:"index.html?theme={id}",exclusive:!0},prism:{title:"Default",option:"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{title:"Okaidia",owner:"ocodia"},"prism-twilight":{title:"Twilight",owner:"remybach"},"prism-coy":{title:"Coy",owner:"tshedor"},"prism-solarizedlight":{title:"Solarized Light",owner:"hectormatos2011 "},"prism-tomorrow":{title:"Tomorrow Night",owner:"Rosey"}},languages:{meta:{path:"components/prism-{id}",noCSS:!0,examplesPath:"examples/prism-{id}",addCheckAll:!0},markup:{title:"Markup",alias:["html","xml","svg","mathml","ssml","atom","rss"],aliasTitles:{html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",ssml:"SSML",atom:"Atom",rss:"RSS"},option:"default"},css:{title:"CSS",option:"default",modify:"markup"},clike:{title:"C-like",option:"default"},javascript:{title:"JavaScript",require:"clike",modify:"markup",optional:"regex",alias:"js",option:"default"},abap:{title:"ABAP",owner:"dellagustin"},abnf:{title:"ABNF",owner:"RunDevelopment"},actionscript:{title:"ActionScript",require:"javascript",modify:"markup",owner:"Golmote"},ada:{title:"Ada",owner:"Lucretia"},agda:{title:"Agda",owner:"xy-ren"},al:{title:"AL",owner:"RunDevelopment"},antlr4:{title:"ANTLR4",alias:"g4",owner:"RunDevelopment"},apacheconf:{title:"Apache Configuration",owner:"GuiTeK"},apex:{title:"Apex",require:["clike","sql"],owner:"RunDevelopment"},apl:{title:"APL",owner:"ngn"},applescript:{title:"AppleScript",owner:"Golmote"},aql:{title:"AQL",owner:"RunDevelopment"},arduino:{title:"Arduino",require:"cpp",alias:"ino",owner:"dkern"},arff:{title:"ARFF",owner:"Golmote"},armasm:{title:"ARM Assembly",alias:"arm-asm",owner:"RunDevelopment"},arturo:{title:"Arturo",alias:"art",optional:["bash","css","javascript","markup","markdown","sql"],owner:"drkameleon"},asciidoc:{alias:"adoc",title:"AsciiDoc",owner:"Golmote"},aspnet:{title:"ASP.NET (C#)",require:["markup","csharp"],owner:"nauzilus"},asm6502:{title:"6502 Assembly",owner:"kzurawel"},asmatmel:{title:"Atmel AVR Assembly",owner:"cerkit"},autohotkey:{title:"AutoHotkey",owner:"aviaryan"},autoit:{title:"AutoIt",owner:"Golmote"},avisynth:{title:"AviSynth",alias:"avs",owner:"Zinfidel"},"avro-idl":{title:"Avro IDL",alias:"avdl",owner:"RunDevelopment"},awk:{title:"AWK",alias:"gawk",aliasTitles:{gawk:"GAWK"},owner:"RunDevelopment"},bash:{title:"Bash",alias:["sh","shell"],aliasTitles:{sh:"Shell",shell:"Shell"},owner:"zeitgeist87"},basic:{title:"BASIC",owner:"Golmote"},batch:{title:"Batch",owner:"Golmote"},bbcode:{title:"BBcode",alias:"shortcode",aliasTitles:{shortcode:"Shortcode"},owner:"RunDevelopment"},bbj:{title:"BBj",owner:"hyyan"},bicep:{title:"Bicep",owner:"johnnyreilly"},birb:{title:"Birb",require:"clike",owner:"Calamity210"},bison:{title:"Bison",require:"c",owner:"Golmote"},bnf:{title:"BNF",alias:"rbnf",aliasTitles:{rbnf:"RBNF"},owner:"RunDevelopment"},bqn:{title:"BQN",owner:"yewscion"},brainfuck:{title:"Brainfuck",owner:"Golmote"},brightscript:{title:"BrightScript",owner:"RunDevelopment"},bro:{title:"Bro",owner:"wayward710"},bsl:{title:"BSL (1C:Enterprise)",alias:"oscript",aliasTitles:{oscript:"OneScript"},owner:"Diversus23"},c:{title:"C",require:"clike",owner:"zeitgeist87"},csharp:{title:"C#",require:"clike",alias:["cs","dotnet"],owner:"mvalipour"},cpp:{title:"C++",require:"c",owner:"zeitgeist87"},cfscript:{title:"CFScript",require:"clike",alias:"cfc",owner:"mjclemente"},chaiscript:{title:"ChaiScript",require:["clike","cpp"],owner:"RunDevelopment"},cil:{title:"CIL",owner:"sbrl"},cilkc:{title:"Cilk/C",require:"c",alias:"cilk-c",owner:"OpenCilk"},cilkcpp:{title:"Cilk/C++",require:"cpp",alias:["cilk-cpp","cilk"],owner:"OpenCilk"},clojure:{title:"Clojure",owner:"troglotit"},cmake:{title:"CMake",owner:"mjrogozinski"},cobol:{title:"COBOL",owner:"RunDevelopment"},coffeescript:{title:"CoffeeScript",require:"javascript",alias:"coffee",owner:"R-osey"},concurnas:{title:"Concurnas",alias:"conc",owner:"jasontatton"},csp:{title:"Content-Security-Policy",owner:"ScottHelme"},cooklang:{title:"Cooklang",owner:"ahue"},coq:{title:"Coq",owner:"RunDevelopment"},crystal:{title:"Crystal",require:"ruby",owner:"MakeNowJust"},"css-extras":{title:"CSS Extras",require:"css",modify:"css",owner:"milesj"},csv:{title:"CSV",owner:"RunDevelopment"},cue:{title:"CUE",owner:"RunDevelopment"},cypher:{title:"Cypher",owner:"RunDevelopment"},d:{title:"D",require:"clike",owner:"Golmote"},dart:{title:"Dart",require:"clike",owner:"Golmote"},dataweave:{title:"DataWeave",owner:"machaval"},dax:{title:"DAX",owner:"peterbud"},dhall:{title:"Dhall",owner:"RunDevelopment"},diff:{title:"Diff",owner:"uranusjr"},django:{title:"Django/Jinja2",require:"markup-templating",alias:"jinja2",owner:"romanvm"},"dns-zone-file":{title:"DNS zone file",owner:"RunDevelopment",alias:"dns-zone"},docker:{title:"Docker",alias:"dockerfile",owner:"JustinBeckwith"},dot:{title:"DOT (Graphviz)",alias:"gv",optional:"markup",owner:"RunDevelopment"},ebnf:{title:"EBNF",owner:"RunDevelopment"},editorconfig:{title:"EditorConfig",owner:"osipxd"},eiffel:{title:"Eiffel",owner:"Conaclos"},ejs:{title:"EJS",require:["javascript","markup-templating"],owner:"RunDevelopment",alias:"eta",aliasTitles:{eta:"Eta"}},elixir:{title:"Elixir",owner:"Golmote"},elm:{title:"Elm",owner:"zwilias"},etlua:{title:"Embedded Lua templating",require:["lua","markup-templating"],owner:"RunDevelopment"},erb:{title:"ERB",require:["ruby","markup-templating"],owner:"Golmote"},erlang:{title:"Erlang",owner:"Golmote"},"excel-formula":{title:"Excel Formula",alias:["xlsx","xls"],owner:"RunDevelopment"},fsharp:{title:"F#",require:"clike",owner:"simonreynolds7"},factor:{title:"Factor",owner:"catb0t"},false:{title:"False",owner:"edukisto"},"firestore-security-rules":{title:"Firestore security rules",require:"clike",owner:"RunDevelopment"},flow:{title:"Flow",require:"javascript",owner:"Golmote"},fortran:{title:"Fortran",owner:"Golmote"},ftl:{title:"FreeMarker Template Language",require:"markup-templating",owner:"RunDevelopment"},gml:{title:"GameMaker Language",alias:"gamemakerlanguage",require:"clike",owner:"LiarOnce"},gap:{title:"GAP (CAS)",owner:"RunDevelopment"},gcode:{title:"G-code",owner:"RunDevelopment"},gdscript:{title:"GDScript",owner:"RunDevelopment"},gedcom:{title:"GEDCOM",owner:"Golmote"},gettext:{title:"gettext",alias:"po",owner:"RunDevelopment"},gherkin:{title:"Gherkin",owner:"hason"},git:{title:"Git",owner:"lgiraudel"},glsl:{title:"GLSL",require:"c",owner:"Golmote"},gn:{title:"GN",alias:"gni",owner:"RunDevelopment"},"linker-script":{title:"GNU Linker Script",alias:"ld",owner:"RunDevelopment"},go:{title:"Go",require:"clike",owner:"arnehormann"},"go-module":{title:"Go module",alias:"go-mod",owner:"RunDevelopment"},gradle:{title:"Gradle",require:"clike",owner:"zeabdelkhalek-badido18"},graphql:{title:"GraphQL",optional:"markdown",owner:"Golmote"},groovy:{title:"Groovy",require:"clike",owner:"robfletcher"},haml:{title:"Haml",require:"ruby",optional:["css","css-extras","coffeescript","erb","javascript","less","markdown","scss","textile"],owner:"Golmote"},handlebars:{title:"Handlebars",require:"markup-templating",alias:["hbs","mustache"],aliasTitles:{mustache:"Mustache"},owner:"Golmote"},haskell:{title:"Haskell",alias:"hs",owner:"bholst"},haxe:{title:"Haxe",require:"clike",optional:"regex",owner:"Golmote"},hcl:{title:"HCL",owner:"outsideris"},hlsl:{title:"HLSL",require:"c",owner:"RunDevelopment"},hoon:{title:"Hoon",owner:"matildepark"},http:{title:"HTTP",optional:["csp","css","hpkp","hsts","javascript","json","markup","uri"],owner:"danielgtaylor"},hpkp:{title:"HTTP Public-Key-Pins",owner:"ScottHelme"},hsts:{title:"HTTP Strict-Transport-Security",owner:"ScottHelme"},ichigojam:{title:"IchigoJam",owner:"BlueCocoa"},icon:{title:"Icon",owner:"Golmote"},"icu-message-format":{title:"ICU Message Format",owner:"RunDevelopment"},idris:{title:"Idris",alias:"idr",owner:"KeenS",require:"haskell"},ignore:{title:".ignore",owner:"osipxd",alias:["gitignore","hgignore","npmignore"],aliasTitles:{gitignore:".gitignore",hgignore:".hgignore",npmignore:".npmignore"}},inform7:{title:"Inform 7",owner:"Golmote"},ini:{title:"Ini",owner:"aviaryan"},io:{title:"Io",owner:"AlesTsurko"},j:{title:"J",owner:"Golmote"},java:{title:"Java",require:"clike",owner:"sherblot"},javadoc:{title:"JavaDoc",require:["markup","java","javadoclike"],modify:"java",optional:"scala",owner:"RunDevelopment"},javadoclike:{title:"JavaDoc-like",modify:["java","javascript","php"],owner:"RunDevelopment"},javastacktrace:{title:"Java stack trace",owner:"RunDevelopment"},jexl:{title:"Jexl",owner:"czosel"},jolie:{title:"Jolie",require:"clike",owner:"thesave"},jq:{title:"JQ",owner:"RunDevelopment"},jsdoc:{title:"JSDoc",require:["javascript","javadoclike","typescript"],modify:"javascript",optional:["actionscript","coffeescript"],owner:"RunDevelopment"},"js-extras":{title:"JS Extras",require:"javascript",modify:"javascript",optional:["actionscript","coffeescript","flow","n4js","typescript"],owner:"RunDevelopment"},json:{title:"JSON",alias:"webmanifest",aliasTitles:{webmanifest:"Web App Manifest"},owner:"CupOfTea696"},json5:{title:"JSON5",require:"json",owner:"RunDevelopment"},jsonp:{title:"JSONP",require:"json",owner:"RunDevelopment"},jsstacktrace:{title:"JS stack trace",owner:"sbrl"},"js-templates":{title:"JS Templates",require:"javascript",modify:"javascript",optional:["css","css-extras","graphql","markdown","markup","sql"],owner:"RunDevelopment"},julia:{title:"Julia",owner:"cdagnino"},keepalived:{title:"Keepalived Configure",owner:"dev-itsheng"},keyman:{title:"Keyman",owner:"mcdurdin"},kotlin:{title:"Kotlin",alias:["kt","kts"],aliasTitles:{kts:"Kotlin Script"},require:"clike",owner:"Golmote"},kumir:{title:"KuMir (\u041a\u0443\u041c\u0438\u0440)",alias:"kum",owner:"edukisto"},kusto:{title:"Kusto",owner:"RunDevelopment"},latex:{title:"LaTeX",alias:["tex","context"],aliasTitles:{tex:"TeX",context:"ConTeXt"},owner:"japborst"},latte:{title:"Latte",require:["clike","markup-templating","php"],owner:"nette"},less:{title:"Less",require:"css",optional:"css-extras",owner:"Golmote"},lilypond:{title:"LilyPond",require:"scheme",alias:"ly",owner:"RunDevelopment"},liquid:{title:"Liquid",require:"markup-templating",owner:"cinhtau"},lisp:{title:"Lisp",alias:["emacs","elisp","emacs-lisp"],owner:"JuanCaicedo"},livescript:{title:"LiveScript",owner:"Golmote"},llvm:{title:"LLVM IR",owner:"porglezomp"},log:{title:"Log file",optional:"javastacktrace",owner:"RunDevelopment"},lolcode:{title:"LOLCODE",owner:"Golmote"},lua:{title:"Lua",owner:"Golmote"},magma:{title:"Magma (CAS)",owner:"RunDevelopment"},makefile:{title:"Makefile",owner:"Golmote"},markdown:{title:"Markdown",require:"markup",optional:"yaml",alias:"md",owner:"Golmote"},"markup-templating":{title:"Markup templating",require:"markup",owner:"Golmote"},mata:{title:"Mata",owner:"RunDevelopment"},matlab:{title:"MATLAB",owner:"Golmote"},maxscript:{title:"MAXScript",owner:"RunDevelopment"},mel:{title:"MEL",owner:"Golmote"},mermaid:{title:"Mermaid",owner:"RunDevelopment"},metafont:{title:"METAFONT",owner:"LaeriExNihilo"},mizar:{title:"Mizar",owner:"Golmote"},mongodb:{title:"MongoDB",owner:"airs0urce",require:"javascript"},monkey:{title:"Monkey",owner:"Golmote"},moonscript:{title:"MoonScript",alias:"moon",owner:"RunDevelopment"},n1ql:{title:"N1QL",owner:"TMWilds"},n4js:{title:"N4JS",require:"javascript",optional:"jsdoc",alias:"n4jsd",owner:"bsmith-n4"},"nand2tetris-hdl":{title:"Nand To Tetris HDL",owner:"stephanmax"},naniscript:{title:"Naninovel Script",owner:"Elringus",alias:"nani"},nasm:{title:"NASM",owner:"rbmj"},neon:{title:"NEON",owner:"nette"},nevod:{title:"Nevod",owner:"nezaboodka"},nginx:{title:"nginx",owner:"volado"},nim:{title:"Nim",owner:"Golmote"},nix:{title:"Nix",owner:"Golmote"},nsis:{title:"NSIS",owner:"idleberg"},objectivec:{title:"Objective-C",require:"c",alias:"objc",owner:"uranusjr"},ocaml:{title:"OCaml",owner:"Golmote"},odin:{title:"Odin",owner:"edukisto"},opencl:{title:"OpenCL",require:"c",modify:["c","cpp"],owner:"Milania1"},openqasm:{title:"OpenQasm",alias:"qasm",owner:"RunDevelopment"},oz:{title:"Oz",owner:"Golmote"},parigp:{title:"PARI/GP",owner:"Golmote"},parser:{title:"Parser",require:"markup",owner:"Golmote"},pascal:{title:"Pascal",alias:"objectpascal",aliasTitles:{objectpascal:"Object Pascal"},owner:"Golmote"},pascaligo:{title:"Pascaligo",owner:"DefinitelyNotAGoat"},psl:{title:"PATROL Scripting Language",owner:"bertysentry"},pcaxis:{title:"PC-Axis",alias:"px",owner:"RunDevelopment"},peoplecode:{title:"PeopleCode",alias:"pcode",owner:"RunDevelopment"},perl:{title:"Perl",owner:"Golmote"},php:{title:"PHP",require:"markup-templating",owner:"milesj"},phpdoc:{title:"PHPDoc",require:["php","javadoclike"],modify:"php",owner:"RunDevelopment"},"php-extras":{title:"PHP Extras",require:"php",modify:"php",owner:"milesj"},"plant-uml":{title:"PlantUML",alias:"plantuml",owner:"RunDevelopment"},plsql:{title:"PL/SQL",require:"sql",owner:"Golmote"},powerquery:{title:"PowerQuery",alias:["pq","mscript"],owner:"peterbud"},powershell:{title:"PowerShell",owner:"nauzilus"},processing:{title:"Processing",require:"clike",owner:"Golmote"},prolog:{title:"Prolog",owner:"Golmote"},promql:{title:"PromQL",owner:"arendjr"},properties:{title:".properties",owner:"Golmote"},protobuf:{title:"Protocol Buffers",require:"clike",owner:"just-boris"},pug:{title:"Pug",require:["markup","javascript"],optional:["coffeescript","ejs","handlebars","less","livescript","markdown","scss","stylus","twig"],owner:"Golmote"},puppet:{title:"Puppet",owner:"Golmote"},pure:{title:"Pure",optional:["c","cpp","fortran"],owner:"Golmote"},purebasic:{title:"PureBasic",require:"clike",alias:"pbfasm",owner:"HeX0R101"},purescript:{title:"PureScript",require:"haskell",alias:"purs",owner:"sriharshachilakapati"},python:{title:"Python",alias:"py",owner:"multipetros"},qsharp:{title:"Q#",require:"clike",alias:"qs",owner:"fedonman"},q:{title:"Q (kdb+ database)",owner:"Golmote"},qml:{title:"QML",require:"javascript",owner:"RunDevelopment"},qore:{title:"Qore",require:"clike",owner:"temnroegg"},r:{title:"R",owner:"Golmote"},racket:{title:"Racket",require:"scheme",alias:"rkt",owner:"RunDevelopment"},cshtml:{title:"Razor C#",alias:"razor",require:["markup","csharp"],optional:["css","css-extras","javascript","js-extras"],owner:"RunDevelopment"},jsx:{title:"React JSX",require:["markup","javascript"],optional:["jsdoc","js-extras","js-templates"],owner:"vkbansal"},tsx:{title:"React TSX",require:["jsx","typescript"]},reason:{title:"Reason",require:"clike",owner:"Golmote"},regex:{title:"Regex",owner:"RunDevelopment"},rego:{title:"Rego",owner:"JordanSh"},renpy:{title:"Ren'py",alias:"rpy",owner:"HyuchiaDiego"},rescript:{title:"ReScript",alias:"res",owner:"vmarcosp"},rest:{title:"reST (reStructuredText)",owner:"Golmote"},rip:{title:"Rip",owner:"ravinggenius"},roboconf:{title:"Roboconf",owner:"Golmote"},robotframework:{title:"Robot Framework",alias:"robot",owner:"RunDevelopment"},ruby:{title:"Ruby",require:"clike",alias:"rb",owner:"samflores"},rust:{title:"Rust",owner:"Golmote"},sas:{title:"SAS",optional:["groovy","lua","sql"],owner:"Golmote"},sass:{title:"Sass (Sass)",require:"css",optional:"css-extras",owner:"Golmote"},scss:{title:"Sass (SCSS)",require:"css",optional:"css-extras",owner:"MoOx"},scala:{title:"Scala",require:"java",owner:"jozic"},scheme:{title:"Scheme",owner:"bacchus123"},"shell-session":{title:"Shell session",require:"bash",alias:["sh-session","shellsession"],owner:"RunDevelopment"},smali:{title:"Smali",owner:"RunDevelopment"},smalltalk:{title:"Smalltalk",owner:"Golmote"},smarty:{title:"Smarty",require:"markup-templating",optional:"php",owner:"Golmote"},sml:{title:"SML",alias:"smlnj",aliasTitles:{smlnj:"SML/NJ"},owner:"RunDevelopment"},solidity:{title:"Solidity (Ethereum)",alias:"sol",require:"clike",owner:"glachaud"},"solution-file":{title:"Solution file",alias:"sln",owner:"RunDevelopment"},soy:{title:"Soy (Closure Template)",require:"markup-templating",owner:"Golmote"},sparql:{title:"SPARQL",require:"turtle",owner:"Triply-Dev",alias:"rq"},"splunk-spl":{title:"Splunk SPL",owner:"RunDevelopment"},sqf:{title:"SQF: Status Quo Function (Arma 3)",require:"clike",owner:"RunDevelopment"},sql:{title:"SQL",owner:"multipetros"},squirrel:{title:"Squirrel",require:"clike",owner:"RunDevelopment"},stan:{title:"Stan",owner:"RunDevelopment"},stata:{title:"Stata Ado",require:["mata","java","python"],owner:"RunDevelopment"},iecst:{title:"Structured Text (IEC 61131-3)",owner:"serhioromano"},stylus:{title:"Stylus",owner:"vkbansal"},supercollider:{title:"SuperCollider",alias:"sclang",owner:"RunDevelopment"},swift:{title:"Swift",owner:"chrischares"},systemd:{title:"Systemd configuration file",owner:"RunDevelopment"},"t4-templating":{title:"T4 templating",owner:"RunDevelopment"},"t4-cs":{title:"T4 Text Templates (C#)",require:["t4-templating","csharp"],alias:"t4",owner:"RunDevelopment"},"t4-vb":{title:"T4 Text Templates (VB)",require:["t4-templating","vbnet"],owner:"RunDevelopment"},tap:{title:"TAP",owner:"isaacs",require:"yaml"},tcl:{title:"Tcl",owner:"PeterChaplin"},tt2:{title:"Template Toolkit 2",require:["clike","markup-templating"],owner:"gflohr"},textile:{title:"Textile",require:"markup",optional:"css",owner:"Golmote"},toml:{title:"TOML",owner:"RunDevelopment"},tremor:{title:"Tremor",alias:["trickle","troy"],owner:"darach",aliasTitles:{trickle:"trickle",troy:"troy"}},turtle:{title:"Turtle",alias:"trig",aliasTitles:{trig:"TriG"},owner:"jakubklimek"},twig:{title:"Twig",require:"markup-templating",owner:"brandonkelly"},typescript:{title:"TypeScript",require:"javascript",optional:"js-templates",alias:"ts",owner:"vkbansal"},typoscript:{title:"TypoScript",alias:"tsconfig",aliasTitles:{tsconfig:"TSConfig"},owner:"dkern"},unrealscript:{title:"UnrealScript",alias:["uscript","uc"],owner:"RunDevelopment"},uorazor:{title:"UO Razor Script",owner:"jaseowns"},uri:{title:"URI",alias:"url",aliasTitles:{url:"URL"},owner:"RunDevelopment"},v:{title:"V",require:"clike",owner:"taggon"},vala:{title:"Vala",require:"clike",optional:"regex",owner:"TemplarVolk"},vbnet:{title:"VB.Net",require:"basic",owner:"Bigsby"},velocity:{title:"Velocity",require:"markup",owner:"Golmote"},verilog:{title:"Verilog",owner:"a-rey"},vhdl:{title:"VHDL",owner:"a-rey"},vim:{title:"vim",owner:"westonganger"},"visual-basic":{title:"Visual Basic",alias:["vb","vba"],aliasTitles:{vba:"VBA"},owner:"Golmote"},warpscript:{title:"WarpScript",owner:"RunDevelopment"},wasm:{title:"WebAssembly",owner:"Golmote"},"web-idl":{title:"Web IDL",alias:"webidl",owner:"RunDevelopment"},wgsl:{title:"WGSL",owner:"Dr4gonthree"},wiki:{title:"Wiki markup",require:"markup",owner:"Golmote"},wolfram:{title:"Wolfram language",alias:["mathematica","nb","wl"],aliasTitles:{mathematica:"Mathematica",nb:"Mathematica Notebook"},owner:"msollami"},wren:{title:"Wren",owner:"clsource"},xeora:{title:"Xeora",require:"markup",alias:"xeoracube",aliasTitles:{xeoracube:"XeoraCube"},owner:"freakmaxi"},"xml-doc":{title:"XML doc (.net)",require:"markup",modify:["csharp","fsharp","vbnet"],owner:"RunDevelopment"},xojo:{title:"Xojo (REALbasic)",owner:"Golmote"},xquery:{title:"XQuery",require:"markup",owner:"Golmote"},yaml:{title:"YAML",alias:"yml",owner:"hason"},yang:{title:"YANG",owner:"RunDevelopment"},zig:{title:"Zig",owner:"RunDevelopment"}},plugins:{meta:{path:"plugins/{id}/prism-{id}",link:"plugins/{id}/"},"line-highlight":{title:"Line Highlight",description:"Highlights specific lines and/or line ranges."},"line-numbers":{title:"Line Numbers",description:"Line number at the beginning of code lines.",owner:"kuba-kubula"},"show-invisibles":{title:"Show Invisibles",description:"Show hidden characters such as tabs and line breaks.",optional:["autolinker","data-uri-highlight"]},autolinker:{title:"Autolinker",description:"Converts URLs and emails in code to clickable links. Parses Markdown links in comments."},wpd:{title:"WebPlatform Docs",description:'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll and highlightAllUnder methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},2885:(e,t,n)=>{const r=n(9901),a=n(9642),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(6500).resolve(t)],delete Prism.languages[e],n(6500)(t),o.add(e)}))}i.silent=!1,e.exports=i},6726:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6726},6500:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6500},9642:e=>{"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,r=e.length;n "));var l={},s=e[r];if(s){function u(t){if(!(t in e))throw new Error(r+" depends on an unknown component "+t);if(!(t in l))for(var i in a(t,o),l[t]=!0,n[t])l[i]=!0}t(s.require,u),t(s.optional,u),t(s.modify,u)}n[r]=l,o.pop()}}return function(e){var t=n[e];return t||(a(e,r),t=n[e]),t}}function a(e){for(var t in e)return!0;return!1}return function(o,i,l){var s=function(e){var t={};for(var n in e){var r=e[n];for(var a in r)if("meta"!=a){var o=r[a];t[a]="string"==typeof o?{title:o}:o}}return t}(o),u=function(e){var n;return function(r){if(r in e)return r;if(!n)for(var a in n={},e){var o=e[a];t(o&&o.alias,(function(t){if(t in n)throw new Error(t+" cannot be alias for both "+a+" and "+n[t]);if(t in e)throw new Error(t+" cannot be alias of "+a+" because it is a component.");n[t]=a}))}return n[r]||r}}(s);i=i.map(u),l=(l||[]).map(u);var c=n(i),d=n(l);i.forEach((function e(n){var r=s[n];t(r&&r.require,(function(t){t in d||(c[t]=!0,e(t))}))}));for(var p,f=r(s),m=c;a(m);){for(var g in p={},m){var h=s[g];t(h&&h.modify,(function(e){e in d&&(p[e]=!0)}))}for(var b in d)if(!(b in c))for(var v in f(b))if(v in c){p[b]=!0;break}for(var y in m=p)c[y]=!0}var w={getIds:function(){var e=[];return w.load((function(t){e.push(t)})),e},load:function(t,n){return function(t,n,r,a){var o=a?a.series:void 0,i=a?a.parallel:e,l={},s={};function u(e){if(e in l)return l[e];s[e]=!0;var a,c=[];for(var d in t(e))d in n&&c.push(d);if(0===c.length)a=r(e);else{var p=i(c.map((function(e){var t=u(e);return delete s[e],t})));o?a=o(p,(function(){return r(e)})):r(e)}return l[e]=a}for(var c in n)u(c);var d=[];for(var p in s)d.push(l[p]);return i(d)}(f,c,t,n)}};return w}}();e.exports=t},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,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,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),o=n(4142);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n